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
43 /* Internal error codes. */
44 #define DETAILER_ERR_PROTO (-1) /* Protocol error. */
45 #define DETAILER_ERR_MSG (-2) /* Error is in detailer->errmsg. */
46 #define DETAILER_ERR_READ (-3) /* Error reading from server. */
47 #define DETAILER_ERR_WRITE (-4) /* Error writing to server. */
50 struct config *config;
56 static int detailer_batch(struct detailer *);
57 static int detailer_coll(struct detailer *, struct coll *,
59 static int detailer_dofile(struct detailer *, struct coll *,
60 struct status *, char *);
65 struct thread_args *args;
66 struct detailer dbuf, *d;
72 d->config = args->config;
77 error = detailer_batch(d);
79 case DETAILER_ERR_PROTO:
80 xasprintf(&args->errmsg, "Detailer failed: Protocol error");
81 args->status = STATUS_FAILURE;
83 case DETAILER_ERR_MSG:
84 xasprintf(&args->errmsg, "Detailer failed: %s", d->errmsg);
86 args->status = STATUS_FAILURE;
88 case DETAILER_ERR_READ:
89 if (stream_eof(d->rd)) {
90 xasprintf(&args->errmsg, "Detailer failed: "
91 "Premature EOF from server");
93 xasprintf(&args->errmsg, "Detailer failed: "
94 "Network read failure: %s", strerror(errno));
96 args->status = STATUS_TRANSIENTFAILURE;
98 case DETAILER_ERR_WRITE:
99 xasprintf(&args->errmsg, "Detailer failed: "
100 "Network write failure: %s", strerror(errno));
101 args->status = STATUS_TRANSIENTFAILURE;
105 args->status = STATUS_SUCCESS;
111 detailer_batch(struct detailer *d)
113 struct config *config;
114 struct stream *rd, *wr;
118 char *cmd, *collname, *line, *release;
119 int error, fixupseof;
124 STAILQ_FOREACH(coll, &config->colls, co_next) {
125 if (coll->co_options & CO_SKIP)
127 line = stream_getln(rd, NULL);
128 cmd = proto_get_ascii(&line);
129 collname = proto_get_ascii(&line);
130 release = proto_get_ascii(&line);
131 error = proto_get_time(&line, &coll->co_scantime);
132 if (error || line != NULL || strcmp(cmd, "COLL") != 0 ||
133 strcmp(collname, coll->co_name) != 0 ||
134 strcmp(release, coll->co_release) != 0)
135 return (DETAILER_ERR_PROTO);
136 error = proto_printf(wr, "COLL %s %s\n", coll->co_name,
139 return (DETAILER_ERR_WRITE);
141 if (coll->co_options & CO_COMPRESS) {
142 stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
143 stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL);
145 st = status_open(coll, -1, &d->errmsg);
147 return (DETAILER_ERR_MSG);
148 error = detailer_coll(d, coll, st);
149 status_close(st, NULL);
152 if (coll->co_options & CO_COMPRESS) {
153 stream_filter_stop(rd);
154 stream_filter_stop(wr);
158 line = stream_getln(rd, NULL);
160 return (DETAILER_ERR_READ);
161 if (strcmp(line, ".") != 0)
162 return (DETAILER_ERR_PROTO);
163 error = proto_printf(wr, ".\n");
165 return (DETAILER_ERR_WRITE);
168 /* Now send fixups if needed. */
171 STAILQ_FOREACH(coll, &config->colls, co_next) {
172 if (coll->co_options & CO_SKIP)
174 error = proto_printf(wr, "COLL %s %s\n", coll->co_name,
177 return (DETAILER_ERR_WRITE);
178 if (coll->co_options & CO_COMPRESS)
179 stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL);
182 fixup = fixups_get(config->fixups);
187 if (fixup->f_coll != coll)
189 error = proto_printf(wr, "Y %s %s %s\n", fixup->f_name,
190 coll->co_tag, coll->co_date);
192 return (DETAILER_ERR_WRITE);
195 error = proto_printf(wr, ".\n");
197 return (DETAILER_ERR_WRITE);
198 if (coll->co_options & CO_COMPRESS)
199 stream_filter_stop(wr);
202 error = proto_printf(wr, ".\n");
204 return (DETAILER_ERR_WRITE);
209 detailer_coll(struct detailer *d, struct coll *coll, struct status *st)
211 struct stream *rd, *wr;
212 char *cmd, *file, *line, *msg;
217 line = stream_getln(rd, NULL);
219 return (DETAILER_ERR_READ);
220 while (strcmp(line, ".") != 0) {
221 cmd = proto_get_ascii(&line);
222 if (cmd == NULL || strlen(cmd) != 1)
223 return (DETAILER_ERR_PROTO);
227 file = proto_get_ascii(&line);
228 if (file == NULL || line != NULL)
229 return (DETAILER_ERR_PROTO);
230 error = proto_printf(wr, "D %s\n", file);
232 return (DETAILER_ERR_WRITE);
235 /* Add or update file. */
236 file = proto_get_ascii(&line);
237 if (file == NULL || line != NULL)
238 return (DETAILER_ERR_PROTO);
239 error = detailer_dofile(d, coll, st, file);
244 /* Warning from server. */
245 msg = proto_get_rest(&line);
247 return (DETAILER_ERR_PROTO);
248 lprintf(-1, "Server warning: %s\n", msg);
251 return (DETAILER_ERR_PROTO);
254 line = stream_getln(rd, NULL);
256 return (DETAILER_ERR_READ);
258 error = proto_printf(wr, ".\n");
260 return (DETAILER_ERR_WRITE);
265 detailer_dofile(struct detailer *d, struct coll *coll, struct status *st,
268 char md5[MD5_DIGEST_SIZE];
271 struct statusrec *sr;
276 path = checkoutpath(coll->co_prefix, file);
278 return (DETAILER_ERR_PROTO);
279 fa = fattr_frompath(path, FATTR_NOFOLLOW);
281 /* We don't have the file, so the only option at this
282 point is to tell the server to send it. The server
283 may figure out that the file is dead, in which case
285 error = proto_printf(wr, "C %s %s %s\n",
286 file, coll->co_tag, coll->co_date);
289 return (DETAILER_ERR_WRITE);
292 ret = status_get(st, file, 0, 0, &sr);
294 d->errmsg = status_errmsg(st);
296 return (DETAILER_ERR_MSG);
301 /* If our recorded information doesn't match the file that the
302 client has, then ignore the recorded information. */
303 if (sr != NULL && (sr->sr_type != SR_CHECKOUTLIVE ||
304 !fattr_equal(sr->sr_clientattr, fa)))
307 if (sr != NULL && strcmp(sr->sr_revdate, ".") != 0) {
308 error = proto_printf(wr, "U %s %s %s %s %s\n", file,
309 coll->co_tag, coll->co_date, sr->sr_revnum, sr->sr_revdate);
312 return (DETAILER_ERR_WRITE);
317 * We don't have complete and/or accurate recorded information
318 * about what version of the file we have. Compute the file's
319 * checksum as an aid toward identifying which version it is.
321 error = MD5_File(path, md5);
323 xasprintf(&d->errmsg,
324 "Cannot calculate checksum for \"%s\": %s", path,
326 return (DETAILER_ERR_MSG);
330 error = proto_printf(wr, "S %s %s %s %s\n", file,
331 coll->co_tag, coll->co_date, md5);
333 error = proto_printf(wr, "s %s %s %s %s %s\n", file,
334 coll->co_tag, coll->co_date, sr->sr_revnum, md5);
337 return (DETAILER_ERR_WRITE);