1 |
|
|
/* $OpenBSD: remote.c,v 1.32 2017/08/28 19:33:20 otto Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2006 Joris Vink <joris@openbsd.org> |
4 |
|
|
* |
5 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
6 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
7 |
|
|
* copyright notice and this permission notice appear in all copies. |
8 |
|
|
* |
9 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include <sys/param.h> /* MAXBSIZE */ |
19 |
|
|
#include <sys/stat.h> |
20 |
|
|
|
21 |
|
|
#include <errno.h> |
22 |
|
|
#include <fcntl.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
#include <unistd.h> |
26 |
|
|
|
27 |
|
|
#include "atomicio.h" |
28 |
|
|
#include "cvs.h" |
29 |
|
|
#include "remote.h" |
30 |
|
|
|
31 |
|
|
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) |
32 |
|
|
|
33 |
|
|
struct cvs_resp * |
34 |
|
|
cvs_remote_get_response_info(const char *response) |
35 |
|
|
{ |
36 |
|
|
int i; |
37 |
|
|
|
38 |
|
|
for (i = 0; cvs_responses[i].supported != -1; i++) { |
39 |
|
|
if (!strcmp(cvs_responses[i].name, response)) |
40 |
|
|
return (&(cvs_responses[i])); |
41 |
|
|
} |
42 |
|
|
|
43 |
|
|
return (NULL); |
44 |
|
|
} |
45 |
|
|
|
46 |
|
|
struct cvs_req * |
47 |
|
|
cvs_remote_get_request_info(const char *request) |
48 |
|
|
{ |
49 |
|
|
int i; |
50 |
|
|
|
51 |
|
|
for (i = 0; cvs_requests[i].supported != -1; i++) { |
52 |
|
|
if (!strcmp(cvs_requests[i].name, request)) |
53 |
|
|
return (&(cvs_requests[i])); |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
return (NULL); |
57 |
|
|
} |
58 |
|
|
|
59 |
|
|
void |
60 |
|
|
cvs_remote_output(char *data) |
61 |
|
|
{ |
62 |
|
|
FILE *out; |
63 |
|
|
size_t len; |
64 |
|
|
char nl = '\n'; |
65 |
|
|
|
66 |
|
|
if (cvs_server_active) |
67 |
|
|
out = stdout; |
68 |
|
|
else |
69 |
|
|
out = current_cvsroot->cr_srvin; |
70 |
|
|
|
71 |
|
|
fputs(data, out); |
72 |
|
|
fputs("\n", out); |
73 |
|
|
|
74 |
|
|
if (cvs_server_active == 0 && cvs_client_inlog_fd != -1) { |
75 |
|
|
len = strlen(data); |
76 |
|
|
if (atomicio(vwrite, cvs_client_inlog_fd, data, len) != len || |
77 |
|
|
atomicio(vwrite, cvs_client_inlog_fd, &nl, 1) != 1) |
78 |
|
|
fatal("failed to write to log file"); |
79 |
|
|
} |
80 |
|
|
} |
81 |
|
|
|
82 |
|
|
char * |
83 |
|
|
cvs_remote_input(void) |
84 |
|
|
{ |
85 |
|
|
FILE *in; |
86 |
|
|
size_t len; |
87 |
|
|
char nl = '\n'; |
88 |
|
|
char *data, *ldata; |
89 |
|
|
|
90 |
|
|
if (cvs_server_active) |
91 |
|
|
in = stdin; |
92 |
|
|
else |
93 |
|
|
in = current_cvsroot->cr_srvout; |
94 |
|
|
|
95 |
|
|
data = fgetln(in, &len); |
96 |
|
|
if (data == NULL) { |
97 |
|
|
if (sig_received != 0) |
98 |
|
|
fatal("received signal %d", sig_received); |
99 |
|
|
|
100 |
|
|
if (cvs_server_active) { |
101 |
|
|
cvs_cleanup(); |
102 |
|
|
exit(0); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
fatal("the connection has been closed by the server"); |
106 |
|
|
} |
107 |
|
|
|
108 |
|
|
if (data[len - 1] == '\n') { |
109 |
|
|
data[len - 1] = '\0'; |
110 |
|
|
ldata = xstrdup(data); |
111 |
|
|
} else { |
112 |
|
|
ldata = xmalloc(len + 1); |
113 |
|
|
memcpy(ldata, data, len); |
114 |
|
|
ldata[len] = '\0'; |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) { |
118 |
|
|
len = strlen(data); |
119 |
|
|
if (atomicio(vwrite, cvs_client_outlog_fd, data, len) != len || |
120 |
|
|
atomicio(vwrite, cvs_client_outlog_fd, &nl, 1) != 1) |
121 |
|
|
fatal("failed to write to log file"); |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
return (ldata); |
125 |
|
|
} |
126 |
|
|
|
127 |
|
|
void |
128 |
|
|
cvs_remote_receive_file(int fd, size_t len) |
129 |
|
|
{ |
130 |
|
|
FILE *in; |
131 |
|
|
char data[MAXBSIZE]; |
132 |
|
|
size_t nread, nleft, toread; |
133 |
|
|
|
134 |
|
|
if (cvs_server_active) |
135 |
|
|
in = stdin; |
136 |
|
|
else |
137 |
|
|
in = current_cvsroot->cr_srvout; |
138 |
|
|
|
139 |
|
|
nleft = len; |
140 |
|
|
|
141 |
|
|
while (nleft > 0) { |
142 |
|
|
toread = MINIMUM(nleft, MAXBSIZE); |
143 |
|
|
|
144 |
|
|
nread = fread(data, sizeof(char), toread, in); |
145 |
|
|
if (nread == 0) |
146 |
|
|
fatal("error receiving file"); |
147 |
|
|
|
148 |
|
|
if (atomicio(vwrite, fd, data, nread) != nread) |
149 |
|
|
fatal("failed to write %zu bytes", nread); |
150 |
|
|
|
151 |
|
|
if (cvs_server_active == 0 && cvs_client_outlog_fd != -1 && |
152 |
|
|
atomicio(vwrite, cvs_client_outlog_fd, data, nread) |
153 |
|
|
!= nread) |
154 |
|
|
fatal("failed to write to log file"); |
155 |
|
|
|
156 |
|
|
nleft -= nread; |
157 |
|
|
} |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
void |
161 |
|
|
cvs_remote_send_file(const char *path, int _fd) |
162 |
|
|
{ |
163 |
|
|
int fd; |
164 |
|
|
FILE *out, *in; |
165 |
|
|
size_t ret, rw; |
166 |
|
|
off_t total; |
167 |
|
|
struct stat st; |
168 |
|
|
char buf[18], data[MAXBSIZE]; |
169 |
|
|
|
170 |
|
|
if (cvs_server_active) |
171 |
|
|
out = stdout; |
172 |
|
|
else |
173 |
|
|
out = current_cvsroot->cr_srvin; |
174 |
|
|
|
175 |
|
|
fd = dup(_fd); |
176 |
|
|
if (fd == -1) |
177 |
|
|
fatal("cvs_remote_send_file: dup: %s", strerror(errno)); |
178 |
|
|
|
179 |
|
|
if (lseek(fd, 0, SEEK_SET) < 0) |
180 |
|
|
fatal("cvs_remote_send_file: %s: lseek: %s", path, |
181 |
|
|
strerror(errno)); |
182 |
|
|
|
183 |
|
|
if (fstat(fd, &st) == -1) |
184 |
|
|
fatal("cvs_remote_send_file: %s: fstat: %s", path, |
185 |
|
|
strerror(errno)); |
186 |
|
|
|
187 |
|
|
cvs_modetostr(st.st_mode, buf, sizeof(buf)); |
188 |
|
|
cvs_remote_output(buf); |
189 |
|
|
|
190 |
|
|
(void)xsnprintf(buf, sizeof(buf), "%lld", st.st_size); |
191 |
|
|
cvs_remote_output(buf); |
192 |
|
|
|
193 |
|
|
if ((in = fdopen(fd, "r")) == NULL) |
194 |
|
|
fatal("cvs_remote_send_file: fdopen %s", strerror(errno)); |
195 |
|
|
|
196 |
|
|
total = 0; |
197 |
|
|
while ((ret = fread(data, sizeof(char), MAXBSIZE, in)) != 0) { |
198 |
|
|
rw = fwrite(data, sizeof(char), ret, out); |
199 |
|
|
if (rw != ret) |
200 |
|
|
fatal("failed to write %zu bytes", ret); |
201 |
|
|
|
202 |
|
|
if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 && |
203 |
|
|
atomicio(vwrite, cvs_client_inlog_fd, data, ret) != ret) |
204 |
|
|
fatal("failed to write to log file"); |
205 |
|
|
|
206 |
|
|
total += ret; |
207 |
|
|
} |
208 |
|
|
|
209 |
|
|
if (total != st.st_size) |
210 |
|
|
fatal("length mismatch, %lld vs %lld", total, st.st_size); |
211 |
|
|
|
212 |
|
|
(void)fclose(in); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
void |
216 |
|
|
cvs_remote_send_file_buf(char *file, BUF *bp, mode_t mode) |
217 |
|
|
{ |
218 |
|
|
char buf[18]; |
219 |
|
|
u_char *data; |
220 |
|
|
size_t len, ret; |
221 |
|
|
|
222 |
|
|
if (cvs_server_active != 1) |
223 |
|
|
fatal("cvs_remote_send_file_buf is server only"); |
224 |
|
|
|
225 |
|
|
len = buf_len(bp); |
226 |
|
|
data = buf_release(bp); |
227 |
|
|
|
228 |
|
|
cvs_modetostr(mode, buf, sizeof(buf)); |
229 |
|
|
cvs_remote_output(buf); |
230 |
|
|
|
231 |
|
|
(void)xsnprintf(buf, sizeof(buf), "%ld", len); |
232 |
|
|
cvs_remote_output(buf); |
233 |
|
|
|
234 |
|
|
ret = fwrite(data, sizeof(char), len, stdout); |
235 |
|
|
if (ret != len) |
236 |
|
|
cvs_log(LP_ERR, "warning: sent %s truncated", file); |
237 |
|
|
|
238 |
|
|
if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 && |
239 |
|
|
atomicio(vwrite, cvs_client_inlog_fd, data, len) != len) |
240 |
|
|
fatal("failed to write to log file"); |
241 |
|
|
|
242 |
|
|
free(data); |
243 |
|
|
} |
244 |
|
|
|
245 |
|
|
void |
246 |
|
|
cvs_remote_classify_file(struct cvs_file *cf) |
247 |
|
|
{ |
248 |
|
|
struct stat st; |
249 |
|
|
CVSENTRIES *entlist; |
250 |
|
|
|
251 |
|
|
entlist = cvs_ent_open(cf->file_wd); |
252 |
|
|
cf->file_ent = cvs_ent_get(entlist, cf->file_name); |
253 |
|
|
|
254 |
|
|
if (cf->file_ent != NULL && cf->file_ent->ce_status != CVS_ENT_REG) { |
255 |
|
|
if (cf->file_ent->ce_status == CVS_ENT_ADDED) { |
256 |
|
|
if (cf->fd != -1) |
257 |
|
|
cf->file_status = FILE_ADDED; |
258 |
|
|
else |
259 |
|
|
cf->file_status = FILE_UNKNOWN; |
260 |
|
|
} else { |
261 |
|
|
cf->file_status = FILE_REMOVED; |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
return; |
265 |
|
|
} |
266 |
|
|
|
267 |
|
|
if (cf->file_ent != NULL) { |
268 |
|
|
if (cf->file_ent->ce_type == CVS_ENT_DIR) |
269 |
|
|
cf->file_type = CVS_DIR; |
270 |
|
|
else |
271 |
|
|
cf->file_type = CVS_FILE; |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
if (cf->fd != -1) |
275 |
|
|
cf->file_flags |= FILE_ON_DISK; |
276 |
|
|
|
277 |
|
|
if ((cf->file_flags & FILE_ON_DISK) && cf->file_ent != NULL) { |
278 |
|
|
if (fstat(cf->fd, &st) == -1) |
279 |
|
|
fatal("cvs_remote_classify_file(%s): %s", cf->file_path, |
280 |
|
|
strerror(errno)); |
281 |
|
|
|
282 |
|
|
if (st.st_mtime != cf->file_ent->ce_mtime || |
283 |
|
|
cf->file_ent->ce_conflict != NULL) |
284 |
|
|
cf->file_status = FILE_MODIFIED; |
285 |
|
|
else |
286 |
|
|
cf->file_status = FILE_UPTODATE; |
287 |
|
|
} else if (!(cf->file_flags & FILE_ON_DISK)) { |
288 |
|
|
cf->file_status = FILE_UNKNOWN; |
289 |
|
|
} |
290 |
|
|
|
291 |
|
|
if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE) |
292 |
|
|
cf->file_status = FILE_MODIFIED; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
|
296 |
|
|
void |
297 |
|
|
cvs_validate_directory(const char *path) |
298 |
|
|
{ |
299 |
|
|
char *dir, *sp, *dp; |
300 |
|
|
|
301 |
|
|
dir = xstrdup(path); |
302 |
|
|
|
303 |
|
|
for (sp = dir; sp != NULL; sp = dp) { |
304 |
|
|
dp = strchr(sp, '/'); |
305 |
|
|
if (dp != NULL) |
306 |
|
|
*(dp++) = '\0'; |
307 |
|
|
|
308 |
|
|
if (!strcmp(sp, "..")) |
309 |
|
|
fatal("path validation failed!"); |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
free(dir); |
313 |
|
|
} |