Subversion Repositories RepoView

Rev

Rev 16 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10 nishi 1
/* $Id: repo.c 20 2024-08-21 16:13:13Z nishi $ */
2
 
3
#include "rv_repo.h"
11 nishi 4
 
5
#include "../config.h"
6
 
7
#include "rv_util.h"
8
 
9
#include <stdbool.h>
10
#include <unistd.h>
11
#include <stdlib.h>
12
#include <dirent.h>
13
#include <stdio.h>
14
#include <string.h>
15
#include <fcntl.h>
16
#include <sys/stat.h>
17
#include <sys/wait.h>
12 nishi 18
#include <signal.h>
11 nishi 19
 
20
char* rv_construct_repouser(const char* reponame, const char* username) {
21
	char cbuf[2];
22
	cbuf[0] = REPO_USER_DELIM;
23
	cbuf[1] = 0;
24
	return rv_strcat3(reponame, cbuf, username);
25
}
26
 
27
bool rv_repo_exists(const char* repouser) {
28
	char* path = rv_strcat3(SVN_ROOT, "/", repouser);
29
	if(access(path, F_OK) == 0) {
30
		free(path);
31
		return true;
32
	}
33
	return false;
34
}
35
 
36
void rv_repo_list(const char* username, void (*handler)(const char* name, const char* rev)) {
37
	struct dirent** nl;
38
	int n = scandir(SVN_ROOT, &nl, NULL, alphasort);
39
	if(n < 0) return;
40
	int i;
41
	for(i = 0; i < n; i++) {
42
		if(strcmp(nl[i]->d_name, "..") != 0 && strcmp(nl[i]->d_name, ".") != 0) {
43
			char* tmp = rv_strcat3(SVN_ROOT, "/", nl[i]->d_name);
44
			char* path = rv_strcat(tmp, "/db/current");
45
			free(tmp);
46
			char* str = rv_strdup(nl[i]->d_name);
47
			int j;
48
			for(j = 0; str[j] != 0; j++) {
49
				if(str[j] == REPO_USER_DELIM) {
50
					str[j] = 0;
51
					if(strcmp(str + j + 1, username) == 0) {
52
						struct stat s;
53
						char* rev = rv_strdup("???");
54
						if(stat(path, &s) == 0) {
55
							free(rev);
56
							rev = malloc(s.st_size + 1);
57
							FILE* f = fopen(path, "r");
58
							fread(rev, 1, s.st_size, f);
59
							fclose(f);
60
							rev[s.st_size] = 0;
61
						}
62
						handler(str, rev);
63
						free(rev);
64
					}
65
					break;
66
				}
67
			}
68
			free(path);
69
			free(str);
70
		}
71
		free(nl[i]);
72
	}
73
	free(nl);
74
}
75
 
76
void null_exec(char** cmd) {
77
	pid_t pid = fork();
78
	if(pid == 0) {
79
		int null = open("/dev/null", O_RDWR);
80
		dup2(STDOUT_FILENO, null);
81
		execvp(cmd[0], cmd);
82
		_exit(0);
83
	} else {
84
		waitpid(pid, 0, 0);
85
	}
86
}
87
 
88
void rv_create_repo(const char* repouser) {
89
	char* user = rv_strdup(repouser);
90
	int i;
91
	for(i = 0; user[i] != 0; i++) {
92
		if(user[i] == REPO_USER_DELIM) {
93
			user[i] = 0;
20 nishi 94
			char* tmp = user;
95
			user = rv_strdup(user + i + 1);
96
			free(tmp);
11 nishi 97
			break;
98
		}
99
	}
100
	char* path = rv_strcat3(SVN_ROOT, "/", repouser);
101
	char* cmd[] = {"svnadmin", "create", path, NULL};
102
	null_exec(cmd);
16 nishi 103
 
104
	char* readme = rv_strcat(path, "/README.txt");
105
	FILE* f = fopen(readme, "w");
106
	fprintf(f, "This is the default README of the RepoView repository.\n");
107
	fprintf(f, "You can change it from the repository manager.\n");
108
	fclose(f);
109
	free(readme);
110
 
11 nishi 111
	free(path);
16 nishi 112
	f = fopen(APACHE_AUTHZ, "r+");
11 nishi 113
	lockf(fileno(f), F_LOCK, 0);
114
 
115
	fseek(f, 0, SEEK_END);
116
 
117
	fprintf(f, "#%%START %s\n", repouser);
15 nishi 118
	fprintf(f, "[%s:/]\n", repouser);
11 nishi 119
	fprintf(f, "* = r\n");
15 nishi 120
	fprintf(f, "%s = rw\n", user);
11 nishi 121
	fprintf(f, "#%%END\n");
122
 
123
	lockf(fileno(f), F_ULOCK, 0);
124
	free(user);
125
}
126
 
127
char* rv_get_readme(const char* repouser) {
128
	char* tmp = rv_strcat3(SVN_ROOT, "/", repouser);
129
	char* path = rv_strcat(tmp, "/README.txt");
130
	free(tmp);
131
	struct stat s;
132
	if(stat(path, &s) == 0) {
133
		FILE* f = fopen(path, "r");
134
		char* buf = malloc(s.st_size + 1);
135
		fread(buf, 1, s.st_size, f);
136
		fclose(f);
137
		buf[s.st_size] = 0;
138
		return buf;
139
	}
140
	return NULL;
141
}
142
 
143
long long rv_get_filesize(const char* repouser, const char* path) {
144
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
145
	int pipes[2];
146
	pipe(pipes);
147
	pid_t pid = fork();
148
	if(pid == 0) {
149
		close(pipes[0]);
150
		dup2(pipes[1], STDOUT_FILENO);
151
		char* cmd[] = {"svnlook", "filesize", svnpath, (char*)path, NULL};
152
		execvp("svnlook", cmd);
153
		_exit(0);
154
	} else {
155
		close(pipes[1]);
156
		char cbuf[2];
157
		cbuf[1] = 0;
158
		char* d = malloc(1);
159
		d[0] = 0;
160
		while(1) {
161
			int n = read(pipes[0], cbuf, 1);
162
			if(n == 0) break;
163
			char* tmp = d;
164
			d = rv_strcat(tmp, cbuf);
165
			free(tmp);
166
		}
167
		int status;
168
		waitpid(pid, &status, 0);
169
		if(WEXITSTATUS(status) != 0) {
170
			free(d);
171
			free(svnpath);
172
			return -1;
173
		}
174
		long long sz = atoll(d);
175
		free(svnpath);
176
		free(d);
177
		return sz;
178
	}
179
}
180
 
14 nishi 181
void rv_remove_repo(const char* repouser) {
182
	printf("");
183
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
184
	pid_t pid = fork();
185
	if(pid == 0) {
186
		char* cmd[] = {"rm", "-rf", svnpath, NULL};
187
		execvp("rm", cmd);
188
		_exit(0);
189
	} else {
190
		waitpid(pid, 0, 0);
191
	}
192
	free(svnpath);
193
 
194
	FILE* f = fopen(APACHE_AUTHZ, "r+");
195
	lockf(fileno(f), F_LOCK, 0);
196
 
197
	fseek(f, 0, SEEK_SET);
198
	struct stat s;
199
	stat(APACHE_AUTHZ, &s);
200
	char* buffer = malloc(s.st_size + 1);
201
	fread(buffer, 1, s.st_size, f);
202
	buffer[s.st_size] = 0;
203
 
204
	f = freopen(APACHE_AUTHZ, "w+", f);
205
	lockf(fileno(f), F_LOCK, 0);
206
	int incr = 0;
207
	int i;
208
	char* start = rv_strcat("#%START ", repouser);
209
	bool discard = false;
210
	for(i = 0;; i++) {
211
		if(buffer[i] == '\n' || buffer[i] == 0) {
212
			char oldc = buffer[i];
213
			buffer[i] = 0;
214
 
215
			char* line = buffer + incr;
216
			if(strcmp(line, start) == 0) {
217
				discard = true;
218
			} else if(discard && strcmp(line, "#%END") == 0) {
219
				discard = false;
15 nishi 220
			} else if(strcmp(line, "") == 0) {
14 nishi 221
			} else if(!discard) {
222
				fprintf(f, "%s\n", line);
223
			}
224
 
225
			incr = i + 1;
226
			if(oldc == 0) break;
227
		}
228
	}
229
 
230
	lockf(fileno(f), F_ULOCK, 0);
231
	fclose(f);
232
}
233
 
15 nishi 234
void rv_set_readme(const char* repouser, const char* readme) {
235
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
236
	char* path = rv_strcat(svnpath, "/README.txt");
237
	FILE* f = fopen(path, "w");
238
	if(f != NULL) {
239
		fwrite(readme, 1, strlen(readme), f);
240
		fclose(f);
241
	}
242
	free(path);
243
	free(svnpath);
244
}
245
 
11 nishi 246
bool rv_get_list(const char* repouser, const char* path, void (*handler)(const char* pathname), int* isdir) {
247
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
248
	int pipes[2];
249
	*isdir = 0;
250
	pipe(pipes);
251
	pid_t pid = fork();
252
	if(pid == 0) {
253
		close(pipes[0]);
254
		dup2(pipes[1], STDOUT_FILENO);
255
		char* cmd[] = {"svnlook", "-N", "tree", svnpath, (char*)path, NULL};
256
		execvp("svnlook", cmd);
257
		_exit(0);
258
	} else {
259
		close(pipes[1]);
260
		char cbuf[2];
261
		cbuf[1] = 0;
262
		char* d = malloc(1);
263
		d[0] = 0;
264
		while(1) {
265
			int n = read(pipes[0], cbuf, 1);
266
			if(n == 0) break;
267
			char* tmp = d;
268
			d = rv_strcat(tmp, cbuf);
269
			free(tmp);
270
		}
271
		int status;
272
		waitpid(pid, &status, 0);
273
		if(WEXITSTATUS(status) != 0) {
274
			free(d);
275
			free(svnpath);
276
			return false;
277
		}
278
		int count = 0;
279
		int incr = 0;
280
		int i;
281
		int phase = 0;
282
	repeat:
283
		for(i = 0;; i++) {
284
			if(d[i] == '\r') {
285
				d[i] = 0;
286
			} else if(d[i] == '\n' || d[i] == 0) {
287
				char oldc = d[i];
288
				d[i] = 0;
289
				count++;
12 nishi 290
				if(count > 1 && d[incr] != 0 && strlen(d + incr + 1) > 0) {
11 nishi 291
					char* pathname = d + incr + 1;
292
					if(phase == 0 && pathname[strlen(pathname) - 1] == '/') {
293
						handler(d + incr + 1);
294
					} else if(phase == 1 && pathname[strlen(pathname) - 1] != '/') {
295
						handler(d + incr + 1);
296
					}
297
				} else {
298
					char* pathname = d + incr;
299
					if(pathname[strlen(pathname) - 1] == '/') *isdir = 1;
300
				}
301
				d[i] = oldc;
302
				incr = i + 1;
303
				if(oldc == 0) break;
304
			}
305
		}
306
		phase++;
12 nishi 307
		incr = 0;
308
		count = 0;
11 nishi 309
		if(phase == 1) goto repeat;
310
		free(d);
311
	}
312
	free(svnpath);
313
	return true;
314
}
315
 
316
char* rv_read_file(const char* repouser, char* path) {
12 nishi 317
	if(rv_get_filesize(repouser, path) > 1024 * 128) return NULL;
11 nishi 318
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
319
	int pipes[2];
320
	pipe(pipes);
321
	pid_t pid = fork();
322
	if(pid == 0) {
323
		close(pipes[0]);
324
		dup2(pipes[1], STDOUT_FILENO);
325
		char* cmd[] = {"svnlook", "cat", svnpath, (char*)path, NULL};
326
		execvp("svnlook", cmd);
327
		_exit(0);
328
	} else {
329
		close(pipes[1]);
12 nishi 330
		char cbuf[1024];
331
		char* d = malloc(1024 * 128);
332
		int incr = 0;
333
		bool bin = false;
11 nishi 334
		while(1) {
12 nishi 335
			int n = read(pipes[0], cbuf, 1024);
336
			if(cbuf[0] == 0) {
337
				bin = true;
338
				kill(pid, SIGKILL);
339
				break;
340
			}
11 nishi 341
			if(n == 0) break;
12 nishi 342
			memcpy(d + incr, cbuf, n);
343
			d[incr + n] = 0;
344
			incr += n;
11 nishi 345
		}
346
		int status;
347
		waitpid(pid, &status, 0);
348
		if(WEXITSTATUS(status) != 0) {
349
			free(d);
350
			free(svnpath);
351
			return NULL;
352
		}
12 nishi 353
		if(bin) {
354
			free(d);
355
			return NULL;
356
		}
11 nishi 357
		return d;
358
	}
359
}