Annotation of src/usr.bin/cvs/remote.c, Revision 1.32
1.32 ! otto 1: /* $OpenBSD: remote.c,v 1.31 2015/11/05 09:48:21 nicm Exp $ */
1.1 joris 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:
1.30 deraadt 18: #include <sys/param.h> /* MAXBSIZE */
1.14 otto 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>
1.1 joris 26:
1.17 tobias 27: #include "atomicio.h"
1.1 joris 28: #include "cvs.h"
29: #include "remote.h"
30:
1.30 deraadt 31: #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
32:
1.1 joris 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
1.32 ! otto 60: cvs_remote_output(char *data)
1.1 joris 61: {
62: FILE *out;
1.17 tobias 63: size_t len;
1.16 tobias 64: char nl = '\n';
1.1 joris 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);
1.16 tobias 73:
74: if (cvs_server_active == 0 && cvs_client_inlog_fd != -1) {
1.17 tobias 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");
1.16 tobias 79: }
1.1 joris 80: }
81:
82: char *
83: cvs_remote_input(void)
84: {
85: FILE *in;
86: size_t len;
1.16 tobias 87: char nl = '\n';
1.1 joris 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';
1.9 otto 110: ldata = xstrdup(data);
1.1 joris 111: } else {
112: ldata = xmalloc(len + 1);
1.9 otto 113: memcpy(ldata, data, len);
114: ldata[len] = '\0';
1.1 joris 115: }
1.5 joris 116:
117: if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) {
1.17 tobias 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");
1.5 joris 122: }
123:
1.1 joris 124: return (ldata);
125: }
126:
1.6 joris 127: void
128: cvs_remote_receive_file(int fd, size_t len)
1.1 joris 129: {
130: FILE *in;
1.10 otto 131: char data[MAXBSIZE];
1.17 tobias 132: size_t nread, nleft, toread;
1.1 joris 133:
134: if (cvs_server_active)
135: in = stdin;
136: else
137: in = current_cvsroot->cr_srvout;
138:
1.6 joris 139: nleft = len;
140:
141: while (nleft > 0) {
1.30 deraadt 142: toread = MINIMUM(nleft, MAXBSIZE);
1.6 joris 143:
144: nread = fread(data, sizeof(char), toread, in);
145: if (nread == 0)
146: fatal("error receiving file");
1.4 joris 147:
1.17 tobias 148: if (atomicio(vwrite, fd, data, nread) != nread)
1.8 otto 149: fatal("failed to write %zu bytes", nread);
1.6 joris 150:
1.17 tobias 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");
1.1 joris 155:
1.6 joris 156: nleft -= nread;
1.5 joris 157: }
1.1 joris 158: }
159:
160: void
1.21 joris 161: cvs_remote_send_file(const char *path, int _fd)
1.1 joris 162: {
1.13 xsa 163: int fd;
1.6 joris 164: FILE *out, *in;
1.8 otto 165: size_t ret, rw;
166: off_t total;
1.1 joris 167: struct stat st;
1.11 otto 168: char buf[18], data[MAXBSIZE];
1.1 joris 169:
170: if (cvs_server_active)
171: out = stdout;
172: else
173: out = current_cvsroot->cr_srvin;
174:
1.21 joris 175: fd = dup(_fd);
176: if (fd == -1)
177: fatal("cvs_remote_send_file: dup: %s", strerror(errno));
178:
1.22 joris 179: if (lseek(fd, 0, SEEK_SET) < 0)
1.21 joris 180: fatal("cvs_remote_send_file: %s: lseek: %s", path,
181: strerror(errno));
1.1 joris 182:
183: if (fstat(fd, &st) == -1)
1.21 joris 184: fatal("cvs_remote_send_file: %s: fstat: %s", path,
185: strerror(errno));
1.1 joris 186:
187: cvs_modetostr(st.st_mode, buf, sizeof(buf));
188: cvs_remote_output(buf);
189:
1.13 xsa 190: (void)xsnprintf(buf, sizeof(buf), "%lld", st.st_size);
1.1 joris 191: cvs_remote_output(buf);
192:
1.6 joris 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)
1.8 otto 200: fatal("failed to write %zu bytes", ret);
1.5 joris 201:
1.17 tobias 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");
1.6 joris 205:
206: total += ret;
1.5 joris 207: }
1.1 joris 208:
1.6 joris 209: if (total != st.st_size)
1.8 otto 210: fatal("length mismatch, %lld vs %lld", total, st.st_size);
1.4 joris 211:
1.6 joris 212: (void)fclose(in);
1.23 joris 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:
1.29 ray 225: len = buf_len(bp);
226: data = buf_release(bp);
1.23 joris 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:
1.31 nicm 242: free(data);
1.1 joris 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) {
1.28 joris 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 {
1.1 joris 261: cf->file_status = FILE_REMOVED;
1.28 joris 262: }
263:
1.1 joris 264: return;
1.2 joris 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;
1.1 joris 272: }
273:
1.25 joris 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) {
1.1 joris 278: if (fstat(cf->fd, &st) == -1)
279: fatal("cvs_remote_classify_file(%s): %s", cf->file_path,
280: strerror(errno));
281:
1.27 joris 282: if (st.st_mtime != cf->file_ent->ce_mtime ||
283: cf->file_ent->ce_conflict != NULL)
1.1 joris 284: cf->file_status = FILE_MODIFIED;
285: else
286: cf->file_status = FILE_UPTODATE;
1.25 joris 287: } else if (!(cf->file_flags & FILE_ON_DISK)) {
1.1 joris 288: cf->file_status = FILE_UNKNOWN;
289: }
1.7 joris 290:
291: if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE)
292: cf->file_status = FILE_MODIFIED;
1.1 joris 293: }
294:
1.18 joris 295:
296: void
297: cvs_validate_directory(const char *path)
298: {
299: char *dir, *sp, *dp;
300:
1.20 joris 301: dir = xstrdup(path);
1.18 joris 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:
1.31 nicm 312: free(dir);
1.18 joris 313: }