1 /*-
2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31
32 #include <assert.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include "config.h"
43 #include "diff.h"
44 #include "fattr.h"
45 #include "fixups.h"
46 #include "keyword.h"
47 #include "updater.h"
48 #include "misc.h"
49 #include "mux.h"
50 #include "proto.h"
51 #include "rcsfile.h"
52 #include "status.h"
53 #include "stream.h"
54
55 /* Internal error codes. */
56 #define UPDATER_ERR_PROTO (-1) /* Protocol error. */
57 #define UPDATER_ERR_MSG (-2) /* Error is in updater->errmsg. */
58 #define UPDATER_ERR_READ (-3) /* Error reading from server. */
59 #define UPDATER_ERR_DELETELIM (-4) /* File deletion limit exceeded. */
60
61 #define BUFSIZE 4096
62
63 /* Everything needed to update a file. */
64 struct file_update {
65 struct statusrec srbuf;
66 char *destpath;
67 char *temppath;
68 char *origpath;
69 char *coname; /* Points somewhere in destpath. */
70 char *wantmd5;
71 struct coll *coll;
72 struct status *st;
73 /* Those are only used for diff updating. */
74 char *author;
75 struct stream *orig;
76 struct stream *to;
77 int attic;
78 int expand;
79 };
80
81 struct updater {
82 struct config *config;
83 struct stream *rd;
84 char *errmsg;
85 int deletecount;
86 };
87
88 static struct file_update *fup_new(struct coll *, struct status *);
89 static int fup_prepare(struct file_update *, char *, int);
90 static void fup_cleanup(struct file_update *);
91 static void fup_free(struct file_update *);
92
93 static void updater_prunedirs(char *, char *);
94 static int updater_batch(struct updater *, int);
95 static int updater_docoll(struct updater *, struct file_update *, int);
96 static int updater_delete(struct updater *, struct file_update *);
97 static void updater_deletefile(const char *);
98 static int updater_checkout(struct updater *, struct file_update *, int);
99 static int updater_addfile(struct updater *, struct file_update *,
100 char *, int);
101 int updater_addelta(struct rcsfile *, struct stream *, char *);
102 static int updater_setattrs(struct updater *, struct file_update *,
103 char *, char *, char *, char *, char *, struct fattr *);
104 static int updater_setdirattrs(struct updater *, struct coll *,
105 struct file_update *, char *, char *);
106 static int updater_updatefile(struct updater *, struct file_update *fup,
107 const char *, int);
108 static int updater_updatenode(struct updater *, struct coll *,
109 struct file_update *, char *, char *);
110 static int updater_diff(struct updater *, struct file_update *);
111 static int updater_diff_batch(struct updater *, struct file_update *);
112 static int updater_diff_apply(struct updater *, struct file_update *,
113 char *);
114 static int updater_rcsedit(struct updater *, struct file_update *, char *,
115 char *);
116 int updater_append_file(struct updater *, struct file_update *,
117 off_t);
118 static int updater_rsync(struct updater *, struct file_update *, size_t);
119 static int updater_read_checkout(struct stream *, struct stream *);
120
121 static struct file_update *
fup_new(struct coll * coll,struct status * st)122 fup_new(struct coll *coll, struct status *st)
123 {
124 struct file_update *fup;
125
126 fup = xmalloc(sizeof(struct file_update));
127 memset(fup, 0, sizeof(*fup));
128 fup->coll = coll;
129 fup->st = st;
130 return (fup);
131 }
132
133 static int
fup_prepare(struct file_update * fup,char * name,int attic)134 fup_prepare(struct file_update *fup, char *name, int attic)
135 {
136 struct coll *coll;
137
138 coll = fup->coll;
139 fup->attic = 0;
140 fup->origpath = NULL;
141
142 if (coll->co_options & CO_CHECKOUTMODE)
143 fup->destpath = checkoutpath(coll->co_prefix, name);
144 else {
145 fup->destpath = cvspath(coll->co_prefix, name, attic);
146 fup->origpath = atticpath(coll->co_prefix, name);
147 /* If they're equal, we don't need special care. */
148 if (fup->origpath != NULL &&
149 strcmp(fup->origpath, fup->destpath) == 0) {
150 free(fup->origpath);
151 fup->origpath = NULL;
152 }
153 fup->attic = attic;
154 }
155 if (fup->destpath == NULL)
156 return (-1);
157 fup->coname = fup->destpath + coll->co_prefixlen + 1;
158 return (0);
159 }
160
161 /* Called after each file update to reinit the structure. */
162 static void
fup_cleanup(struct file_update * fup)163 fup_cleanup(struct file_update *fup)
164 {
165 struct statusrec *sr;
166
167 sr = &fup->srbuf;
168
169 if (fup->destpath != NULL) {
170 free(fup->destpath);
171 fup->destpath = NULL;
172 }
173 if (fup->temppath != NULL) {
174 free(fup->temppath);
175 fup->temppath = NULL;
176 }
177 if (fup->origpath != NULL) {
178 free(fup->origpath);
179 fup->origpath = NULL;
180 }
181 fup->coname = NULL;
182 if (fup->author != NULL) {
183 free(fup->author);
184 fup->author = NULL;
185 }
186 fup->expand = 0;
187 if (fup->wantmd5 != NULL) {
188 free(fup->wantmd5);
189 fup->wantmd5 = NULL;
190 }
191 if (fup->orig != NULL) {
192 stream_close(fup->orig);
193 fup->orig = NULL;
194 }
195 if (fup->to != NULL) {
196 stream_close(fup->to);
197 fup->to = NULL;
198 }
199 if (sr->sr_file != NULL)
200 free(sr->sr_file);
201 if (sr->sr_tag != NULL)
202 free(sr->sr_tag);
203 if (sr->sr_date != NULL)
204 free(sr->sr_date);
205 if (sr->sr_revnum != NULL)
206 free(sr->sr_revnum);
207 if (sr->sr_revdate != NULL)
208 free(sr->sr_revdate);
209 fattr_free(sr->sr_clientattr);
210 fattr_free(sr->sr_serverattr);
211 memset(sr, 0, sizeof(*sr));
212 }
213
214 static void
fup_free(struct file_update * fup)215 fup_free(struct file_update *fup)
216 {
217
218 fup_cleanup(fup);
219 free(fup);
220 }
221
222 void *
updater(void * arg)223 updater(void *arg)
224 {
225 struct thread_args *args;
226 struct updater upbuf, *up;
227 int error;
228
229 args = arg;
230
231 up = &upbuf;
232 up->config = args->config;
233 up->rd = args->rd;
234 up->errmsg = NULL;
235 up->deletecount = 0;
236
237 error = updater_batch(up, 0);
238
239 /*
240 * Make sure to close the fixups even in case of an error,
241 * so that the detailer thread doesn't block indefinitely.
242 */
243 fixups_close(up->config->fixups);
244 if (!error)
245 error = updater_batch(up, 1);
246 switch (error) {
247 case UPDATER_ERR_PROTO:
248 xasprintf(&args->errmsg, "Updater failed: Protocol error");
249 args->status = STATUS_FAILURE;
250 break;
251 case UPDATER_ERR_MSG:
252 xasprintf(&args->errmsg, "Updater failed: %s", up->errmsg);
253 free(up->errmsg);
254 args->status = STATUS_FAILURE;
255 break;
256 case UPDATER_ERR_READ:
257 if (stream_eof(up->rd)) {
258 xasprintf(&args->errmsg, "Updater failed: "
259 "Premature EOF from server");
260 } else {
261 xasprintf(&args->errmsg, "Updater failed: "
262 "Network read failure: %s", strerror(errno));
263 }
264 args->status = STATUS_TRANSIENTFAILURE;
265 break;
266 case UPDATER_ERR_DELETELIM:
267 xasprintf(&args->errmsg, "Updater failed: "
268 "File deletion limit exceeded");
269 args->status = STATUS_FAILURE;
270 break;
271 default:
272 assert(error == 0);
273 args->status = STATUS_SUCCESS;
274 };
275 return (NULL);
276 }
277
278 static int
updater_batch(struct updater * up,int isfixups)279 updater_batch(struct updater *up, int isfixups)
280 {
281 struct stream *rd;
282 struct coll *coll;
283 struct status *st;
284 struct file_update *fup;
285 char *line, *cmd, *errmsg, *collname, *release;
286 int error;
287
288 rd = up->rd;
289 STAILQ_FOREACH(coll, &up->config->colls, co_next) {
290 if (coll->co_options & CO_SKIP)
291 continue;
292 umask(coll->co_umask);
293 line = stream_getln(rd, NULL);
294 if (line == NULL)
295 return (UPDATER_ERR_READ);
296 cmd = proto_get_ascii(&line);
297 collname = proto_get_ascii(&line);
298 release = proto_get_ascii(&line);
299 if (release == NULL || line != NULL)
300 return (UPDATER_ERR_PROTO);
301 if (strcmp(cmd, "COLL") != 0 ||
302 strcmp(collname, coll->co_name) != 0 ||
303 strcmp(release, coll->co_release) != 0)
304 return (UPDATER_ERR_PROTO);
305
306 if (!isfixups)
307 lprintf(1, "Updating collection %s/%s\n", coll->co_name,
308 coll->co_release);
309
310 if (coll->co_options & CO_COMPRESS)
311 stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
312
313 st = status_open(coll, coll->co_scantime, &errmsg);
314 if (st == NULL) {
315 up->errmsg = errmsg;
316 return (UPDATER_ERR_MSG);
317 }
318 fup = fup_new(coll, st);
319 error = updater_docoll(up, fup, isfixups);
320 status_close(st, &errmsg);
321 fup_free(fup);
322 if (errmsg != NULL) {
323 /* Discard previous error. */
324 if (up->errmsg != NULL)
325 free(up->errmsg);
326 up->errmsg = errmsg;
327 return (UPDATER_ERR_MSG);
328 }
329 if (error)
330 return (error);
331
332 if (coll->co_options & CO_COMPRESS)
333 stream_filter_stop(rd);
334 }
335 line = stream_getln(rd, NULL);
336 if (line == NULL)
337 return (UPDATER_ERR_READ);
338 if (strcmp(line, ".") != 0)
339 return (UPDATER_ERR_PROTO);
340 return (0);
341 }
342
343 static int
updater_docoll(struct updater * up,struct file_update * fup,int isfixups)344 updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
345 {
346 struct stream *rd;
347 struct coll *coll;
348 struct statusrec srbuf, *sr;
349 struct fattr *rcsattr, *tmp;
350 char *attr, *cmd, *blocksize, *line, *msg;
351 char *name, *tag, *date, *revdate;
352 char *expand, *wantmd5, *revnum;
353 char *optstr, *rcsopt, *pos;
354 time_t t;
355 off_t position;
356 int attic, error, needfixupmsg;
357
358 error = 0;
359 rd = up->rd;
360 coll = fup->coll;
361 needfixupmsg = isfixups;
362 while ((line = stream_getln(rd, NULL)) != NULL) {
363 if (strcmp(line, ".") == 0)
364 break;
365 memset(&srbuf, 0, sizeof(srbuf));
366 if (needfixupmsg) {
367 lprintf(1, "Applying fixups for collection %s/%s\n",
368 coll->co_name, coll->co_release);
369 needfixupmsg = 0;
370 }
371 cmd = proto_get_ascii(&line);
372 if (cmd == NULL || strlen(cmd) != 1)
373 return (UPDATER_ERR_PROTO);
374 switch (cmd[0]) {
375 case 'T':
376 /* Update recorded information for checked-out file. */
377 name = proto_get_ascii(&line);
378 tag = proto_get_ascii(&line);
379 date = proto_get_ascii(&line);
380 revnum = proto_get_ascii(&line);
381 revdate = proto_get_ascii(&line);
382 attr = proto_get_ascii(&line);
383 if (attr == NULL || line != NULL)
384 return (UPDATER_ERR_PROTO);
385
386 rcsattr = fattr_decode(attr);
387 if (rcsattr == NULL)
388 return (UPDATER_ERR_PROTO);
389
390 error = fup_prepare(fup, name, 0);
391 if (error)
392 return (UPDATER_ERR_PROTO);
393 error = updater_setattrs(up, fup, name, tag, date,
394 revnum, revdate, rcsattr);
395 fattr_free(rcsattr);
396 if (error)
397 return (error);
398 break;
399 case 'c':
400 /* Checkout dead file. */
401 name = proto_get_ascii(&line);
402 tag = proto_get_ascii(&line);
403 date = proto_get_ascii(&line);
404 attr = proto_get_ascii(&line);
405 if (attr == NULL || line != NULL)
406 return (UPDATER_ERR_PROTO);
407
408 error = fup_prepare(fup, name, 0);
409 if (error)
410 return (UPDATER_ERR_PROTO);
411 /* Theoritically, the file does not exist on the client.
412 Just to make sure, we'll delete it here, if it
413 exists. */
414 if (access(fup->destpath, F_OK) == 0) {
415 error = updater_delete(up, fup);
416 if (error)
417 return (error);
418 }
419
420 sr = &srbuf;
421 sr->sr_type = SR_CHECKOUTDEAD;
422 sr->sr_file = name;
423 sr->sr_tag = tag;
424 sr->sr_date = date;
425 sr->sr_serverattr = fattr_decode(attr);
426 if (sr->sr_serverattr == NULL)
427 return (UPDATER_ERR_PROTO);
428
429 error = status_put(fup->st, sr);
430 fattr_free(sr->sr_serverattr);
431 if (error) {
432 up->errmsg = status_errmsg(fup->st);
433 return (UPDATER_ERR_MSG);
434 }
435 break;
436 case 'U':
437 /* Update live checked-out file. */
438 name = proto_get_ascii(&line);
439 tag = proto_get_ascii(&line);
440 date = proto_get_ascii(&line);
441 proto_get_ascii(&line); /* XXX - oldRevNum */
442 proto_get_ascii(&line); /* XXX - fromAttic */
443 proto_get_ascii(&line); /* XXX - logLines */
444 expand = proto_get_ascii(&line);
445 attr = proto_get_ascii(&line);
446 wantmd5 = proto_get_ascii(&line);
447 if (wantmd5 == NULL || line != NULL)
448 return (UPDATER_ERR_PROTO);
449
450 sr = &fup->srbuf;
451 sr->sr_type = SR_CHECKOUTLIVE;
452 sr->sr_file = xstrdup(name);
453 sr->sr_date = xstrdup(date);
454 sr->sr_tag = xstrdup(tag);
455 sr->sr_serverattr = fattr_decode(attr);
456 if (sr->sr_serverattr == NULL)
457 return (UPDATER_ERR_PROTO);
458
459 fup->expand = keyword_decode_expand(expand);
460 if (fup->expand == -1)
461 return (UPDATER_ERR_PROTO);
462 error = fup_prepare(fup, name, 0);
463 if (error)
464 return (UPDATER_ERR_PROTO);
465
466 fup->wantmd5 = xstrdup(wantmd5);
467 fup->temppath = tempname(fup->destpath);
468 error = updater_diff(up, fup);
469 if (error)
470 return (error);
471 break;
472 case 'u':
473 /* Update dead checked-out file. */
474 name = proto_get_ascii(&line);
475 tag = proto_get_ascii(&line);
476 date = proto_get_ascii(&line);
477 attr = proto_get_ascii(&line);
478 if (attr == NULL || line != NULL)
479 return (UPDATER_ERR_PROTO);
480
481 error = fup_prepare(fup, name, 0);
482 if (error)
483 return (UPDATER_ERR_PROTO);
484 error = updater_delete(up, fup);
485 if (error)
486 return (error);
487 sr = &srbuf;
488 sr->sr_type = SR_CHECKOUTDEAD;
489 sr->sr_file = name;
490 sr->sr_tag = tag;
491 sr->sr_date = date;
492 sr->sr_serverattr = fattr_decode(attr);
493 if (sr->sr_serverattr == NULL)
494 return (UPDATER_ERR_PROTO);
495 error = status_put(fup->st, sr);
496 fattr_free(sr->sr_serverattr);
497 if (error) {
498 up->errmsg = status_errmsg(fup->st);
499 return (UPDATER_ERR_MSG);
500 }
501 break;
502 case 'C':
503 case 'Y':
504 /* Checkout file. */
505 name = proto_get_ascii(&line);
506 tag = proto_get_ascii(&line);
507 date = proto_get_ascii(&line);
508 revnum = proto_get_ascii(&line);
509 revdate = proto_get_ascii(&line);
510 attr = proto_get_ascii(&line);
511 if (attr == NULL || line != NULL)
512 return (UPDATER_ERR_PROTO);
513
514 sr = &fup->srbuf;
515 sr->sr_type = SR_CHECKOUTLIVE;
516 sr->sr_file = xstrdup(name);
517 sr->sr_tag = xstrdup(tag);
518 sr->sr_date = xstrdup(date);
519 sr->sr_revnum = xstrdup(revnum);
520 sr->sr_revdate = xstrdup(revdate);
521 sr->sr_serverattr = fattr_decode(attr);
522 if (sr->sr_serverattr == NULL)
523 return (UPDATER_ERR_PROTO);
524
525 t = rcsdatetotime(revdate);
526 if (t == -1)
527 return (UPDATER_ERR_PROTO);
528
529 sr->sr_clientattr = fattr_new(FT_FILE, t);
530 tmp = fattr_forcheckout(sr->sr_serverattr,
531 coll->co_umask);
532 fattr_override(sr->sr_clientattr, tmp, FA_MASK);
533 fattr_free(tmp);
534 fattr_mergedefault(sr->sr_clientattr);
535 error = fup_prepare(fup, name, 0);
536 if (error)
537 return (UPDATER_ERR_PROTO);
538 fup->temppath = tempname(fup->destpath);
539 if (*cmd == 'Y')
540 error = updater_checkout(up, fup, 1);
541 else
542 error = updater_checkout(up, fup, 0);
543 if (error)
544 return (error);
545 break;
546 case 'D':
547 /* Delete file. */
548 name = proto_get_ascii(&line);
549 if (name == NULL || line != NULL)
550 return (UPDATER_ERR_PROTO);
551 error = fup_prepare(fup, name, 0);
552 if (error)
553 return (UPDATER_ERR_PROTO);
554 error = updater_delete(up, fup);
555 if (error)
556 return (error);
557 error = status_delete(fup->st, name, 0);
558 if (error) {
559 up->errmsg = status_errmsg(fup->st);
560 return (UPDATER_ERR_MSG);
561 }
562 break;
563 case 'A':
564 case 'a':
565 case 'R':
566 name = proto_get_ascii(&line);
567 attr = proto_get_ascii(&line);
568 if (name == NULL || attr == NULL || line != NULL)
569 return (UPDATER_ERR_PROTO);
570 attic = (cmd[0] == 'a');
571 error = fup_prepare(fup, name, attic);
572 if (error)
573 return (UPDATER_ERR_PROTO);
574
575 fup->temppath = tempname(fup->destpath);
576 sr = &fup->srbuf;
577 sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
578 sr->sr_file = xstrdup(name);
579 sr->sr_serverattr = fattr_decode(attr);
580 if (sr->sr_serverattr == NULL)
581 return (UPDATER_ERR_PROTO);
582 if (attic)
583 lprintf(1, " Create %s -> Attic\n", name);
584 else
585 lprintf(1, " Create %s\n", name);
586 error = updater_addfile(up, fup, attr, 0);
587 if (error)
588 return (error);
589 break;
590 case 'r':
591 name = proto_get_ascii(&line);
592 attr = proto_get_ascii(&line);
593 blocksize = proto_get_ascii(&line);
594 wantmd5 = proto_get_ascii(&line);
595 if (name == NULL || attr == NULL || blocksize == NULL ||
596 wantmd5 == NULL) {
597 return (UPDATER_ERR_PROTO);
598 }
599 error = fup_prepare(fup, name, 0);
600 if (error)
601 return (UPDATER_ERR_PROTO);
602 fup->wantmd5 = xstrdup(wantmd5);
603 fup->temppath = tempname(fup->destpath);
604 sr = &fup->srbuf;
605 sr->sr_file = xstrdup(name);
606 sr->sr_serverattr = fattr_decode(attr);
607 sr->sr_type = SR_FILELIVE;
608 if (sr->sr_serverattr == NULL)
609 return (UPDATER_ERR_PROTO);
610 error = updater_rsync(up, fup, strtol(blocksize, NULL,
611 10));
612 if (error)
613 return (error);
614 break;
615 case 'I':
616 /*
617 * Create directory and add DirDown entry in status
618 * file.
619 */
620 name = proto_get_ascii(&line);
621 if (name == NULL || line != NULL)
622 return (UPDATER_ERR_PROTO);
623 error = fup_prepare(fup, name, 0);
624 if (error)
625 return (UPDATER_ERR_PROTO);
626 sr = &fup->srbuf;
627 sr->sr_type = SR_DIRDOWN;
628 sr->sr_file = xstrdup(name);
629 sr->sr_serverattr = NULL;
630 sr->sr_clientattr = fattr_new(FT_DIRECTORY, -1);
631 fattr_mergedefault(sr->sr_clientattr);
632
633 error = mkdirhier(fup->destpath, coll->co_umask);
634 if (error)
635 return (UPDATER_ERR_PROTO);
636 if (access(fup->destpath, F_OK) != 0) {
637 lprintf(1, " Mkdir %s\n", name);
638 error = fattr_makenode(sr->sr_clientattr,
639 fup->destpath);
640 if (error)
641 return (UPDATER_ERR_PROTO);
642 }
643 error = status_put(fup->st, sr);
644 if (error) {
645 up->errmsg = status_errmsg(fup->st);
646 return (UPDATER_ERR_MSG);
647 }
648 break;
649 case 'i':
650 /* Remove DirDown entry in status file. */
651 name = proto_get_ascii(&line);
652 if (name == NULL || line != NULL)
653 return (UPDATER_ERR_PROTO);
654 error = fup_prepare(fup, name, 0);
655 if (error)
656 return (UPDATER_ERR_PROTO);
657 error = status_delete(fup->st, name, 0);
658 if (error) {
659 up->errmsg = status_errmsg(fup->st);
660 return (UPDATER_ERR_MSG);
661 }
662 break;
663 case 'J':
664 /*
665 * Set attributes of directory and update DirUp entry in
666 * status file.
667 */
668 name = proto_get_ascii(&line);
669 if (name == NULL)
670 return (UPDATER_ERR_PROTO);
671 attr = proto_get_ascii(&line);
672 if (attr == NULL || line != NULL)
673 return (UPDATER_ERR_PROTO);
674 error = fup_prepare(fup, name, 0);
675 if (error)
676 return (UPDATER_ERR_PROTO);
677 error = updater_setdirattrs(up, coll, fup, name, attr);
678 if (error)
679 return (error);
680 break;
681 case 'j':
682 /*
683 * Remove directory and delete its DirUp entry in status
684 * file.
685 */
686 name = proto_get_ascii(&line);
687 if (name == NULL || line != NULL)
688 return (UPDATER_ERR_PROTO);
689 error = fup_prepare(fup, name, 0);
690 if (error)
691 return (UPDATER_ERR_PROTO);
692 lprintf(1, " Rmdir %s\n", name);
693 updater_deletefile(fup->destpath);
694 error = status_delete(fup->st, name, 0);
695 if (error) {
696 up->errmsg = status_errmsg(fup->st);
697 return (UPDATER_ERR_MSG);
698 }
699 break;
700 case 'L':
701 case 'l':
702 name = proto_get_ascii(&line);
703 if (name == NULL)
704 return (UPDATER_ERR_PROTO);
705 attr = proto_get_ascii(&line);
706 if (attr == NULL || line != NULL)
707 return (UPDATER_ERR_PROTO);
708 attic = (cmd[0] == 'l');
709 sr = &fup->srbuf;
710 sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
711 sr->sr_file = xstrdup(name);
712 sr->sr_serverattr = fattr_decode(attr);
713 sr->sr_clientattr = fattr_decode(attr);
714 if (sr->sr_serverattr == NULL ||
715 sr->sr_clientattr == NULL)
716 return (UPDATER_ERR_PROTO);
717
718 /* Save space. Described in detail in updatefile. */
719 if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT)
720 || fattr_getlinkcount(sr->sr_clientattr) <= 1)
721 fattr_maskout(sr->sr_clientattr,
722 FA_DEV | FA_INODE);
723 fattr_maskout(sr->sr_clientattr, FA_FLAGS);
724 error = status_put(fup->st, sr);
725 if (error) {
726 up->errmsg = status_errmsg(fup->st);
727 return (UPDATER_ERR_MSG);
728 }
729 break;
730 case 'N':
731 case 'n':
732 name = proto_get_ascii(&line);
733 attr = proto_get_ascii(&line);
734 if (name == NULL || attr == NULL || line != NULL)
735 return (UPDATER_ERR_PROTO);
736 attic = (cmd[0] == 'n');
737 error = fup_prepare(fup, name, attic);
738 if (error)
739 return (UPDATER_ERR_PROTO);
740 sr = &fup->srbuf;
741 sr->sr_type = (attic ? SR_FILEDEAD : SR_FILELIVE);
742 sr->sr_file = xstrdup(name);
743 sr->sr_serverattr = fattr_decode(attr);
744 sr->sr_clientattr = fattr_new(FT_SYMLINK, -1);
745 fattr_mergedefault(sr->sr_clientattr);
746 fattr_maskout(sr->sr_clientattr, FA_FLAGS);
747 error = updater_updatenode(up, coll, fup, name, attr);
748 if (error)
749 return (error);
750 break;
751 case 'V':
752 case 'v':
753 name = proto_get_ascii(&line);
754 attr = proto_get_ascii(&line);
755 optstr = proto_get_ascii(&line);
756 wantmd5 = proto_get_ascii(&line);
757 rcsopt = NULL; /* XXX: Not supported. */
758 if (attr == NULL || line != NULL || wantmd5 == NULL)
759 return (UPDATER_ERR_PROTO);
760 attic = (cmd[0] == 'v');
761 error = fup_prepare(fup, name, attic);
762 if (error)
763 return (UPDATER_ERR_PROTO);
764 fup->temppath = tempname(fup->destpath);
765 fup->wantmd5 = xstrdup(wantmd5);
766 sr = &fup->srbuf;
767 sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
768 sr->sr_file = xstrdup(name);
769 sr->sr_serverattr = fattr_decode(attr);
770 if (sr->sr_serverattr == NULL)
771 return (UPDATER_ERR_PROTO);
772
773 error = updater_rcsedit(up, fup, name, rcsopt);
774 if (error)
775 return (error);
776 break;
777 case 'X':
778 case 'x':
779 name = proto_get_ascii(&line);
780 attr = proto_get_ascii(&line);
781 if (name == NULL || attr == NULL || line != NULL)
782 return (UPDATER_ERR_PROTO);
783 attic = (cmd[0] == 'x');
784 error = fup_prepare(fup, name, attic);
785 if (error)
786 return (UPDATER_ERR_PROTO);
787
788 fup->temppath = tempname(fup->destpath);
789 sr = &fup->srbuf;
790 sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
791 sr->sr_file = xstrdup(name);
792 sr->sr_serverattr = fattr_decode(attr);
793 if (sr->sr_serverattr == NULL)
794 return (UPDATER_ERR_PROTO);
795 lprintf(1, " Fixup %s\n", name);
796 error = updater_addfile(up, fup, attr, 1);
797 if (error)
798 return (error);
799 break;
800 case 'Z':
801 name = proto_get_ascii(&line);
802 attr = proto_get_ascii(&line);
803 pos = proto_get_ascii(&line);
804 if (name == NULL || attr == NULL || pos == NULL ||
805 line != NULL)
806 return (UPDATER_ERR_PROTO);
807 error = fup_prepare(fup, name, 0);
808 fup->temppath = tempname(fup->destpath);
809 sr = &fup->srbuf;
810 sr->sr_type = SR_FILELIVE;
811 sr->sr_file = xstrdup(name);
812 sr->sr_serverattr = fattr_decode(attr);
813 if (sr->sr_serverattr == NULL)
814 return (UPDATER_ERR_PROTO);
815 position = strtol(pos, NULL, 10);
816 lprintf(1, " Append to %s\n", name);
817 error = updater_append_file(up, fup, position);
818 if (error)
819 return (error);
820 break;
821 case '!':
822 /* Warning from server. */
823 msg = proto_get_rest(&line);
824 if (msg == NULL)
825 return (UPDATER_ERR_PROTO);
826 lprintf(-1, "Server warning: %s\n", msg);
827 break;
828 default:
829 return (UPDATER_ERR_PROTO);
830 }
831 fup_cleanup(fup);
832 }
833 if (line == NULL)
834 return (UPDATER_ERR_READ);
835 return (0);
836 }
837
838 /* Delete file. */
839 static int
updater_delete(struct updater * up,struct file_update * fup)840 updater_delete(struct updater *up, struct file_update *fup)
841 {
842 struct config *config;
843 struct coll *coll;
844
845 config = up->config;
846 coll = fup->coll;
847 if (coll->co_options & CO_DELETE) {
848 lprintf(1, " Delete %s\n", fup->coname);
849 if (config->deletelim >= 0 &&
850 up->deletecount >= config->deletelim)
851 return (UPDATER_ERR_DELETELIM);
852 up->deletecount++;
853 updater_deletefile(fup->destpath);
854 if (coll->co_options & CO_CHECKOUTMODE)
855 updater_prunedirs(coll->co_prefix, fup->destpath);
856 } else {
857 lprintf(1," NoDelete %s\n", fup->coname);
858 }
859 return (0);
860 }
861
862 static void
updater_deletefile(const char * path)863 updater_deletefile(const char *path)
864 {
865 int error;
866
867 error = fattr_delete(path);
868 if (error && errno != ENOENT) {
869 lprintf(-1, "Cannot delete \"%s\": %s\n",
870 path, strerror(errno));
871 }
872 }
873
874 static int
updater_setattrs(struct updater * up,struct file_update * fup,char * name,char * tag,char * date,char * revnum,char * revdate,struct fattr * rcsattr)875 updater_setattrs(struct updater *up, struct file_update *fup, char *name,
876 char *tag, char *date, char *revnum, char *revdate, struct fattr *rcsattr)
877 {
878 struct statusrec sr;
879 struct status *st;
880 struct coll *coll;
881 struct fattr *fileattr, *fa;
882 char *path;
883 int error, rv;
884
885 coll = fup->coll;
886 st = fup->st;
887 path = fup->destpath;
888
889 fileattr = fattr_frompath(path, FATTR_NOFOLLOW);
890 if (fileattr == NULL) {
891 /* The file has vanished. */
892 error = status_delete(st, name, 0);
893 if (error) {
894 up->errmsg = status_errmsg(st);
895 return (UPDATER_ERR_MSG);
896 }
897 return (0);
898 }
899 fa = fattr_forcheckout(rcsattr, coll->co_umask);
900 fattr_override(fileattr, fa, FA_MASK);
901 fattr_free(fa);
902
903 rv = fattr_install(fileattr, path, NULL);
904 if (rv == -1) {
905 lprintf(1, " SetAttrs %s\n", fup->coname);
906 fattr_free(fileattr);
907 xasprintf(&up->errmsg, "Cannot set attributes for \"%s\": %s",
908 path, strerror(errno));
909 return (UPDATER_ERR_MSG);
910 }
911 if (rv == 1) {
912 lprintf(1, " SetAttrs %s\n", fup->coname);
913 fattr_free(fileattr);
914 fileattr = fattr_frompath(path, FATTR_NOFOLLOW);
915 if (fileattr == NULL) {
916 /* We're being very unlucky. */
917 error = status_delete(st, name, 0);
918 if (error) {
919 up->errmsg = status_errmsg(st);
920 return (UPDATER_ERR_MSG);
921 }
922 return (0);
923 }
924 }
925
926 fattr_maskout(fileattr, FA_COIGNORE);
927
928 sr.sr_type = SR_CHECKOUTLIVE;
929 sr.sr_file = name;
930 sr.sr_tag = tag;
931 sr.sr_date = date;
932 sr.sr_revnum = revnum;
933 sr.sr_revdate = revdate;
934 sr.sr_clientattr = fileattr;
935 sr.sr_serverattr = rcsattr;
936
937 error = status_put(st, &sr);
938 fattr_free(fileattr);
939 if (error) {
940 up->errmsg = status_errmsg(st);
941 return (UPDATER_ERR_MSG);
942 }
943 return (0);
944 }
945
946 static int
updater_updatefile(struct updater * up,struct file_update * fup,const char * md5,int isfixup)947 updater_updatefile(struct updater *up, struct file_update *fup,
948 const char *md5, int isfixup)
949 {
950 struct coll *coll;
951 struct status *st;
952 struct statusrec *sr;
953 struct fattr *fileattr;
954 int error, rv;
955
956 coll = fup->coll;
957 sr = &fup->srbuf;
958 st = fup->st;
959
960 if (strcmp(fup->wantmd5, md5) != 0) {
961 if (isfixup) {
962 lprintf(-1, "%s: Checksum mismatch -- "
963 "file not updated\n", fup->destpath);
964 } else {
965 lprintf(-1, "%s: Checksum mismatch -- "
966 "will transfer entire file\n", fup->destpath);
967 fixups_put(up->config->fixups, fup->coll, sr->sr_file);
968 }
969 if (coll->co_options & CO_KEEPBADFILES)
970 lprintf(-1, "Bad version saved in %s\n", fup->temppath);
971 else
972 updater_deletefile(fup->temppath);
973 return (0);
974 }
975
976 fattr_umask(sr->sr_clientattr, coll->co_umask);
977 rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath);
978 if (rv == -1) {
979 xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
980 fup->temppath, fup->destpath, strerror(errno));
981 return (UPDATER_ERR_MSG);
982 }
983
984 /* XXX Executes */
985 /*
986 * We weren't necessarily able to set all the file attributes to the
987 * desired values, and any executes may have altered the attributes.
988 * To make sure we record the actual attribute values, we fetch
989 * them from the file.
990 *
991 * However, we preserve the link count as received from the
992 * server. This is important for preserving hard links in mirror
993 * mode.
994 */
995 fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
996 if (fileattr == NULL) {
997 xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
998 strerror(errno));
999 return (UPDATER_ERR_MSG);
1000 }
1001 fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
1002 fattr_free(sr->sr_clientattr);
1003 sr->sr_clientattr = fileattr;
1004
1005 /*
1006 * To save space, don't write out the device and inode unless
1007 * the link count is greater than 1. These attributes are used
1008 * only for detecting hard links. If the link count is 1 then we
1009 * know there aren't any hard links.
1010 */
1011 if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
1012 fattr_getlinkcount(sr->sr_clientattr) <= 1)
1013 fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
1014
1015 if (coll->co_options & CO_CHECKOUTMODE)
1016 fattr_maskout(sr->sr_clientattr, FA_COIGNORE);
1017
1018 error = status_put(st, sr);
1019 if (error) {
1020 up->errmsg = status_errmsg(st);
1021 return (UPDATER_ERR_MSG);
1022 }
1023 return (0);
1024 }
1025
1026 /*
1027 * Update attributes of a directory.
1028 */
1029 static int
updater_setdirattrs(struct updater * up,struct coll * coll,struct file_update * fup,char * name,char * attr)1030 updater_setdirattrs(struct updater *up, struct coll *coll,
1031 struct file_update *fup, char *name, char *attr)
1032 {
1033 struct statusrec *sr;
1034 struct fattr *fa;
1035 int error, rv;
1036
1037 sr = &fup->srbuf;
1038 sr->sr_type = SR_DIRUP;
1039 sr->sr_file = xstrdup(name);
1040 sr->sr_clientattr = fattr_decode(attr);
1041 sr->sr_serverattr = fattr_decode(attr);
1042 if (sr->sr_clientattr == NULL || sr->sr_serverattr == NULL)
1043 return (UPDATER_ERR_PROTO);
1044 fattr_mergedefault(sr->sr_clientattr);
1045 fattr_umask(sr->sr_clientattr, coll->co_umask);
1046 rv = fattr_install(sr->sr_clientattr, fup->destpath, NULL);
1047 lprintf(1, " SetAttrs %s\n", name);
1048 if (rv == -1) {
1049 xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
1050 fup->temppath, fup->destpath, strerror(errno));
1051 return (UPDATER_ERR_MSG);
1052 }
1053 /*
1054 * Now, make sure they were set and record what was set in the status
1055 * file.
1056 */
1057 fa = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
1058 if (fa == NULL) {
1059 xasprintf(&up->errmsg, "Cannot open \%s\": %s", fup->destpath,
1060 strerror(errno));
1061 return (UPDATER_ERR_MSG);
1062 }
1063 fattr_free(sr->sr_clientattr);
1064 fattr_maskout(fa, FA_FLAGS);
1065 sr->sr_clientattr = fa;
1066 error = status_put(fup->st, sr);
1067 if (error) {
1068 up->errmsg = status_errmsg(fup->st);
1069 return (UPDATER_ERR_MSG);
1070 }
1071
1072 return (0);
1073 }
1074
1075 static int
updater_diff(struct updater * up,struct file_update * fup)1076 updater_diff(struct updater *up, struct file_update *fup)
1077 {
1078 char md5[MD5_DIGEST_SIZE];
1079 struct coll *coll;
1080 struct statusrec *sr;
1081 struct fattr *fa, *tmp;
1082 char *author, *path, *revnum, *revdate;
1083 char *line, *cmd;
1084 int error;
1085
1086 coll = fup->coll;
1087 sr = &fup->srbuf;
1088 path = fup->destpath;
1089
1090 lprintf(1, " Edit %s\n", fup->coname);
1091 while ((line = stream_getln(up->rd, NULL)) != NULL) {
1092 if (strcmp(line, ".") == 0)
1093 break;
1094 cmd = proto_get_ascii(&line);
1095 if (cmd == NULL || strcmp(cmd, "D") != 0)
1096 return (UPDATER_ERR_PROTO);
1097 revnum = proto_get_ascii(&line);
1098 proto_get_ascii(&line); /* XXX - diffbase */
1099 revdate = proto_get_ascii(&line);
1100 author = proto_get_ascii(&line);
1101 if (author == NULL || line != NULL)
1102 return (UPDATER_ERR_PROTO);
1103 if (sr->sr_revnum != NULL)
1104 free(sr->sr_revnum);
1105 if (sr->sr_revdate != NULL)
1106 free(sr->sr_revdate);
1107 if (fup->author != NULL)
1108 free(fup->author);
1109 sr->sr_revnum = xstrdup(revnum);
1110 sr->sr_revdate = xstrdup(revdate);
1111 fup->author = xstrdup(author);
1112 if (fup->orig == NULL) {
1113 /* First patch, the "origin" file is the one we have. */
1114 fup->orig = stream_open_file(path, O_RDONLY);
1115 if (fup->orig == NULL) {
1116 xasprintf(&up->errmsg, "%s: Cannot open: %s",
1117 path, strerror(errno));
1118 return (UPDATER_ERR_MSG);
1119 }
1120 } else {
1121 /* Subsequent patches. */
1122 stream_close(fup->orig);
1123 fup->orig = fup->to;
1124 stream_rewind(fup->orig);
1125 unlink(fup->temppath);
1126 free(fup->temppath);
1127 fup->temppath = tempname(path);
1128 }
1129 fup->to = stream_open_file(fup->temppath,
1130 O_RDWR | O_CREAT | O_TRUNC, 0600);
1131 if (fup->to == NULL) {
1132 xasprintf(&up->errmsg, "%s: Cannot open: %s",
1133 fup->temppath, strerror(errno));
1134 return (UPDATER_ERR_MSG);
1135 }
1136 lprintf(2, " Add delta %s %s %s\n", sr->sr_revnum,
1137 sr->sr_revdate, fup->author);
1138 error = updater_diff_batch(up, fup);
1139 if (error)
1140 return (error);
1141 }
1142 if (line == NULL)
1143 return (UPDATER_ERR_READ);
1144
1145 fa = fattr_frompath(path, FATTR_FOLLOW);
1146 tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask);
1147 fattr_override(fa, tmp, FA_MASK);
1148 fattr_free(tmp);
1149 fattr_maskout(fa, FA_MODTIME);
1150 sr->sr_clientattr = fa;
1151
1152 if (MD5_File(fup->temppath, md5) == -1) {
1153 xasprintf(&up->errmsg,
1154 "Cannot calculate checksum for \"%s\": %s",
1155 path, strerror(errno));
1156 return (UPDATER_ERR_MSG);
1157 }
1158 error = updater_updatefile(up, fup, md5, 0);
1159 return (error);
1160 }
1161
1162 /*
1163 * Edit a file and add delta.
1164 */
1165 static int
updater_diff_batch(struct updater * up,struct file_update * fup)1166 updater_diff_batch(struct updater *up, struct file_update *fup)
1167 {
1168 struct stream *rd;
1169 char *cmd, *line, *state, *tok;
1170 int error;
1171
1172 state = NULL;
1173 rd = up->rd;
1174 while ((line = stream_getln(rd, NULL)) != NULL) {
1175 if (strcmp(line, ".") == 0)
1176 break;
1177 cmd = proto_get_ascii(&line);
1178 if (cmd == NULL || strlen(cmd) != 1) {
1179 error = UPDATER_ERR_PROTO;
1180 goto bad;
1181 }
1182 switch (cmd[0]) {
1183 case 'L':
1184 line = stream_getln(rd, NULL);
1185 /* XXX - We're just eating the log for now. */
1186 while (line != NULL && strcmp(line, ".") != 0 &&
1187 strcmp(line, ".+") != 0)
1188 line = stream_getln(rd, NULL);
1189 if (line == NULL) {
1190 error = UPDATER_ERR_READ;
1191 goto bad;
1192 }
1193 break;
1194 case 'S':
1195 tok = proto_get_ascii(&line);
1196 if (tok == NULL || line != NULL) {
1197 error = UPDATER_ERR_PROTO;
1198 goto bad;
1199 }
1200 if (state != NULL)
1201 free(state);
1202 state = xstrdup(tok);
1203 break;
1204 case 'T':
1205 error = updater_diff_apply(up, fup, state);
1206 if (error)
1207 goto bad;
1208 break;
1209 default:
1210 error = UPDATER_ERR_PROTO;
1211 goto bad;
1212 }
1213 }
1214 if (line == NULL) {
1215 error = UPDATER_ERR_READ;
1216 goto bad;
1217 }
1218 if (state != NULL)
1219 free(state);
1220 return (0);
1221 bad:
1222 if (state != NULL)
1223 free(state);
1224 return (error);
1225 }
1226
1227 int
updater_diff_apply(struct updater * up,struct file_update * fup,char * state)1228 updater_diff_apply(struct updater *up, struct file_update *fup, char *state)
1229 {
1230 struct diffinfo dibuf, *di;
1231 struct coll *coll;
1232 struct statusrec *sr;
1233 int error;
1234
1235 coll = fup->coll;
1236 sr = &fup->srbuf;
1237 di = &dibuf;
1238
1239 di->di_rcsfile = sr->sr_file;
1240 di->di_cvsroot = coll->co_cvsroot;
1241 di->di_revnum = sr->sr_revnum;
1242 di->di_revdate = sr->sr_revdate;
1243 di->di_author = fup->author;
1244 di->di_tag = sr->sr_tag;
1245 di->di_state = state;
1246 di->di_expand = fup->expand;
1247
1248 error = diff_apply(up->rd, fup->orig, fup->to, coll->co_keyword, di, 1);
1249 if (error) {
1250 /* XXX Bad error message */
1251 xasprintf(&up->errmsg, "Bad diff from server");
1252 return (UPDATER_ERR_MSG);
1253 }
1254 return (0);
1255 }
1256
1257 /* Update or create a node. */
1258 static int
updater_updatenode(struct updater * up,struct coll * coll,struct file_update * fup,char * name,char * attr)1259 updater_updatenode(struct updater *up, struct coll *coll,
1260 struct file_update *fup, char *name, char *attr)
1261 {
1262 struct fattr *fa, *fileattr;
1263 struct status *st;
1264 struct statusrec *sr;
1265 int error, rv;
1266
1267 sr = &fup->srbuf;
1268 st = fup->st;
1269 fa = fattr_decode(attr);
1270
1271 if (fattr_type(fa) == FT_SYMLINK) {
1272 lprintf(1, " Symlink %s -> %s\n", name,
1273 fattr_getlinktarget(fa));
1274 } else {
1275 lprintf(1, " Mknod %s\n", name);
1276 }
1277
1278 /* Create directory. */
1279 error = mkdirhier(fup->destpath, coll->co_umask);
1280 if (error)
1281 return (UPDATER_ERR_PROTO);
1282
1283 /* If it does not exist, create it. */
1284 if (access(fup->destpath, F_OK) != 0)
1285 fattr_makenode(fa, fup->destpath);
1286
1287 /*
1288 * Coming from attic? I don't think this is a problem since we have
1289 * determined attic before we call this function (Look at UpdateNode in
1290 * cvsup).
1291 */
1292 fattr_umask(fa, coll->co_umask);
1293 rv = fattr_install(fa, fup->destpath, fup->temppath);
1294 if (rv == -1) {
1295 xasprintf(&up->errmsg, "Cannot update attributes on "
1296 "\"%s\": %s", fup->destpath, strerror(errno));
1297 return (UPDATER_ERR_MSG);
1298 }
1299 /*
1300 * XXX: Executes not implemented. Have not encountered much use for it
1301 * yet.
1302 */
1303 /*
1304 * We weren't necessarily able to set all the file attributes to the
1305 * desired values, and any executes may have altered the attributes.
1306 * To make sure we record the actual attribute values, we fetch
1307 * them from the file.
1308 *
1309 * However, we preserve the link count as received from the
1310 * server. This is important for preserving hard links in mirror
1311 * mode.
1312 */
1313 fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
1314 if (fileattr == NULL) {
1315 xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
1316 strerror(errno));
1317 return (UPDATER_ERR_MSG);
1318 }
1319 fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
1320 fattr_free(sr->sr_clientattr);
1321 sr->sr_clientattr = fileattr;
1322
1323 /*
1324 * To save space, don't write out the device and inode unless
1325 * the link count is greater than 1. These attributes are used
1326 * only for detecting hard links. If the link count is 1 then we
1327 * know there aren't any hard links.
1328 */
1329 if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
1330 fattr_getlinkcount(sr->sr_clientattr) <= 1)
1331 fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
1332
1333 /* If it is a symlink, write only out it's path. */
1334 if (fattr_type(fa) == FT_SYMLINK) {
1335 fattr_maskout(sr->sr_clientattr, ~(FA_FILETYPE |
1336 FA_LINKTARGET));
1337 }
1338 fattr_maskout(sr->sr_clientattr, FA_FLAGS);
1339 error = status_put(st, sr);
1340 if (error) {
1341 up->errmsg = status_errmsg(st);
1342 return (UPDATER_ERR_MSG);
1343 }
1344 fattr_free(fa);
1345
1346 return (0);
1347 }
1348
1349 /*
1350 * Fetches a new file in CVS mode.
1351 */
1352 static int
updater_addfile(struct updater * up,struct file_update * fup,char * attr,int isfixup)1353 updater_addfile(struct updater *up, struct file_update *fup, char *attr,
1354 int isfixup)
1355 {
1356 struct coll *coll;
1357 struct stream *to;
1358 struct statusrec *sr;
1359 struct fattr *fa;
1360 char buf[BUFSIZE];
1361 char md5[MD5_DIGEST_SIZE];
1362 ssize_t nread;
1363 off_t fsize, remains;
1364 char *cmd, *line, *path;
1365 int error;
1366
1367 coll = fup->coll;
1368 path = fup->destpath;
1369 sr = &fup->srbuf;
1370 fa = fattr_decode(attr);
1371 fsize = fattr_filesize(fa);
1372
1373 error = mkdirhier(path, coll->co_umask);
1374 if (error)
1375 return (UPDATER_ERR_PROTO);
1376 to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC, 0755);
1377 if (to == NULL) {
1378 xasprintf(&up->errmsg, "%s: Cannot create: %s",
1379 fup->temppath, strerror(errno));
1380 return (UPDATER_ERR_MSG);
1381 }
1382 stream_filter_start(to, STREAM_FILTER_MD5, md5);
1383 remains = fsize;
1384 do {
1385 nread = stream_read(up->rd, buf, (BUFSIZE > remains ?
1386 remains : BUFSIZE));
1387 if (nread == -1)
1388 return (UPDATER_ERR_PROTO);
1389 remains -= nread;
1390 if (stream_write(to, buf, nread) == -1)
1391 goto bad;
1392 } while (remains > 0);
1393 stream_close(to);
1394 line = stream_getln(up->rd, NULL);
1395 if (line == NULL)
1396 return (UPDATER_ERR_PROTO);
1397 /* Check for EOF. */
1398 if (!(*line == '.' || (strncmp(line, ".<", 2) != 0)))
1399 return (UPDATER_ERR_PROTO);
1400 line = stream_getln(up->rd, NULL);
1401 if (line == NULL)
1402 return (UPDATER_ERR_PROTO);
1403
1404 cmd = proto_get_ascii(&line);
1405 fup->wantmd5 = proto_get_ascii(&line);
1406 if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
1407 return (UPDATER_ERR_PROTO);
1408
1409 sr->sr_clientattr = fattr_frompath(fup->temppath, FATTR_NOFOLLOW);
1410 if (sr->sr_clientattr == NULL)
1411 return (UPDATER_ERR_PROTO);
1412 fattr_override(sr->sr_clientattr, sr->sr_serverattr,
1413 FA_MODTIME | FA_MASK);
1414 error = updater_updatefile(up, fup, md5, isfixup);
1415 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
1416 return (error);
1417 bad:
1418 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1419 strerror(errno));
1420 return (UPDATER_ERR_MSG);
1421 }
1422
1423 static int
updater_checkout(struct updater * up,struct file_update * fup,int isfixup)1424 updater_checkout(struct updater *up, struct file_update *fup, int isfixup)
1425 {
1426 char md5[MD5_DIGEST_SIZE];
1427 struct statusrec *sr;
1428 struct coll *coll;
1429 struct stream *to;
1430 ssize_t nbytes;
1431 size_t size;
1432 char *cmd, *path, *line;
1433 int error, first;
1434
1435 coll = fup->coll;
1436 sr = &fup->srbuf;
1437 path = fup->destpath;
1438
1439 if (isfixup)
1440 lprintf(1, " Fixup %s\n", fup->coname);
1441 else
1442 lprintf(1, " Checkout %s\n", fup->coname);
1443 error = mkdirhier(path, coll->co_umask);
1444 if (error) {
1445 xasprintf(&up->errmsg,
1446 "Cannot create directories leading to \"%s\": %s",
1447 path, strerror(errno));
1448 return (UPDATER_ERR_MSG);
1449 }
1450
1451 to = stream_open_file(fup->temppath,
1452 O_WRONLY | O_CREAT | O_TRUNC, 0600);
1453 if (to == NULL) {
1454 xasprintf(&up->errmsg, "%s: Cannot create: %s",
1455 fup->temppath, strerror(errno));
1456 return (UPDATER_ERR_MSG);
1457 }
1458 stream_filter_start(to, STREAM_FILTER_MD5, md5);
1459 line = stream_getln(up->rd, &size);
1460 first = 1;
1461 while (line != NULL) {
1462 if (line[size - 1] == '\n')
1463 size--;
1464 if ((size == 1 && *line == '.') ||
1465 (size == 2 && memcmp(line, ".+", 2) == 0))
1466 break;
1467 if (size >= 2 && memcmp(line, "..", 2) == 0) {
1468 size--;
1469 line++;
1470 }
1471 if (!first) {
1472 nbytes = stream_write(to, "\n", 1);
1473 if (nbytes == -1)
1474 goto bad;
1475 }
1476 nbytes = stream_write(to, line, size);
1477 if (nbytes == -1)
1478 goto bad;
1479 line = stream_getln(up->rd, &size);
1480 first = 0;
1481 }
1482 if (line == NULL) {
1483 stream_close(to);
1484 return (UPDATER_ERR_READ);
1485 }
1486 if (size == 1 && *line == '.') {
1487 nbytes = stream_write(to, "\n", 1);
1488 if (nbytes == -1)
1489 goto bad;
1490 }
1491 stream_close(to);
1492 /* Get the checksum line. */
1493 line = stream_getln(up->rd, NULL);
1494 if (line == NULL)
1495 return (UPDATER_ERR_READ);
1496 cmd = proto_get_ascii(&line);
1497 fup->wantmd5 = proto_get_ascii(&line);
1498 if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
1499 return (UPDATER_ERR_PROTO);
1500 error = updater_updatefile(up, fup, md5, isfixup);
1501 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
1502 if (error)
1503 return (error);
1504 return (0);
1505 bad:
1506 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1507 strerror(errno));
1508 return (UPDATER_ERR_MSG);
1509 }
1510
1511 /*
1512 * Remove all empty directories below file.
1513 * This function will trash the path passed to it.
1514 */
1515 static void
updater_prunedirs(char * base,char * file)1516 updater_prunedirs(char *base, char *file)
1517 {
1518 char *cp;
1519 int error;
1520
1521 while ((cp = strrchr(file, '/')) != NULL) {
1522 *cp = '\0';
1523 if (strcmp(base, file) == 0)
1524 return;
1525 error = rmdir(file);
1526 if (error)
1527 return;
1528 }
1529 }
1530
1531 /*
1532 * Edit an RCS file.
1533 */
1534 static int
updater_rcsedit(struct updater * up,struct file_update * fup,char * name,char * rcsopt)1535 updater_rcsedit(struct updater *up, struct file_update *fup, char *name,
1536 char *rcsopt)
1537 {
1538 struct coll *coll;
1539 struct stream *dest;
1540 struct statusrec *sr;
1541 struct status *st;
1542 struct rcsfile *rf;
1543 struct fattr *oldfattr;
1544 char md5[MD5_DIGEST_SIZE];
1545 char *branch, *cmd, *expand, *line, *path, *revnum, *tag, *temppath;
1546 int error;
1547
1548 coll = fup->coll;
1549 sr = &fup->srbuf;
1550 st = fup->st;
1551 temppath = fup->temppath;
1552 path = fup->origpath != NULL ? fup->origpath : fup->destpath;
1553 error = 0;
1554
1555 /* If the path is new, we must create the Attic dir if needed. */
1556 if (fup->origpath != NULL) {
1557 error = mkdirhier(fup->destpath, coll->co_umask);
1558 if (error) {
1559 xasprintf(&up->errmsg, "Unable to create Attic dir for "
1560 "%s\n", fup->origpath);
1561 return (UPDATER_ERR_MSG);
1562 }
1563 }
1564 /*
1565 * XXX: we could avoid parsing overhead if we're reading ahead before we
1566 * parse the file.
1567 */
1568 oldfattr = fattr_frompath(path, FATTR_NOFOLLOW);
1569 if (oldfattr == NULL) {
1570 xasprintf(&up->errmsg, "%s: Cannot get attributes: %s", path,
1571 strerror(errno));
1572 return (UPDATER_ERR_MSG);
1573 }
1574 fattr_merge(sr->sr_serverattr, oldfattr);
1575 rf = NULL;
1576
1577 /* Macro for making touching an RCS file faster. */
1578 #define UPDATER_OPENRCS(rf, up, path, name, cvsroot, tag) do { \
1579 if ((rf) == NULL) { \
1580 lprintf(1, " Edit %s", fup->coname); \
1581 if (fup->attic) \
1582 lprintf(1, " -> Attic"); \
1583 lprintf(1, "\n"); \
1584 (rf) = rcsfile_frompath((path), (name), (cvsroot), \
1585 (tag), 0); \
1586 if ((rf) == NULL) { \
1587 xasprintf(&(up)->errmsg, \
1588 "Error reading rcsfile %s\n", (name)); \
1589 return (UPDATER_ERR_MSG); \
1590 } \
1591 } \
1592 } while (0)
1593
1594 while ((line = stream_getln(up->rd, NULL)) != NULL) {
1595 if (strcmp(line, ".") == 0)
1596 break;
1597 cmd = proto_get_ascii(&line);
1598 if (cmd == NULL) {
1599 lprintf(-1, "Error editing %s\n", name);
1600 return (UPDATER_ERR_PROTO);
1601 }
1602 switch(cmd[0]) {
1603 case 'B':
1604 branch = proto_get_ascii(&line);
1605 if (branch == NULL || line != NULL)
1606 return (UPDATER_ERR_PROTO);
1607 UPDATER_OPENRCS(rf, up, path, name,
1608 coll->co_cvsroot, coll->co_tag);
1609 break;
1610 case 'b':
1611 UPDATER_OPENRCS(rf, up, path, name,
1612 coll->co_cvsroot, coll->co_tag);
1613 rcsfile_setval(rf, RCSFILE_BRANCH, NULL);
1614 break;
1615 case 'D':
1616 UPDATER_OPENRCS(rf, up, path, name,
1617 coll->co_cvsroot, coll->co_tag);
1618 error = updater_addelta(rf, up->rd, line);
1619 if (error)
1620 return (error);
1621 break;
1622 case 'd':
1623 revnum = proto_get_ascii(&line);
1624 if (revnum == NULL || line != NULL)
1625 return (UPDATER_ERR_PROTO);
1626 UPDATER_OPENRCS(rf, up, path, name,
1627 coll->co_cvsroot, coll->co_tag);
1628 rcsfile_deleterev(rf, revnum);
1629 break;
1630 case 'E':
1631 expand = proto_get_ascii(&line);
1632 if (expand == NULL || line != NULL)
1633 return (UPDATER_ERR_PROTO);
1634 UPDATER_OPENRCS(rf, up, path, name,
1635 coll->co_cvsroot, coll->co_tag);
1636 rcsfile_setval(rf, RCSFILE_EXPAND, expand);
1637 break;
1638 case 'T':
1639 tag = proto_get_ascii(&line);
1640 revnum = proto_get_ascii(&line);
1641 if (tag == NULL || revnum == NULL ||
1642 line != NULL)
1643 return (UPDATER_ERR_PROTO);
1644 UPDATER_OPENRCS(rf, up, path, name,
1645 coll->co_cvsroot, coll->co_tag);
1646 rcsfile_addtag(rf, tag, revnum);
1647 break;
1648 case 't':
1649 tag = proto_get_ascii(&line);
1650 revnum = proto_get_ascii(&line);
1651 if (tag == NULL || revnum == NULL ||
1652 line != NULL)
1653 return (UPDATER_ERR_PROTO);
1654 UPDATER_OPENRCS(rf, up, path, name,
1655 coll->co_cvsroot, coll->co_tag);
1656 rcsfile_deletetag(rf, tag, revnum);
1657 break;
1658 default:
1659 return (UPDATER_ERR_PROTO);
1660 }
1661 }
1662
1663 if (rf == NULL) {
1664 fattr_maskout(oldfattr, ~FA_MODTIME);
1665 if (fattr_equal(oldfattr, sr->sr_serverattr))
1666 lprintf(1, " SetAttrs %s", fup->coname);
1667 else
1668 lprintf(1, " Touch %s", fup->coname);
1669 /* Install new attributes. */
1670 fattr_umask(sr->sr_serverattr, coll->co_umask);
1671 fattr_install(sr->sr_serverattr, fup->destpath, NULL);
1672 if (fup->attic)
1673 lprintf(1, " -> Attic");
1674 lprintf(1, "\n");
1675 fattr_free(oldfattr);
1676 goto finish;
1677 }
1678
1679 /* Write and rename temp file. */
1680 dest = stream_open_file(fup->temppath,
1681 O_RDWR | O_CREAT | O_TRUNC, 0600);
1682 if (dest == NULL) {
1683 xasprintf(&up->errmsg, "Error opening file %s for writing: %s\n",
1684 fup->temppath, strerror(errno));
1685 return (UPDATER_ERR_MSG);
1686 }
1687 stream_filter_start(dest, STREAM_FILTER_MD5RCS, md5);
1688 error = rcsfile_write(rf, dest);
1689 stream_close(dest);
1690 rcsfile_free(rf);
1691 if (error) {
1692 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1693 strerror(errno));
1694 return (UPDATER_ERR_MSG);
1695 }
1696
1697 finish:
1698 sr->sr_clientattr = fattr_frompath(path, FATTR_NOFOLLOW);
1699 if (sr->sr_clientattr == NULL) {
1700 xasprintf(&up->errmsg, "%s: Cannot get attributes: %s",
1701 fup->destpath, strerror(errno));
1702 return (UPDATER_ERR_MSG);
1703 }
1704 fattr_override(sr->sr_clientattr, sr->sr_serverattr,
1705 FA_MODTIME | FA_MASK);
1706 if (rf != NULL) {
1707 error = updater_updatefile(up, fup, md5, 0);
1708 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
1709 if (error)
1710 return (error);
1711 } else {
1712 /* Record its attributes since we touched it. */
1713 if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
1714 fattr_getlinkcount(sr->sr_clientattr) <= 1)
1715 fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
1716 error = status_put(st, sr);
1717 if (error) {
1718 up->errmsg = status_errmsg(st);
1719 return (UPDATER_ERR_MSG);
1720 }
1721 }
1722
1723 /* In this case, we need to remove the old file afterwards. */
1724 /* XXX: Can we be sure that a file not edited is moved? I don't think
1725 * this is a problem, since if a file is moved, it should be edited to
1726 * show if it's dead or not.
1727 */
1728 if (fup->origpath != NULL)
1729 updater_deletefile(fup->origpath);
1730 return (0);
1731 }
1732
1733 /*
1734 * Add a delta to a RCS file.
1735 */
1736 int
updater_addelta(struct rcsfile * rf,struct stream * rd,char * cmdline)1737 updater_addelta(struct rcsfile *rf, struct stream *rd, char *cmdline)
1738 {
1739 struct delta *d;
1740 size_t size;
1741 char *author, *cmd, *diffbase, *line, *logline;
1742 char *revdate, *revnum, *state, *textline;
1743
1744 revnum = proto_get_ascii(&cmdline);
1745 diffbase = proto_get_ascii(&cmdline);
1746 revdate = proto_get_ascii(&cmdline);
1747 author = proto_get_ascii(&cmdline);
1748 size = 0;
1749
1750 if (revnum == NULL || revdate == NULL || author == NULL)
1751 return (UPDATER_ERR_PROTO);
1752
1753 /* First add the delta so we have it. */
1754 d = rcsfile_addelta(rf, revnum, revdate, author, diffbase);
1755 if (d == NULL) {
1756 lprintf(-1, "Error adding delta %s\n", revnum);
1757 return (UPDATER_ERR_READ);
1758 }
1759 while ((line = stream_getln(rd, NULL)) != NULL) {
1760 if (strcmp(line, ".") == 0)
1761 break;
1762 cmd = proto_get_ascii(&line);
1763 switch (cmd[0]) {
1764 case 'L':
1765 /* Do the same as in 'C' command. */
1766 logline = stream_getln(rd, &size);
1767 while (logline != NULL) {
1768 if (size == 2 && *logline == '.')
1769 break;
1770 if (size == 3 &&
1771 memcmp(logline, ".+", 2) == 0) {
1772 rcsdelta_truncatelog(d, -1);
1773 break;
1774 }
1775 if (size >= 3 &&
1776 memcmp(logline, "..", 2) == 0) {
1777 size--;
1778 logline++;
1779 }
1780 if (rcsdelta_appendlog(d, logline, size)
1781 < 0)
1782 return (-1);
1783 logline = stream_getln(rd, &size);
1784 }
1785 break;
1786 case 'N':
1787 case 'n':
1788 /* XXX: Not supported. */
1789 break;
1790 case 'S':
1791 state = proto_get_ascii(&line);
1792 if (state == NULL)
1793 return (UPDATER_ERR_PROTO);
1794 rcsdelta_setstate(d, state);
1795 break;
1796 case 'T':
1797 /* Do the same as in 'C' command. */
1798 textline = stream_getln(rd, &size);
1799 while (textline != NULL) {
1800 if (size == 2 && *textline == '.')
1801 break;
1802 if (size == 3 &&
1803 memcmp(textline, ".+", 2) == 0) {
1804 /* Truncate newline. */
1805 rcsdelta_truncatetext(d, -1);
1806 break;
1807 }
1808 if (size >= 3 &&
1809 memcmp(textline, "..", 2) == 0) {
1810 size--;
1811 textline++;
1812 }
1813 if (rcsdelta_appendtext(d, textline,
1814 size) < 0)
1815 return (-1);
1816 textline = stream_getln(rd, &size);
1817 }
1818 break;
1819 }
1820 }
1821
1822 return (0);
1823 }
1824
1825 int
updater_append_file(struct updater * up,struct file_update * fup,off_t pos)1826 updater_append_file(struct updater *up, struct file_update *fup, off_t pos)
1827 {
1828 struct fattr *fa;
1829 struct stream *to;
1830 struct statusrec *sr;
1831 ssize_t nread;
1832 off_t bytes;
1833 char buf[BUFSIZE], md5[MD5_DIGEST_SIZE];
1834 char *line, *cmd;
1835 int error, fd;
1836
1837 sr = &fup->srbuf;
1838 fa = sr->sr_serverattr;
1839 to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC,
1840 0755);
1841 if (to == NULL) {
1842 xasprintf(&up->errmsg, "%s: Cannot open: %s", fup->temppath,
1843 strerror(errno));
1844 return (UPDATER_ERR_MSG);
1845 }
1846 fd = open(fup->destpath, O_RDONLY);
1847 if (fd < 0) {
1848 xasprintf(&up->errmsg, "%s: Cannot open: %s", fup->destpath,
1849 strerror(errno));
1850 return (UPDATER_ERR_MSG);
1851 }
1852
1853 stream_filter_start(to, STREAM_FILTER_MD5, md5);
1854 /* First write the existing content. */
1855 while ((nread = read(fd, buf, BUFSIZE)) > 0) {
1856 if (stream_write(to, buf, nread) == -1)
1857 goto bad;
1858 }
1859 if (nread == -1) {
1860 xasprintf(&up->errmsg, "%s: Error reading: %s", fup->destpath,
1861 strerror(errno));
1862 return (UPDATER_ERR_MSG);
1863 }
1864 close(fd);
1865
1866 bytes = fattr_filesize(fa) - pos;
1867 /* Append the new data. */
1868 do {
1869 nread = stream_read(up->rd, buf,
1870 (BUFSIZE > bytes) ? bytes : BUFSIZE);
1871 if (nread == -1)
1872 return (UPDATER_ERR_PROTO);
1873 bytes -= nread;
1874 if (stream_write(to, buf, nread) == -1)
1875 goto bad;
1876 } while (bytes > 0);
1877 stream_close(to);
1878
1879 line = stream_getln(up->rd, NULL);
1880 if (line == NULL)
1881 return (UPDATER_ERR_PROTO);
1882 /* Check for EOF. */
1883 if (!(*line == '.' || (strncmp(line, ".<", 2) != 0)))
1884 return (UPDATER_ERR_PROTO);
1885 line = stream_getln(up->rd, NULL);
1886 if (line == NULL)
1887 return (UPDATER_ERR_PROTO);
1888
1889 cmd = proto_get_ascii(&line);
1890 fup->wantmd5 = proto_get_ascii(&line);
1891 if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
1892 return (UPDATER_ERR_PROTO);
1893
1894 sr->sr_clientattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
1895 if (sr->sr_clientattr == NULL)
1896 return (UPDATER_ERR_PROTO);
1897 fattr_override(sr->sr_clientattr, sr->sr_serverattr,
1898 FA_MODTIME | FA_MASK);
1899 error = updater_updatefile(up, fup, md5, 0);
1900 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
1901 return (error);
1902 bad:
1903 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1904 strerror(errno));
1905 return (UPDATER_ERR_MSG);
1906 }
1907
1908 /*
1909 * Read file data from stream of checkout commands, and write it to the
1910 * destination.
1911 */
1912 static int
updater_read_checkout(struct stream * src,struct stream * dest)1913 updater_read_checkout(struct stream *src, struct stream *dest)
1914 {
1915 ssize_t nbytes;
1916 size_t size;
1917 char *line;
1918 int first;
1919
1920 first = 1;
1921 line = stream_getln(src, &size);
1922 while (line != NULL) {
1923 if (line[size - 1] == '\n')
1924 size--;
1925 if ((size == 1 && *line == '.') ||
1926 (size == 2 && strncmp(line, ".+", 2) == 0))
1927 break;
1928 if (size >= 2 && strncmp(line, "..", 2) == 0) {
1929 size--;
1930 line++;
1931 }
1932 if (!first) {
1933 nbytes = stream_write(dest, "\n", 1);
1934 if (nbytes == -1)
1935 return (UPDATER_ERR_MSG);
1936 }
1937 nbytes = stream_write(dest, line, size);
1938 if (nbytes == -1)
1939 return (UPDATER_ERR_MSG);
1940 line = stream_getln(src, &size);
1941 first = 0;
1942 }
1943 if (line == NULL)
1944 return (UPDATER_ERR_READ);
1945 if (size == 1 && *line == '.') {
1946 nbytes = stream_write(dest, "\n", 1);
1947 if (nbytes == -1)
1948 return (UPDATER_ERR_MSG);
1949 }
1950 return (0);
1951 }
1952
1953 /* Update file using the rsync protocol. */
1954 static int
updater_rsync(struct updater * up,struct file_update * fup,size_t blocksize)1955 updater_rsync(struct updater *up, struct file_update *fup, size_t blocksize)
1956 {
1957 struct statusrec *sr;
1958 struct stream *to;
1959 char md5[MD5_DIGEST_SIZE];
1960 ssize_t nbytes;
1961 size_t blocknum, blockstart, blockcount;
1962 char *buf, *line;
1963 int error, orig;
1964
1965 sr = &fup->srbuf;
1966
1967 lprintf(1, " Rsync %s\n", fup->coname);
1968 /* First open all files that we are going to work on. */
1969 to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC,
1970 0600);
1971 if (to == NULL) {
1972 xasprintf(&up->errmsg, "%s: Cannot create: %s",
1973 fup->temppath, strerror(errno));
1974 return (UPDATER_ERR_MSG);
1975 }
1976 orig = open(fup->destpath, O_RDONLY);
1977 if (orig < 0) {
1978 xasprintf(&up->errmsg, "%s: Cannot open: %s",
1979 fup->destpath, strerror(errno));
1980 return (UPDATER_ERR_MSG);
1981 }
1982 stream_filter_start(to, STREAM_FILTER_MD5, md5);
1983
1984 error = updater_read_checkout(up->rd, to);
1985 if (error) {
1986 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1987 strerror(errno));
1988 return (error);
1989 }
1990
1991 /* Buffer must contain blocksize bytes. */
1992 buf = xmalloc(blocksize);
1993 /* Done with the initial text, read and write chunks. */
1994 line = stream_getln(up->rd, NULL);
1995 while (line != NULL) {
1996 if (strcmp(line, ".") == 0)
1997 break;
1998 error = UPDATER_ERR_PROTO;
1999 if (proto_get_sizet(&line, &blockstart, 10) != 0)
2000 goto bad;
2001 if (proto_get_sizet(&line, &blockcount, 10) != 0)
2002 goto bad;
2003 /* Read blocks from original file. */
2004 lseek(orig, (blocksize * blockstart), SEEK_SET);
2005 error = UPDATER_ERR_MSG;
2006 for (blocknum = 0; blocknum < blockcount; blocknum++) {
2007 nbytes = read(orig, buf, blocksize);
2008 if (nbytes < 0) {
2009 xasprintf(&up->errmsg, "%s: Cannot read: %s",
2010 fup->destpath, strerror(errno));
2011 goto bad;
2012 }
2013 nbytes = stream_write(to, buf, nbytes);
2014 if (nbytes == -1) {
2015 xasprintf(&up->errmsg, "%s: Cannot write: %s",
2016 fup->temppath, strerror(errno));
2017 goto bad;
2018 }
2019 }
2020 /* Get the remaining text from the server. */
2021 error = updater_read_checkout(up->rd, to);
2022 if (error) {
2023 xasprintf(&up->errmsg, "%s: Cannot write: %s",
2024 fup->temppath, strerror(errno));
2025 goto bad;
2026 }
2027 line = stream_getln(up->rd, NULL);
2028 }
2029 stream_close(to);
2030 close(orig);
2031
2032 sr->sr_clientattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
2033 if (sr->sr_clientattr == NULL)
2034 return (UPDATER_ERR_PROTO);
2035 fattr_override(sr->sr_clientattr, sr->sr_serverattr,
2036 FA_MODTIME | FA_MASK);
2037
2038 error = updater_updatefile(up, fup, md5, 0);
2039 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
2040 bad:
2041 free(buf);
2042 return (error);
2043 }
2044