2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/types.h>
47 #include "rsyncfile.h"
51 /* Internal error codes. */
52 #define DETAILER_ERR_PROTO (-1) /* Protocol error. */
53 #define DETAILER_ERR_MSG (-2) /* Error is in detailer->errmsg. */
54 #define DETAILER_ERR_READ (-3) /* Error reading from server. */
55 #define DETAILER_ERR_WRITE (-4) /* Error writing to server. */
58 struct config *config;
64 static int detailer_batch(struct detailer *);
65 static int detailer_coll(struct detailer *, struct coll *,
67 static int detailer_dofile_co(struct detailer *, struct coll *,
68 struct status *, char *);
69 static int detailer_dofile_rcs(struct detailer *, struct coll *,
71 static int detailer_dofile_regular(struct detailer *, char *, char *);
72 static int detailer_dofile_rsync(struct detailer *, char *, char *);
73 static int detailer_checkrcsattr(struct detailer *, struct coll *, char *,
75 int detailer_send_details(struct detailer *, struct coll *, char *,
76 char *, struct fattr *);
81 struct thread_args *args;
82 struct detailer dbuf, *d;
88 d->config = args->config;
93 error = detailer_batch(d);
95 case DETAILER_ERR_PROTO:
96 xasprintf(&args->errmsg, "Detailer failed: Protocol error");
97 args->status = STATUS_FAILURE;
99 case DETAILER_ERR_MSG:
100 xasprintf(&args->errmsg, "Detailer failed: %s", d->errmsg);
102 args->status = STATUS_FAILURE;
104 case DETAILER_ERR_READ:
105 if (stream_eof(d->rd)) {
106 xasprintf(&args->errmsg, "Detailer failed: "
107 "Premature EOF from server");
109 xasprintf(&args->errmsg, "Detailer failed: "
110 "Network read failure: %s", strerror(errno));
112 args->status = STATUS_TRANSIENTFAILURE;
114 case DETAILER_ERR_WRITE:
115 xasprintf(&args->errmsg, "Detailer failed: "
116 "Network write failure: %s", strerror(errno));
117 args->status = STATUS_TRANSIENTFAILURE;
121 args->status = STATUS_SUCCESS;
127 detailer_batch(struct detailer *d)
129 struct config *config;
130 struct stream *rd, *wr;
134 char *cmd, *collname, *line, *release;
135 int error, fixupseof;
140 STAILQ_FOREACH(coll, &config->colls, co_next) {
141 if (coll->co_options & CO_SKIP)
143 line = stream_getln(rd, NULL);
144 cmd = proto_get_ascii(&line);
145 collname = proto_get_ascii(&line);
146 release = proto_get_ascii(&line);
147 error = proto_get_time(&line, &coll->co_scantime);
148 if (error || line != NULL || strcmp(cmd, "COLL") != 0 ||
149 strcmp(collname, coll->co_name) != 0 ||
150 strcmp(release, coll->co_release) != 0)
151 return (DETAILER_ERR_PROTO);
152 error = proto_printf(wr, "COLL %s %s\n", coll->co_name,
155 return (DETAILER_ERR_WRITE);
157 if (coll->co_options & CO_COMPRESS) {
158 stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
159 stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL);
161 st = status_open(coll, -1, &d->errmsg);
163 return (DETAILER_ERR_MSG);
164 error = detailer_coll(d, coll, st);
165 status_close(st, NULL);
168 if (coll->co_options & CO_COMPRESS) {
169 stream_filter_stop(rd);
170 stream_filter_stop(wr);
174 line = stream_getln(rd, NULL);
176 return (DETAILER_ERR_READ);
177 if (strcmp(line, ".") != 0)
178 return (DETAILER_ERR_PROTO);
179 error = proto_printf(wr, ".\n");
181 return (DETAILER_ERR_WRITE);
184 /* Now send fixups if needed. */
187 STAILQ_FOREACH(coll, &config->colls, co_next) {
188 if (coll->co_options & CO_SKIP)
190 error = proto_printf(wr, "COLL %s %s\n", coll->co_name,
193 return (DETAILER_ERR_WRITE);
194 if (coll->co_options & CO_COMPRESS)
195 stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL);
198 fixup = fixups_get(config->fixups);
203 if (fixup->f_coll != coll)
205 if (coll->co_options & CO_CHECKOUTMODE)
206 error = proto_printf(wr, "Y %s %s %s\n",
207 fixup->f_name, coll->co_tag, coll->co_date);
209 error = proto_printf(wr, "A %s\n",
213 return (DETAILER_ERR_WRITE);
216 error = proto_printf(wr, ".\n");
218 return (DETAILER_ERR_WRITE);
219 if (coll->co_options & CO_COMPRESS)
220 stream_filter_stop(wr);
223 error = proto_printf(wr, ".\n");
225 return (DETAILER_ERR_WRITE);
230 detailer_coll(struct detailer *d, struct coll *coll, struct status *st)
232 struct fattr *rcsattr;
233 struct stream *rd, *wr;
234 char *attr, *cmd, *file, *line, *msg, *path, *target;
240 line = stream_getln(rd, NULL);
242 return (DETAILER_ERR_READ);
243 while (strcmp(line, ".") != 0) {
244 cmd = proto_get_ascii(&line);
245 if (cmd == NULL || strlen(cmd) != 1)
246 return (DETAILER_ERR_PROTO);
250 file = proto_get_ascii(&line);
251 if (file == NULL || line != NULL)
252 return (DETAILER_ERR_PROTO);
253 error = proto_printf(wr, "D %s\n", file);
255 return (DETAILER_ERR_WRITE);
260 /* Directory operations. */
261 file = proto_get_ascii(&line);
262 if (file == NULL || line != NULL)
263 return (DETAILER_ERR_PROTO);
264 error = proto_printf(wr, "%s %s\n", cmd, file);
266 return (DETAILER_ERR_WRITE);
269 /* Set directory attributes. */
270 file = proto_get_ascii(&line);
271 attr = proto_get_ascii(&line);
272 if (file == NULL || line != NULL || attr == NULL)
273 return (DETAILER_ERR_PROTO);
274 error = proto_printf(wr, "%s %s %s\n", cmd, file, attr);
276 return (DETAILER_ERR_WRITE);
280 /* Create a hard link. */
281 file = proto_get_ascii(&line);
282 target = proto_get_ascii(&line);
283 if (file == NULL || target == NULL)
284 return (DETAILER_ERR_PROTO);
285 error = proto_printf(wr, "%s %s %s\n", cmd, file,
289 file = proto_get_ascii(&line);
290 attr = proto_get_ascii(&line);
291 if (file == NULL || attr == NULL || line != NULL) {
292 return (DETAILER_ERR_PROTO);
294 rcsattr = fattr_decode(attr);
295 if (rcsattr == NULL) {
296 return (DETAILER_ERR_PROTO);
298 error = detailer_checkrcsattr(d, coll, file, rcsattr,
303 file = proto_get_ascii(&line);
304 attr = proto_get_ascii(&line);
305 if (file == NULL || attr == NULL || line != NULL)
306 return (DETAILER_ERR_PROTO);
307 rcsattr = fattr_decode(attr);
309 return (DETAILER_ERR_PROTO);
310 error = detailer_checkrcsattr(d, coll, file, rcsattr,
315 /* Add or update file. */
316 file = proto_get_ascii(&line);
317 if (file == NULL || line != NULL)
318 return (DETAILER_ERR_PROTO);
319 if (coll->co_options & CO_CHECKOUTMODE) {
320 error = detailer_dofile_co(d, coll, st, file);
322 path = cvspath(coll->co_prefix, file, 0);
323 rcsattr = fattr_frompath(path, FATTR_NOFOLLOW);
324 error = detailer_send_details(d, coll, file,
334 /* Warning from server. */
335 msg = proto_get_rest(&line);
337 return (DETAILER_ERR_PROTO);
338 lprintf(-1, "Server warning: %s\n", msg);
341 return (DETAILER_ERR_PROTO);
344 line = stream_getln(rd, NULL);
346 return (DETAILER_ERR_READ);
348 error = proto_printf(wr, ".\n");
350 return (DETAILER_ERR_WRITE);
355 * Tell the server to update a regular file.
358 detailer_dofile_regular(struct detailer *d, char *name, char *path)
362 char md5[MD5_DIGEST_SIZE];
366 error = stat(path, &st);
367 /* If we don't have it or it's unaccessible, we want it again. */
369 proto_printf(wr, "A %s\n", name);
373 /* If not, we want the file to be updated. */
374 error = MD5_File(path, md5);
376 lprintf(-1, "Error reading \"%s\"\n", name);
379 error = proto_printf(wr, "R %s %O %s\n", name, st.st_size, md5);
381 return (DETAILER_ERR_WRITE);
386 * Tell the server to update a file with the rsync algorithm.
389 detailer_dofile_rsync(struct detailer *d, char *name, char *path)
392 struct rsyncfile *rf;
395 rf = rsync_open(path, 0, 1);
397 /* Fallback if we fail in opening it. */
398 proto_printf(wr, "A %s\n", name);
401 proto_printf(wr, "r %s %z %z\n", name, rsync_filesize(rf),
402 rsync_blocksize(rf));
403 /* Detail the blocks. */
404 while (rsync_nextblock(rf) != 0)
405 proto_printf(wr, "%s %s\n", rsync_rsum(rf), rsync_blockmd5(rf));
406 proto_printf(wr, ".\n");
412 * Tell the server to update an RCS file that we have, or send it if we don't.
415 detailer_dofile_rcs(struct detailer *d, struct coll *coll, char *name,
424 path = atticpath(coll->co_prefix, name);
425 fa = fattr_frompath(path, FATTR_NOFOLLOW);
427 /* We don't have it, so send request to get it. */
428 error = proto_printf(wr, "A %s\n", name);
430 return (DETAILER_ERR_WRITE);
435 rf = rcsfile_frompath(path, name, coll->co_cvsroot, coll->co_tag, 1);
438 error = proto_printf(wr, "A %s\n", name);
440 return (DETAILER_ERR_WRITE);
443 /* Tell to update the RCS file. The client version details follow. */
444 rcsfile_send_details(rf, wr);
451 detailer_dofile_co(struct detailer *d, struct coll *coll, struct status *st,
456 struct statusrec *sr;
457 char md5[MD5_DIGEST_SIZE];
462 path = checkoutpath(coll->co_prefix, file);
464 return (DETAILER_ERR_PROTO);
465 fa = fattr_frompath(path, FATTR_NOFOLLOW);
467 /* We don't have the file, so the only option at this
468 point is to tell the server to send it. The server
469 may figure out that the file is dead, in which case
471 error = proto_printf(wr, "C %s %s %s\n",
472 file, coll->co_tag, coll->co_date);
475 return (DETAILER_ERR_WRITE);
478 ret = status_get(st, file, 0, 0, &sr);
480 d->errmsg = status_errmsg(st);
482 return (DETAILER_ERR_MSG);
487 /* If our recorded information doesn't match the file that the
488 client has, then ignore the recorded information. */
489 if (sr != NULL && (sr->sr_type != SR_CHECKOUTLIVE ||
490 !fattr_equal(sr->sr_clientattr, fa)))
493 if (sr != NULL && strcmp(sr->sr_revdate, ".") != 0) {
494 error = proto_printf(wr, "U %s %s %s %s %s\n", file,
495 coll->co_tag, coll->co_date, sr->sr_revnum, sr->sr_revdate);
498 return (DETAILER_ERR_WRITE);
503 * We don't have complete and/or accurate recorded information
504 * about what version of the file we have. Compute the file's
505 * checksum as an aid toward identifying which version it is.
507 error = MD5_File(path, md5);
509 xasprintf(&d->errmsg,
510 "Cannot calculate checksum for \"%s\": %s", path,
512 return (DETAILER_ERR_MSG);
516 error = proto_printf(wr, "S %s %s %s %s\n", file,
517 coll->co_tag, coll->co_date, md5);
519 error = proto_printf(wr, "s %s %s %s %s %s\n", file,
520 coll->co_tag, coll->co_date, sr->sr_revnum, md5);
523 return (DETAILER_ERR_WRITE);
528 detailer_checkrcsattr(struct detailer *d, struct coll *coll, char *name,
529 struct fattr *server_attr, int attic)
531 struct fattr *client_attr;
536 * I don't think we can use the status file, since it only records file
537 * attributes in cvsmode.
540 path = cvspath(coll->co_prefix, name, attic);
542 return (DETAILER_ERR_PROTO);
545 if (access(path, F_OK) == 0 &&
546 ((client_attr = fattr_frompath(path, FATTR_NOFOLLOW)) != NULL) &&
547 fattr_equal(client_attr, server_attr)) {
548 attr = fattr_encode(client_attr, NULL, 0);
550 error = proto_printf(d->wr, "l %s %s\n", name, attr);
552 error = proto_printf(d->wr, "L %s %s\n", name, attr);
556 fattr_free(client_attr);
558 return (DETAILER_ERR_WRITE);
561 /* We don't have it, so tell the server to send it. */
562 error = detailer_send_details(d, coll, name, path, client_attr);
563 fattr_free(client_attr);
569 detailer_send_details(struct detailer *d, struct coll *coll, char *name,
570 char *path, struct fattr *fa)
576 * Try to check if the file exists either live or dead to see if we can
577 * edit it and put it live or dead, rather than receiving the entire
581 path = atticpath(coll->co_prefix, name);
582 fa = fattr_frompath(path, FATTR_NOFOLLOW);
585 error = proto_printf(d->wr, "A %s\n", name);
587 return (DETAILER_ERR_WRITE);
588 } else if (fattr_type(fa) == FT_FILE) {
589 if (isrcs(name, &len) && !(coll->co_options & CO_NORCS)) {
590 detailer_dofile_rcs(d, coll, name, path);
591 } else if (!(coll->co_options & CO_NORSYNC) &&
592 !globtree_test(coll->co_norsync, name)) {
593 detailer_dofile_rsync(d, name, path);
595 detailer_dofile_regular(d, name, path);
598 error = proto_printf(d->wr, "N %s\n", name);
600 return (DETAILER_ERR_WRITE);