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