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
29 #include <sys/types.h>
53 /* Internal error codes. */
54 #define UPDATER_ERR_PROTO (-1) /* Protocol error. */
55 #define UPDATER_ERR_MSG (-2) /* Error is in updater->errmsg. */
56 #define UPDATER_ERR_READ (-3) /* Error reading from server. */
57 #define UPDATER_ERR_DELETELIM (-4) /* File deletion limit exceeded. */
59 /* Everything needed to update a file. */
61 struct statusrec srbuf;
64 char *coname; /* Points somewhere in destpath. */
68 /* Those are only used for diff updating. */
76 struct config *config;
82 static struct file_update *fup_new(struct coll *, struct status *);
83 static int fup_prepare(struct file_update *, char *);
84 static void fup_cleanup(struct file_update *);
85 static void fup_free(struct file_update *);
87 static void updater_prunedirs(char *, char *);
88 static int updater_batch(struct updater *, int);
89 static int updater_docoll(struct updater *, struct file_update *, int);
90 static int updater_delete(struct updater *, struct file_update *);
91 static void updater_deletefile(const char *);
92 static int updater_checkout(struct updater *, struct file_update *, int);
93 static int updater_setattrs(struct updater *, struct file_update *,
94 char *, char *, char *, char *, char *, struct fattr *);
95 static int updater_updatefile(struct updater *, struct file_update *fup,
97 static int updater_diff(struct updater *, struct file_update *);
98 static int updater_diff_batch(struct updater *, struct file_update *);
99 static int updater_diff_apply(struct updater *, struct file_update *,
102 static struct file_update *
103 fup_new(struct coll *coll, struct status *st)
105 struct file_update *fup;
107 fup = xmalloc(sizeof(struct file_update));
108 memset(fup, 0, sizeof(*fup));
115 fup_prepare(struct file_update *fup, char *name)
120 fup->destpath = checkoutpath(coll->co_prefix, name);
121 if (fup->destpath == NULL)
123 fup->coname = fup->destpath + coll->co_prefixlen + 1;
127 /* Called after each file update to reinit the structure. */
129 fup_cleanup(struct file_update *fup)
131 struct statusrec *sr;
135 if (fup->destpath != NULL) {
137 fup->destpath = NULL;
139 if (fup->temppath != NULL) {
141 fup->temppath = NULL;
144 if (fup->author != NULL) {
149 if (fup->wantmd5 != NULL) {
153 if (fup->orig != NULL) {
154 stream_close(fup->orig);
157 if (fup->to != NULL) {
158 stream_close(fup->to);
161 if (sr->sr_file != NULL)
163 if (sr->sr_tag != NULL)
165 if (sr->sr_date != NULL)
167 if (sr->sr_revnum != NULL)
169 if (sr->sr_revdate != NULL)
170 free(sr->sr_revdate);
171 fattr_free(sr->sr_clientattr);
172 fattr_free(sr->sr_serverattr);
173 memset(sr, 0, sizeof(*sr));
177 fup_free(struct file_update *fup)
187 struct thread_args *args;
188 struct updater upbuf, *up;
194 up->config = args->config;
199 error = updater_batch(up, 0);
202 * Make sure to close the fixups even in case of an error,
203 * so that the lister thread doesn't block indefinitely.
205 fixups_close(up->config->fixups);
207 error = updater_batch(up, 1);
209 case UPDATER_ERR_PROTO:
210 xasprintf(&args->errmsg, "Updater failed: Protocol error");
211 args->status = STATUS_FAILURE;
213 case UPDATER_ERR_MSG:
214 xasprintf(&args->errmsg, "Updater failed: %s", up->errmsg);
216 args->status = STATUS_FAILURE;
218 case UPDATER_ERR_READ:
219 if (stream_eof(up->rd)) {
220 xasprintf(&args->errmsg, "Updater failed: "
221 "Premature EOF from server");
223 xasprintf(&args->errmsg, "Updater failed: "
224 "Network read failure: %s", strerror(errno));
226 args->status = STATUS_TRANSIENTFAILURE;
228 case UPDATER_ERR_DELETELIM:
229 xasprintf(&args->errmsg, "Updater failed: "
230 "File deletion limit exceeded");
231 args->status = STATUS_FAILURE;
235 args->status = STATUS_SUCCESS;
241 updater_batch(struct updater *up, int isfixups)
246 struct file_update *fup;
247 char *line, *cmd, *errmsg, *collname, *release;
251 STAILQ_FOREACH(coll, &up->config->colls, co_next) {
252 if (coll->co_options & CO_SKIP)
254 umask(coll->co_umask);
255 line = stream_getln(rd, NULL);
257 return (UPDATER_ERR_READ);
258 cmd = proto_get_ascii(&line);
259 collname = proto_get_ascii(&line);
260 release = proto_get_ascii(&line);
261 if (release == NULL || line != NULL)
262 return (UPDATER_ERR_PROTO);
263 if (strcmp(cmd, "COLL") != 0 ||
264 strcmp(collname, coll->co_name) != 0 ||
265 strcmp(release, coll->co_release) != 0)
266 return (UPDATER_ERR_PROTO);
269 lprintf(1, "Updating collection %s/%s\n", coll->co_name,
272 if (coll->co_options & CO_COMPRESS)
273 stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
275 st = status_open(coll, coll->co_scantime, &errmsg);
278 return (UPDATER_ERR_MSG);
280 fup = fup_new(coll, st);
281 error = updater_docoll(up, fup, isfixups);
282 status_close(st, &errmsg);
284 if (errmsg != NULL) {
285 /* Discard previous error. */
286 if (up->errmsg != NULL)
289 return (UPDATER_ERR_MSG);
294 if (coll->co_options & CO_COMPRESS)
295 stream_filter_stop(rd);
297 line = stream_getln(rd, NULL);
299 return (UPDATER_ERR_READ);
300 if (strcmp(line, ".") != 0)
301 return (UPDATER_ERR_PROTO);
306 updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
310 struct statusrec srbuf, *sr;
311 struct fattr *rcsattr, *tmp;
312 char *cmd, *line, *msg, *attr;
313 char *name, *tag, *date, *revdate;
314 char *expand, *wantmd5, *revnum;
316 int error, needfixupmsg;
321 needfixupmsg = isfixups;
322 while ((line = stream_getln(rd, NULL)) != NULL) {
323 if (strcmp(line, ".") == 0)
325 memset(&srbuf, 0, sizeof(srbuf));
327 lprintf(1, "Applying fixups for collection %s/%s\n",
328 coll->co_name, coll->co_release);
331 cmd = proto_get_ascii(&line);
332 if (cmd == NULL || strlen(cmd) != 1)
333 return (UPDATER_ERR_PROTO);
336 /* Update recorded information for checked-out file. */
337 name = proto_get_ascii(&line);
338 tag = proto_get_ascii(&line);
339 date = proto_get_ascii(&line);
340 revnum = proto_get_ascii(&line);
341 revdate = proto_get_ascii(&line);
342 attr = proto_get_ascii(&line);
343 if (attr == NULL || line != NULL)
344 return (UPDATER_ERR_PROTO);
346 rcsattr = fattr_decode(attr);
348 return (UPDATER_ERR_PROTO);
350 error = fup_prepare(fup, name);
352 return (UPDATER_ERR_PROTO);
353 error = updater_setattrs(up, fup, name, tag, date,
354 revnum, revdate, rcsattr);
360 /* Checkout dead file. */
361 name = proto_get_ascii(&line);
362 tag = proto_get_ascii(&line);
363 date = proto_get_ascii(&line);
364 attr = proto_get_ascii(&line);
365 if (attr == NULL || line != NULL)
366 return (UPDATER_ERR_PROTO);
368 error = fup_prepare(fup, name);
370 return (UPDATER_ERR_PROTO);
371 /* Theoritically, the file does not exist on the client.
372 Just to make sure, we'll delete it here, if it
374 if (access(fup->destpath, F_OK) == 0) {
375 error = updater_delete(up, fup);
381 sr->sr_type = SR_CHECKOUTDEAD;
385 sr->sr_serverattr = fattr_decode(attr);
386 if (sr->sr_serverattr == NULL)
387 return (UPDATER_ERR_PROTO);
389 error = status_put(fup->st, sr);
390 fattr_free(sr->sr_serverattr);
392 up->errmsg = status_errmsg(fup->st);
393 return (UPDATER_ERR_MSG);
397 /* Update live checked-out file. */
398 name = proto_get_ascii(&line);
399 tag = proto_get_ascii(&line);
400 date = proto_get_ascii(&line);
401 proto_get_ascii(&line); /* XXX - oldRevNum */
402 proto_get_ascii(&line); /* XXX - fromAttic */
403 proto_get_ascii(&line); /* XXX - logLines */
404 expand = proto_get_ascii(&line);
405 attr = proto_get_ascii(&line);
406 wantmd5 = proto_get_ascii(&line);
407 if (wantmd5 == NULL || line != NULL)
408 return (UPDATER_ERR_PROTO);
411 sr->sr_type = SR_CHECKOUTLIVE;
412 sr->sr_file = xstrdup(name);
413 sr->sr_date = xstrdup(date);
414 sr->sr_tag = xstrdup(tag);
415 sr->sr_serverattr = fattr_decode(attr);
416 if (sr->sr_serverattr == NULL)
417 return (UPDATER_ERR_PROTO);
419 fup->expand = keyword_decode_expand(expand);
420 if (fup->expand == -1)
421 return (UPDATER_ERR_PROTO);
422 error = fup_prepare(fup, name);
424 return (UPDATER_ERR_PROTO);
426 fup->wantmd5 = xstrdup(wantmd5);
427 fup->temppath = tempname(fup->destpath);
428 error = updater_diff(up, fup);
433 /* Update dead checked-out file. */
434 name = proto_get_ascii(&line);
435 tag = proto_get_ascii(&line);
436 date = proto_get_ascii(&line);
437 attr = proto_get_ascii(&line);
438 if (attr == NULL || line != NULL)
439 return (UPDATER_ERR_PROTO);
441 error = fup_prepare(fup, name);
443 return (UPDATER_ERR_PROTO);
444 error = updater_delete(up, fup);
448 sr->sr_type = SR_CHECKOUTDEAD;
452 sr->sr_serverattr = fattr_decode(attr);
453 if (sr->sr_serverattr == NULL)
454 return (UPDATER_ERR_PROTO);
455 error = status_put(fup->st, sr);
456 fattr_free(sr->sr_serverattr);
458 up->errmsg = status_errmsg(fup->st);
459 return (UPDATER_ERR_MSG);
465 name = proto_get_ascii(&line);
466 tag = proto_get_ascii(&line);
467 date = proto_get_ascii(&line);
468 revnum = proto_get_ascii(&line);
469 revdate = proto_get_ascii(&line);
470 attr = proto_get_ascii(&line);
471 if (attr == NULL || line != NULL)
472 return (UPDATER_ERR_PROTO);
475 sr->sr_type = SR_CHECKOUTLIVE;
476 sr->sr_file = xstrdup(name);
477 sr->sr_tag = xstrdup(tag);
478 sr->sr_date = xstrdup(date);
479 sr->sr_revnum = xstrdup(revnum);
480 sr->sr_revdate = xstrdup(revdate);
481 sr->sr_serverattr = fattr_decode(attr);
482 if (sr->sr_serverattr == NULL)
483 return (UPDATER_ERR_PROTO);
485 t = rcsdatetotime(revdate);
487 return (UPDATER_ERR_PROTO);
489 sr->sr_clientattr = fattr_new(FT_FILE, t);
490 tmp = fattr_forcheckout(sr->sr_serverattr,
492 fattr_override(sr->sr_clientattr, tmp, FA_MASK);
494 fattr_mergedefault(sr->sr_clientattr);
495 error = fup_prepare(fup, name);
497 return (UPDATER_ERR_PROTO);
498 fup->temppath = tempname(fup->destpath);
500 error = updater_checkout(up, fup, 1);
502 error = updater_checkout(up, fup, 0);
508 name = proto_get_ascii(&line);
509 if (name == NULL || line != NULL)
510 return (UPDATER_ERR_PROTO);
511 error = fup_prepare(fup, name);
513 return (UPDATER_ERR_PROTO);
514 error = updater_delete(up, fup);
517 error = status_delete(fup->st, name, 0);
519 up->errmsg = status_errmsg(fup->st);
520 return (UPDATER_ERR_MSG);
524 /* Warning from server. */
525 msg = proto_get_rest(&line);
527 return (UPDATER_ERR_PROTO);
528 lprintf(-1, "Server warning: %s\n", msg);
531 return (UPDATER_ERR_PROTO);
536 return (UPDATER_ERR_READ);
542 updater_delete(struct updater *up, struct file_update *fup)
544 struct config *config;
549 if (coll->co_options & CO_DELETE) {
550 lprintf(1, " Delete %s\n", fup->coname);
551 if (config->deletelim >= 0 &&
552 up->deletecount >= config->deletelim)
553 return (UPDATER_ERR_DELETELIM);
555 updater_deletefile(fup->destpath);
556 if (coll->co_options & CO_CHECKOUTMODE)
557 updater_prunedirs(coll->co_prefix, fup->destpath);
559 lprintf(1," NoDelete %s\n", fup->coname);
565 updater_deletefile(const char *path)
569 error = fattr_delete(path);
570 if (error && errno != ENOENT) {
571 lprintf(-1, "Cannot delete \"%s\": %s\n",
572 path, strerror(errno));
577 updater_setattrs(struct updater *up, struct file_update *fup, char *name,
578 char *tag, char *date, char *revnum, char *revdate, struct fattr *rcsattr)
583 struct fattr *fileattr, *fa;
589 path = fup->destpath;
591 fileattr = fattr_frompath(path, FATTR_NOFOLLOW);
592 if (fileattr == NULL) {
593 /* The file has vanished. */
594 error = status_delete(st, name, 0);
596 up->errmsg = status_errmsg(st);
597 return (UPDATER_ERR_MSG);
601 fa = fattr_forcheckout(rcsattr, coll->co_umask);
602 fattr_override(fileattr, fa, FA_MASK);
605 rv = fattr_install(fileattr, path, NULL);
607 lprintf(1, " SetAttrs %s\n", fup->coname);
608 fattr_free(fileattr);
609 xasprintf(&up->errmsg, "Cannot set attributes for \"%s\": %s",
610 path, strerror(errno));
611 return (UPDATER_ERR_MSG);
614 lprintf(1, " SetAttrs %s\n", fup->coname);
615 fattr_free(fileattr);
616 fileattr = fattr_frompath(path, FATTR_NOFOLLOW);
617 if (fileattr == NULL) {
618 /* We're being very unlucky. */
619 error = status_delete(st, name, 0);
621 up->errmsg = status_errmsg(st);
622 return (UPDATER_ERR_MSG);
628 fattr_maskout(fileattr, FA_COIGNORE);
630 sr.sr_type = SR_CHECKOUTLIVE;
634 sr.sr_revnum = revnum;
635 sr.sr_revdate = revdate;
636 sr.sr_clientattr = fileattr;
637 sr.sr_serverattr = rcsattr;
639 error = status_put(st, &sr);
640 fattr_free(fileattr);
642 up->errmsg = status_errmsg(st);
643 return (UPDATER_ERR_MSG);
649 updater_updatefile(struct updater *up, struct file_update *fup,
650 const char *md5, int isfixup)
654 struct statusrec *sr;
655 struct fattr *fileattr;
662 if (strcmp(fup->wantmd5, md5) != 0) {
664 lprintf(-1, "%s: Checksum mismatch -- "
665 "file not updated\n", fup->destpath);
667 lprintf(-1, "%s: Checksum mismatch -- "
668 "will transfer entire file\n", fup->destpath);
669 fixups_put(up->config->fixups, fup->coll, sr->sr_file);
671 if (coll->co_options & CO_KEEPBADFILES)
672 lprintf(-1, "Bad version saved in %s\n", fup->temppath);
674 updater_deletefile(fup->temppath);
678 fattr_umask(sr->sr_clientattr, coll->co_umask);
679 rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath);
681 xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
682 fup->temppath, fup->destpath, strerror(errno));
683 return (UPDATER_ERR_MSG);
688 * We weren't necessarily able to set all the file attributes to the
689 * desired values, and any executes may have altered the attributes.
690 * To make sure we record the actual attribute values, we fetch
691 * them from the file.
693 * However, we preserve the link count as received from the
694 * server. This is important for preserving hard links in mirror
697 fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
698 if (fileattr == NULL) {
699 xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
701 return (UPDATER_ERR_MSG);
703 fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
704 fattr_free(sr->sr_clientattr);
705 sr->sr_clientattr = fileattr;
708 * To save space, don't write out the device and inode unless
709 * the link count is greater than 1. These attributes are used
710 * only for detecting hard links. If the link count is 1 then we
711 * know there aren't any hard links.
713 if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
714 fattr_getlinkcount(sr->sr_clientattr) <= 1)
715 fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
717 if (coll->co_options & CO_CHECKOUTMODE)
718 fattr_maskout(sr->sr_clientattr, FA_COIGNORE);
720 error = status_put(st, sr);
722 up->errmsg = status_errmsg(st);
723 return (UPDATER_ERR_MSG);
729 updater_diff(struct updater *up, struct file_update *fup)
731 char md5[MD5_DIGEST_SIZE];
733 struct statusrec *sr;
734 struct fattr *fa, *tmp;
735 char *author, *path, *revnum, *revdate;
741 path = fup->destpath;
743 lprintf(1, " Edit %s\n", fup->coname);
744 while ((line = stream_getln(up->rd, NULL)) != NULL) {
745 if (strcmp(line, ".") == 0)
747 cmd = proto_get_ascii(&line);
748 if (cmd == NULL || strcmp(cmd, "D") != 0)
749 return (UPDATER_ERR_PROTO);
750 revnum = proto_get_ascii(&line);
751 proto_get_ascii(&line); /* XXX - diffbase */
752 revdate = proto_get_ascii(&line);
753 author = proto_get_ascii(&line);
754 if (author == NULL || line != NULL)
755 return (UPDATER_ERR_PROTO);
756 if (sr->sr_revnum != NULL)
758 if (sr->sr_revdate != NULL)
759 free(sr->sr_revdate);
760 if (fup->author != NULL)
762 sr->sr_revnum = xstrdup(revnum);
763 sr->sr_revdate = xstrdup(revdate);
764 fup->author = xstrdup(author);
765 if (fup->orig == NULL) {
766 /* First patch, the "origin" file is the one we have. */
767 fup->orig = stream_open_file(path, O_RDONLY);
768 if (fup->orig == NULL) {
769 xasprintf(&up->errmsg, "%s: Cannot open: %s",
770 path, strerror(errno));
771 return (UPDATER_ERR_MSG);
774 /* Subsequent patches. */
775 stream_close(fup->orig);
777 stream_rewind(fup->orig);
778 unlink(fup->temppath);
780 fup->temppath = tempname(path);
782 fup->to = stream_open_file(fup->temppath,
783 O_RDWR | O_CREAT | O_TRUNC, 0600);
784 if (fup->to == NULL) {
785 xasprintf(&up->errmsg, "%s: Cannot open: %s",
786 fup->temppath, strerror(errno));
787 return (UPDATER_ERR_MSG);
789 lprintf(2, " Add delta %s %s %s\n", sr->sr_revnum,
790 sr->sr_revdate, fup->author);
791 error = updater_diff_batch(up, fup);
796 return (UPDATER_ERR_READ);
798 fa = fattr_frompath(path, FATTR_FOLLOW);
799 tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask);
800 fattr_override(fa, tmp, FA_MASK);
802 fattr_maskout(fa, FA_MODTIME);
803 sr->sr_clientattr = fa;
805 if (MD5_File(fup->temppath, md5) == -1) {
806 xasprintf(&up->errmsg,
807 "Cannot calculate checksum for \"%s\": %s",
808 path, strerror(errno));
809 return (UPDATER_ERR_MSG);
811 error = updater_updatefile(up, fup, md5, 0);
816 updater_diff_batch(struct updater *up, struct file_update *fup)
819 char *cmd, *line, *state, *tok;
824 while ((line = stream_getln(rd, NULL)) != NULL) {
825 if (strcmp(line, ".") == 0)
827 cmd = proto_get_ascii(&line);
828 if (cmd == NULL || strlen(cmd) != 1) {
829 error = UPDATER_ERR_PROTO;
834 line = stream_getln(rd, NULL);
835 /* XXX - We're just eating the log for now. */
836 while (line != NULL && strcmp(line, ".") != 0 &&
837 strcmp(line, ".+") != 0)
838 line = stream_getln(rd, NULL);
840 error = UPDATER_ERR_READ;
845 tok = proto_get_ascii(&line);
846 if (tok == NULL || line != NULL) {
847 error = UPDATER_ERR_PROTO;
852 state = xstrdup(tok);
855 error = updater_diff_apply(up, fup, state);
860 error = UPDATER_ERR_PROTO;
865 error = UPDATER_ERR_READ;
878 updater_diff_apply(struct updater *up, struct file_update *fup, char *state)
880 struct diffinfo dibuf, *di;
882 struct statusrec *sr;
889 di->di_rcsfile = sr->sr_file;
890 di->di_cvsroot = coll->co_cvsroot;
891 di->di_revnum = sr->sr_revnum;
892 di->di_revdate = sr->sr_revdate;
893 di->di_author = fup->author;
894 di->di_tag = sr->sr_tag;
895 di->di_state = state;
896 di->di_expand = fup->expand;
898 error = diff_apply(up->rd, fup->orig, fup->to, coll->co_keyword, di);
900 /* XXX Bad error message */
901 xasprintf(&up->errmsg, "Bad diff from server");
902 return (UPDATER_ERR_MSG);
908 updater_checkout(struct updater *up, struct file_update *fup, int isfixup)
910 char md5[MD5_DIGEST_SIZE];
911 struct statusrec *sr;
914 char *cmd, *path, *line;
921 path = fup->destpath;
924 lprintf(1, " Fixup %s\n", fup->coname);
926 lprintf(1, " Checkout %s\n", fup->coname);
927 error = mkdirhier(path, coll->co_umask);
929 xasprintf(&up->errmsg,
930 "Cannot create directories leading to \"%s\": %s",
931 path, strerror(errno));
932 return (UPDATER_ERR_MSG);
935 to = stream_open_file(fup->temppath,
936 O_WRONLY | O_CREAT | O_TRUNC, 0600);
938 xasprintf(&up->errmsg, "%s: Cannot create: %s",
939 fup->temppath, strerror(errno));
940 return (UPDATER_ERR_MSG);
942 stream_filter_start(to, STREAM_FILTER_MD5, md5);
943 line = stream_getln(up->rd, &size);
945 while (line != NULL) {
946 if (line[size - 1] == '\n')
948 if ((size == 1 && *line == '.') ||
949 (size == 2 && memcmp(line, ".+", 2) == 0))
951 if (size >= 2 && memcmp(line, "..", 2) == 0) {
956 nbytes = stream_write(to, "\n", 1);
960 stream_write(to, line, size);
961 line = stream_getln(up->rd, &size);
966 return (UPDATER_ERR_READ);
968 if (size == 1 && *line == '.') {
969 nbytes = stream_write(to, "\n", 1);
974 /* Get the checksum line. */
975 line = stream_getln(up->rd, NULL);
977 return (UPDATER_ERR_READ);
978 cmd = proto_get_ascii(&line);
979 fup->wantmd5 = proto_get_ascii(&line);
980 if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
981 return (UPDATER_ERR_PROTO);
982 error = updater_updatefile(up, fup, md5, isfixup);
983 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
988 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
990 return (UPDATER_ERR_MSG);
994 * Remove all empty directories below file.
995 * This function will trash the path passed to it.
998 updater_prunedirs(char *base, char *file)
1003 while ((cp = strrchr(file, '/')) != NULL) {
1005 if (strcmp(base, file) == 0)
1007 error = rmdir(file);