Subversion Repositories RepoView

Rev

Rev 11 | Rev 14 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10 nishi 1
/* $Id: repo.c 12 2024-08-21 05:05:19Z 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;
94
			break;
95
		}
96
	}
97
	char* path = rv_strcat3(SVN_ROOT, "/", repouser);
98
	char* cmd[] = {"svnadmin", "create", path, NULL};
99
	null_exec(cmd);
100
	free(path);
101
	FILE* f = fopen(APACHE_AUTHZ, "r+");
102
	lockf(fileno(f), F_LOCK, 0);
103
 
104
	fseek(f, 0, SEEK_END);
105
 
106
	fprintf(f, "#%%START %s\n", repouser);
107
	fprintf(f, "* = r\n");
108
	fprintf(f, "%s = r\n", user);
109
	fprintf(f, "#%%END\n");
110
 
111
	lockf(fileno(f), F_ULOCK, 0);
112
	free(user);
113
}
114
 
115
char* rv_get_readme(const char* repouser) {
116
	char* tmp = rv_strcat3(SVN_ROOT, "/", repouser);
117
	char* path = rv_strcat(tmp, "/README.txt");
118
	free(tmp);
119
	struct stat s;
120
	if(stat(path, &s) == 0) {
121
		FILE* f = fopen(path, "r");
122
		char* buf = malloc(s.st_size + 1);
123
		fread(buf, 1, s.st_size, f);
124
		fclose(f);
125
		buf[s.st_size] = 0;
126
		return buf;
127
	}
128
	return NULL;
129
}
130
 
131
long long rv_get_filesize(const char* repouser, const char* path) {
132
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
133
	int pipes[2];
134
	pipe(pipes);
135
	pid_t pid = fork();
136
	if(pid == 0) {
137
		close(pipes[0]);
138
		dup2(pipes[1], STDOUT_FILENO);
139
		char* cmd[] = {"svnlook", "filesize", svnpath, (char*)path, NULL};
140
		execvp("svnlook", cmd);
141
		_exit(0);
142
	} else {
143
		close(pipes[1]);
144
		char cbuf[2];
145
		cbuf[1] = 0;
146
		char* d = malloc(1);
147
		d[0] = 0;
148
		while(1) {
149
			int n = read(pipes[0], cbuf, 1);
150
			if(n == 0) break;
151
			char* tmp = d;
152
			d = rv_strcat(tmp, cbuf);
153
			free(tmp);
154
		}
155
		int status;
156
		waitpid(pid, &status, 0);
157
		if(WEXITSTATUS(status) != 0) {
158
			free(d);
159
			free(svnpath);
160
			return -1;
161
		}
162
		long long sz = atoll(d);
163
		free(svnpath);
164
		free(d);
165
		return sz;
166
	}
167
}
168
 
169
bool rv_get_list(const char* repouser, const char* path, void (*handler)(const char* pathname), int* isdir) {
170
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
171
	int pipes[2];
172
	*isdir = 0;
173
	pipe(pipes);
174
	pid_t pid = fork();
175
	if(pid == 0) {
176
		close(pipes[0]);
177
		dup2(pipes[1], STDOUT_FILENO);
178
		char* cmd[] = {"svnlook", "-N", "tree", svnpath, (char*)path, NULL};
179
		execvp("svnlook", cmd);
180
		_exit(0);
181
	} else {
182
		close(pipes[1]);
183
		char cbuf[2];
184
		cbuf[1] = 0;
185
		char* d = malloc(1);
186
		d[0] = 0;
187
		while(1) {
188
			int n = read(pipes[0], cbuf, 1);
189
			if(n == 0) break;
190
			char* tmp = d;
191
			d = rv_strcat(tmp, cbuf);
192
			free(tmp);
193
		}
194
		int status;
195
		waitpid(pid, &status, 0);
196
		if(WEXITSTATUS(status) != 0) {
197
			free(d);
198
			free(svnpath);
199
			return false;
200
		}
201
		int count = 0;
202
		int incr = 0;
203
		int i;
204
		int phase = 0;
205
	repeat:
206
		for(i = 0;; i++) {
207
			if(d[i] == '\r') {
208
				d[i] = 0;
209
			} else if(d[i] == '\n' || d[i] == 0) {
210
				char oldc = d[i];
211
				d[i] = 0;
212
				count++;
12 nishi 213
				if(count > 1 && d[incr] != 0 && strlen(d + incr + 1) > 0) {
11 nishi 214
					char* pathname = d + incr + 1;
215
					if(phase == 0 && pathname[strlen(pathname) - 1] == '/') {
216
						handler(d + incr + 1);
217
					} else if(phase == 1 && pathname[strlen(pathname) - 1] != '/') {
218
						handler(d + incr + 1);
219
					}
220
				} else {
221
					char* pathname = d + incr;
222
					if(pathname[strlen(pathname) - 1] == '/') *isdir = 1;
223
				}
224
				d[i] = oldc;
225
				incr = i + 1;
226
				if(oldc == 0) break;
227
			}
228
		}
229
		phase++;
12 nishi 230
		incr = 0;
231
		count = 0;
11 nishi 232
		if(phase == 1) goto repeat;
233
		free(d);
234
	}
235
	free(svnpath);
236
	return true;
237
}
238
 
239
char* rv_read_file(const char* repouser, char* path) {
12 nishi 240
	if(rv_get_filesize(repouser, path) > 1024 * 128) return NULL;
11 nishi 241
	char* svnpath = rv_strcat3(SVN_ROOT, "/", repouser);
242
	int pipes[2];
243
	pipe(pipes);
244
	pid_t pid = fork();
245
	if(pid == 0) {
246
		close(pipes[0]);
247
		dup2(pipes[1], STDOUT_FILENO);
248
		char* cmd[] = {"svnlook", "cat", svnpath, (char*)path, NULL};
249
		execvp("svnlook", cmd);
250
		_exit(0);
251
	} else {
252
		close(pipes[1]);
12 nishi 253
		char cbuf[1024];
254
		char* d = malloc(1024 * 128);
255
		int incr = 0;
256
		bool bin = false;
11 nishi 257
		while(1) {
12 nishi 258
			int n = read(pipes[0], cbuf, 1024);
259
			if(cbuf[0] == 0) {
260
				bin = true;
261
				kill(pid, SIGKILL);
262
				break;
263
			}
11 nishi 264
			if(n == 0) break;
12 nishi 265
			memcpy(d + incr, cbuf, n);
266
			d[incr + n] = 0;
267
			incr += n;
11 nishi 268
		}
269
		int status;
270
		waitpid(pid, &status, 0);
271
		if(WEXITSTATUS(status) != 0) {
272
			free(d);
273
			free(svnpath);
274
			return NULL;
275
		}
12 nishi 276
		if(bin) {
277
			free(d);
278
			return NULL;
279
		}
11 nishi 280
		return d;
281
	}
282
}