xref: /openbsd-src/usr.bin/cvs/remote.c (revision 799f675f6700f14e59124f9825c723e9f2ce19dc)
1 /*	$OpenBSD: remote.c,v 1.12 2007/01/26 11:19:44 joris 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 "includes.h"
19 
20 #include "cvs.h"
21 #include "log.h"
22 #include "diff.h"
23 #include "remote.h"
24 
25 struct cvs_resp *
26 cvs_remote_get_response_info(const char *response)
27 {
28 	int i;
29 
30 	for (i = 0; cvs_responses[i].supported != -1; i++) {
31 		if (!strcmp(cvs_responses[i].name, response))
32 			return (&(cvs_responses[i]));
33 	}
34 
35 	return (NULL);
36 }
37 
38 struct cvs_req *
39 cvs_remote_get_request_info(const char *request)
40 {
41 	int i;
42 
43 	for (i = 0; cvs_requests[i].supported != -1; i++) {
44 		if (!strcmp(cvs_requests[i].name, request))
45 			return (&(cvs_requests[i]));
46 	}
47 
48 	return (NULL);
49 }
50 
51 void
52 cvs_remote_output(const char *data)
53 {
54 	FILE *out;
55 
56 	if (cvs_server_active)
57 		out = stdout;
58 	else
59 		out = current_cvsroot->cr_srvin;
60 
61 	fputs(data, out);
62 	fputs("\n", out);
63 }
64 
65 char *
66 cvs_remote_input(void)
67 {
68 	FILE *in;
69 	size_t len;
70 	char *data, *ldata;
71 
72 	if (cvs_server_active)
73 		in = stdin;
74 	else
75 		in = current_cvsroot->cr_srvout;
76 
77 	data = fgetln(in, &len);
78 	if (data == NULL) {
79 		if (sig_received != 0)
80 			fatal("received signal %d", sig_received);
81 
82 		if (cvs_server_active) {
83 			cvs_cleanup();
84 			exit(0);
85 		}
86 
87 		fatal("the connection has been closed by the server");
88 	}
89 
90 	if (data[len - 1] == '\n') {
91 		data[len - 1] = '\0';
92 		ldata = xstrdup(data);
93 	} else {
94 		ldata = xmalloc(len + 1);
95 		memcpy(ldata, data, len);
96 		ldata[len] = '\0';
97 	}
98 
99 	if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) {
100 		BUF *bp;
101 
102 		bp = cvs_buf_alloc(strlen(ldata), BUF_AUTOEXT);
103 
104 		if (cvs_buf_append(bp, ldata, strlen(ldata)) < 0)
105 			fatal("cvs_remote_input: cvs_buf_append");
106 
107 		cvs_buf_putc(bp, '\n');
108 
109 		if (cvs_buf_write_fd(bp, cvs_client_outlog_fd) < 0)
110 			fatal("cvs_remote_input: cvs_buf_write_fd");
111 
112 		cvs_buf_free(bp);
113 	}
114 
115 	return (ldata);
116 }
117 
118 void
119 cvs_remote_receive_file(int fd, size_t len)
120 {
121 	FILE *in;
122 	char data[MAXBSIZE];
123 	size_t nread, nwrite, nleft, toread;
124 
125 	if (cvs_server_active)
126 		in = stdin;
127 	else
128 		in = current_cvsroot->cr_srvout;
129 
130 	nleft = len;
131 
132 	while (nleft > 0) {
133 		toread = MIN(nleft, MAXBSIZE);
134 
135 		nread = fread(data, sizeof(char), toread, in);
136 		if (nread == 0)
137 			fatal("error receiving file");
138 
139 		nwrite = write(fd, data, nread);
140 		if (nwrite != nread)
141 			fatal("failed to write %zu bytes", nread);
142 
143 		if (cvs_server_active == 0 &&
144 		    cvs_client_outlog_fd != -1)
145 			(void)write(cvs_client_outlog_fd, data, nread);
146 
147 		nleft -= nread;
148 	}
149 }
150 
151 void
152 cvs_remote_send_file(const char *path)
153 {
154 	int l, fd;
155 	FILE *out, *in;
156 	size_t ret, rw;
157 	off_t total;
158 	struct stat st;
159 	char buf[18], data[MAXBSIZE];
160 
161 	if (cvs_server_active)
162 		out = stdout;
163 	else
164 		out = current_cvsroot->cr_srvin;
165 
166 	if ((fd = open(path, O_RDONLY)) == -1)
167 		fatal("cvs_remote_send_file: %s: %s", path, strerror(errno));
168 
169 	if (fstat(fd, &st) == -1)
170 		fatal("cvs_remote_send_file: %s: %s", path, strerror(errno));
171 
172 	cvs_modetostr(st.st_mode, buf, sizeof(buf));
173 	cvs_remote_output(buf);
174 
175 	l = snprintf(buf, sizeof(buf), "%lld", st.st_size);
176 	if (l == -1 || l >= (int)sizeof(buf))
177 		fatal("cvs_remote_send_file: overflow");
178 	cvs_remote_output(buf);
179 
180 	if ((in = fdopen(fd, "r")) == NULL)
181 		fatal("cvs_remote_send_file: fdopen %s", strerror(errno));
182 
183 	total = 0;
184 	while ((ret = fread(data, sizeof(char), MAXBSIZE, in)) != 0) {
185 		rw = fwrite(data, sizeof(char), ret, out);
186 		if (rw != ret)
187 			fatal("failed to write %zu bytes", ret);
188 
189 		if (cvs_server_active == 0 &&
190 		    cvs_client_outlog_fd != -1)
191 			(void)write(cvs_client_outlog_fd, data, ret);
192 
193 		total += ret;
194 	}
195 
196 	if (total != st.st_size)
197 		fatal("length mismatch, %lld vs %lld", total, st.st_size);
198 
199 	(void)fclose(in);
200 }
201 
202 void
203 cvs_remote_classify_file(struct cvs_file *cf)
204 {
205 	struct stat st;
206 	CVSENTRIES *entlist;
207 
208 	entlist = cvs_ent_open(cf->file_wd);
209 	cf->file_ent = cvs_ent_get(entlist, cf->file_name);
210 	cvs_ent_close(entlist, ENT_NOSYNC);
211 
212 	if (cf->file_ent != NULL && cf->file_ent->ce_status != CVS_ENT_REG) {
213 		if (cf->file_ent->ce_status == CVS_ENT_ADDED)
214 			cf->file_status = FILE_ADDED;
215 		else
216 			cf->file_status = FILE_REMOVED;
217 		return;
218 	}
219 
220 	if (cf->file_ent != NULL) {
221 		if (cf->file_ent->ce_type == CVS_ENT_DIR)
222 			cf->file_type = CVS_DIR;
223 		else
224 			cf->file_type = CVS_FILE;
225 	}
226 
227 	if (cf->fd != -1 && cf->file_ent != NULL) {
228 		if (fstat(cf->fd, &st) == -1)
229 			fatal("cvs_remote_classify_file(%s): %s", cf->file_path,
230 			    strerror(errno));
231 
232 		if (st.st_mtime != cf->file_ent->ce_mtime)
233 			cf->file_status = FILE_MODIFIED;
234 		else
235 			cf->file_status = FILE_UPTODATE;
236 	} else if (cf->fd == -1) {
237 		cf->file_status = FILE_UNKNOWN;
238 	}
239 
240 	if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE)
241 		cf->file_status = FILE_MODIFIED;
242 }
243 
244