Annotation of src/usr.bin/cvs/remote.c, Revision 1.34
1.34 ! deraadt 1: /* $OpenBSD: remote.c,v 1.33 2019/06/28 13:35:00 deraadt 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.34 ! deraadt 18: #include <sys/types.h>
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))
1.34 ! deraadt 32: #define _MAXBSIZE (64 * 1024)
1.30 deraadt 33:
1.1 joris 34: struct cvs_resp *
35: cvs_remote_get_response_info(const char *response)
36: {
37: int i;
38:
39: for (i = 0; cvs_responses[i].supported != -1; i++) {
40: if (!strcmp(cvs_responses[i].name, response))
41: return (&(cvs_responses[i]));
42: }
43:
44: return (NULL);
45: }
46:
47: struct cvs_req *
48: cvs_remote_get_request_info(const char *request)
49: {
50: int i;
51:
52: for (i = 0; cvs_requests[i].supported != -1; i++) {
53: if (!strcmp(cvs_requests[i].name, request))
54: return (&(cvs_requests[i]));
55: }
56:
57: return (NULL);
58: }
59:
60: void
1.32 otto 61: cvs_remote_output(char *data)
1.1 joris 62: {
63: FILE *out;
1.17 tobias 64: size_t len;
1.16 tobias 65: char nl = '\n';
1.1 joris 66:
67: if (cvs_server_active)
68: out = stdout;
69: else
70: out = current_cvsroot->cr_srvin;
71:
72: fputs(data, out);
73: fputs("\n", out);
1.16 tobias 74:
75: if (cvs_server_active == 0 && cvs_client_inlog_fd != -1) {
1.17 tobias 76: len = strlen(data);
77: if (atomicio(vwrite, cvs_client_inlog_fd, data, len) != len ||
78: atomicio(vwrite, cvs_client_inlog_fd, &nl, 1) != 1)
79: fatal("failed to write to log file");
1.16 tobias 80: }
1.1 joris 81: }
82:
83: char *
84: cvs_remote_input(void)
85: {
86: FILE *in;
87: size_t len;
1.16 tobias 88: char nl = '\n';
1.1 joris 89: char *data, *ldata;
90:
91: if (cvs_server_active)
92: in = stdin;
93: else
94: in = current_cvsroot->cr_srvout;
95:
96: data = fgetln(in, &len);
97: if (data == NULL) {
98: if (sig_received != 0)
99: fatal("received signal %d", sig_received);
100:
101: if (cvs_server_active) {
102: cvs_cleanup();
103: exit(0);
104: }
105:
106: fatal("the connection has been closed by the server");
107: }
108:
109: if (data[len - 1] == '\n') {
110: data[len - 1] = '\0';
1.9 otto 111: ldata = xstrdup(data);
1.1 joris 112: } else {
113: ldata = xmalloc(len + 1);
1.9 otto 114: memcpy(ldata, data, len);
115: ldata[len] = '\0';
1.1 joris 116: }
1.5 joris 117:
118: if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) {
1.17 tobias 119: len = strlen(data);
120: if (atomicio(vwrite, cvs_client_outlog_fd, data, len) != len ||
121: atomicio(vwrite, cvs_client_outlog_fd, &nl, 1) != 1)
122: fatal("failed to write to log file");
1.5 joris 123: }
124:
1.1 joris 125: return (ldata);
126: }
127:
1.6 joris 128: void
129: cvs_remote_receive_file(int fd, size_t len)
1.1 joris 130: {
131: FILE *in;
1.34 ! deraadt 132: char data[_MAXBSIZE];
1.17 tobias 133: size_t nread, nleft, toread;
1.1 joris 134:
135: if (cvs_server_active)
136: in = stdin;
137: else
138: in = current_cvsroot->cr_srvout;
139:
1.6 joris 140: nleft = len;
141:
142: while (nleft > 0) {
1.34 ! deraadt 143: toread = MINIMUM(nleft, sizeof data);
1.6 joris 144:
145: nread = fread(data, sizeof(char), toread, in);
146: if (nread == 0)
147: fatal("error receiving file");
1.4 joris 148:
1.17 tobias 149: if (atomicio(vwrite, fd, data, nread) != nread)
1.8 otto 150: fatal("failed to write %zu bytes", nread);
1.6 joris 151:
1.17 tobias 152: if (cvs_server_active == 0 && cvs_client_outlog_fd != -1 &&
153: atomicio(vwrite, cvs_client_outlog_fd, data, nread)
154: != nread)
155: fatal("failed to write to log file");
1.1 joris 156:
1.6 joris 157: nleft -= nread;
1.5 joris 158: }
1.1 joris 159: }
160:
161: void
1.21 joris 162: cvs_remote_send_file(const char *path, int _fd)
1.1 joris 163: {
1.13 xsa 164: int fd;
1.6 joris 165: FILE *out, *in;
1.8 otto 166: size_t ret, rw;
167: off_t total;
1.1 joris 168: struct stat st;
1.34 ! deraadt 169: char buf[18], data[_MAXBSIZE];
1.1 joris 170:
171: if (cvs_server_active)
172: out = stdout;
173: else
174: out = current_cvsroot->cr_srvin;
175:
1.21 joris 176: fd = dup(_fd);
177: if (fd == -1)
178: fatal("cvs_remote_send_file: dup: %s", strerror(errno));
179:
1.33 deraadt 180: if (lseek(fd, 0, SEEK_SET) == -1)
1.21 joris 181: fatal("cvs_remote_send_file: %s: lseek: %s", path,
182: strerror(errno));
1.1 joris 183:
184: if (fstat(fd, &st) == -1)
1.21 joris 185: fatal("cvs_remote_send_file: %s: fstat: %s", path,
186: strerror(errno));
1.1 joris 187:
188: cvs_modetostr(st.st_mode, buf, sizeof(buf));
189: cvs_remote_output(buf);
190:
1.13 xsa 191: (void)xsnprintf(buf, sizeof(buf), "%lld", st.st_size);
1.1 joris 192: cvs_remote_output(buf);
193:
1.6 joris 194: if ((in = fdopen(fd, "r")) == NULL)
195: fatal("cvs_remote_send_file: fdopen %s", strerror(errno));
196:
197: total = 0;
1.34 ! deraadt 198: while ((ret = fread(data, sizeof(char), sizeof data, in)) != 0) {
1.6 joris 199: rw = fwrite(data, sizeof(char), ret, out);
200: if (rw != ret)
1.8 otto 201: fatal("failed to write %zu bytes", ret);
1.5 joris 202:
1.17 tobias 203: if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 &&
204: atomicio(vwrite, cvs_client_inlog_fd, data, ret) != ret)
205: fatal("failed to write to log file");
1.6 joris 206:
207: total += ret;
1.5 joris 208: }
1.1 joris 209:
1.6 joris 210: if (total != st.st_size)
1.8 otto 211: fatal("length mismatch, %lld vs %lld", total, st.st_size);
1.4 joris 212:
1.6 joris 213: (void)fclose(in);
1.23 joris 214: }
215:
216: void
217: cvs_remote_send_file_buf(char *file, BUF *bp, mode_t mode)
218: {
219: char buf[18];
220: u_char *data;
221: size_t len, ret;
222:
223: if (cvs_server_active != 1)
224: fatal("cvs_remote_send_file_buf is server only");
225:
1.29 ray 226: len = buf_len(bp);
227: data = buf_release(bp);
1.23 joris 228:
229: cvs_modetostr(mode, buf, sizeof(buf));
230: cvs_remote_output(buf);
231:
232: (void)xsnprintf(buf, sizeof(buf), "%ld", len);
233: cvs_remote_output(buf);
234:
235: ret = fwrite(data, sizeof(char), len, stdout);
236: if (ret != len)
237: cvs_log(LP_ERR, "warning: sent %s truncated", file);
238:
239: if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 &&
240: atomicio(vwrite, cvs_client_inlog_fd, data, len) != len)
241: fatal("failed to write to log file");
242:
1.31 nicm 243: free(data);
1.1 joris 244: }
245:
246: void
247: cvs_remote_classify_file(struct cvs_file *cf)
248: {
249: struct stat st;
250: CVSENTRIES *entlist;
251:
252: entlist = cvs_ent_open(cf->file_wd);
253: cf->file_ent = cvs_ent_get(entlist, cf->file_name);
254:
255: if (cf->file_ent != NULL && cf->file_ent->ce_status != CVS_ENT_REG) {
1.28 joris 256: if (cf->file_ent->ce_status == CVS_ENT_ADDED) {
257: if (cf->fd != -1)
258: cf->file_status = FILE_ADDED;
259: else
260: cf->file_status = FILE_UNKNOWN;
261: } else {
1.1 joris 262: cf->file_status = FILE_REMOVED;
1.28 joris 263: }
264:
1.1 joris 265: return;
1.2 joris 266: }
267:
268: if (cf->file_ent != NULL) {
269: if (cf->file_ent->ce_type == CVS_ENT_DIR)
270: cf->file_type = CVS_DIR;
271: else
272: cf->file_type = CVS_FILE;
1.1 joris 273: }
274:
1.25 joris 275: if (cf->fd != -1)
276: cf->file_flags |= FILE_ON_DISK;
277:
278: if ((cf->file_flags & FILE_ON_DISK) && cf->file_ent != NULL) {
1.1 joris 279: if (fstat(cf->fd, &st) == -1)
280: fatal("cvs_remote_classify_file(%s): %s", cf->file_path,
281: strerror(errno));
282:
1.27 joris 283: if (st.st_mtime != cf->file_ent->ce_mtime ||
284: cf->file_ent->ce_conflict != NULL)
1.1 joris 285: cf->file_status = FILE_MODIFIED;
286: else
287: cf->file_status = FILE_UPTODATE;
1.25 joris 288: } else if (!(cf->file_flags & FILE_ON_DISK)) {
1.1 joris 289: cf->file_status = FILE_UNKNOWN;
290: }
1.7 joris 291:
292: if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE)
293: cf->file_status = FILE_MODIFIED;
1.1 joris 294: }
295:
1.18 joris 296:
297: void
298: cvs_validate_directory(const char *path)
299: {
300: char *dir, *sp, *dp;
301:
1.20 joris 302: dir = xstrdup(path);
1.18 joris 303:
304: for (sp = dir; sp != NULL; sp = dp) {
305: dp = strchr(sp, '/');
306: if (dp != NULL)
307: *(dp++) = '\0';
308:
309: if (!strcmp(sp, ".."))
310: fatal("path validation failed!");
311: }
312:
1.31 nicm 313: free(dir);
1.18 joris 314: }