Deleted Added
full compact
updater.c (156230) updater.c (156701)
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 unchanged lines hidden (view full) ---

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 *
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 unchanged lines hidden (view full) ---

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: vendor/csup/dist/contrib/csup/updater.c 156230 2006-03-03 04:11:29Z mux $
26 * $FreeBSD: vendor/csup/dist/contrib/csup/updater.c 156701 2006-03-14 03:51:13Z mux $
27 */
28
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include <assert.h>
33#include <errno.h>
34#include <fcntl.h>

--- 14 unchanged lines hidden (view full) ---

49#include "proto.h"
50#include "status.h"
51#include "stream.h"
52
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. */
27 */
28
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include <assert.h>
33#include <errno.h>
34#include <fcntl.h>

--- 14 unchanged lines hidden (view full) ---

49#include "proto.h"
50#include "status.h"
51#include "stream.h"
52
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. */
57
58/* Everything needed to update a file. */
59struct file_update {
60 struct statusrec srbuf;
61 char *destpath;
58
59/* Everything needed to update a file. */
60struct file_update {
61 struct statusrec srbuf;
62 char *destpath;
63 char *temppath;
62 char *coname; /* Points somewhere in destpath. */
63 char *wantmd5;
64 struct coll *coll;
65 struct status *st;
66 /* Those are only used for diff updating. */
67 char *author;
68 struct stream *orig;
69 struct stream *to;
70 int expand;
71};
72
73struct updater {
74 struct config *config;
75 struct stream *rd;
76 char *errmsg;
64 char *coname; /* Points somewhere in destpath. */
65 char *wantmd5;
66 struct coll *coll;
67 struct status *st;
68 /* Those are only used for diff updating. */
69 char *author;
70 struct stream *orig;
71 struct stream *to;
72 int expand;
73};
74
75struct updater {
76 struct config *config;
77 struct stream *rd;
78 char *errmsg;
79 int deletecount;
77};
78
79static struct file_update *fup_new(struct coll *, struct status *);
80static int fup_prepare(struct file_update *, char *);
81static void fup_cleanup(struct file_update *);
82static void fup_free(struct file_update *);
83
84static void updater_prunedirs(char *, char *);
85static int updater_batch(struct updater *, int);
86static int updater_docoll(struct updater *, struct file_update *, int);
80};
81
82static struct file_update *fup_new(struct coll *, struct status *);
83static int fup_prepare(struct file_update *, char *);
84static void fup_cleanup(struct file_update *);
85static void fup_free(struct file_update *);
86
87static void updater_prunedirs(char *, char *);
88static int updater_batch(struct updater *, int);
89static int updater_docoll(struct updater *, struct file_update *, int);
87static void updater_delete(struct file_update *);
90static int updater_delete(struct updater *, struct file_update *);
91static void updater_deletefile(const char *);
88static int updater_checkout(struct updater *, struct file_update *, int);
89static int updater_setattrs(struct updater *, struct file_update *,
90 char *, char *, char *, char *, char *, struct fattr *);
92static int updater_checkout(struct updater *, struct file_update *, int);
93static int updater_setattrs(struct updater *, struct file_update *,
94 char *, char *, char *, char *, char *, struct fattr *);
91static void updater_checkmd5(struct updater *, struct file_update *,
92 const char *, int);
93static int updater_updatefile(struct updater *, struct file_update *fup,
95static int updater_updatefile(struct updater *, struct file_update *fup,
94 const char *, const char *);
96 const char *, int);
95static int updater_diff(struct updater *, struct file_update *);
96static int updater_diff_batch(struct updater *, struct file_update *);
97static int updater_diff_apply(struct updater *, struct file_update *,
98 char *);
99
100static struct file_update *
101fup_new(struct coll *coll, struct status *st)
102{

--- 26 unchanged lines hidden (view full) ---

129 struct statusrec *sr;
130
131 sr = &fup->srbuf;
132
133 if (fup->destpath != NULL) {
134 free(fup->destpath);
135 fup->destpath = NULL;
136 }
97static int updater_diff(struct updater *, struct file_update *);
98static int updater_diff_batch(struct updater *, struct file_update *);
99static int updater_diff_apply(struct updater *, struct file_update *,
100 char *);
101
102static struct file_update *
103fup_new(struct coll *coll, struct status *st)
104{

--- 26 unchanged lines hidden (view full) ---

131 struct statusrec *sr;
132
133 sr = &fup->srbuf;
134
135 if (fup->destpath != NULL) {
136 free(fup->destpath);
137 fup->destpath = NULL;
138 }
139 if (fup->temppath != NULL) {
140 free(fup->temppath);
141 fup->temppath = NULL;
142 }
137 fup->coname = NULL;
138 if (fup->author != NULL) {
139 free(fup->author);
140 fup->author = NULL;
141 }
142 fup->expand = 0;
143 if (fup->wantmd5 != NULL) {
144 free(fup->wantmd5);

--- 38 unchanged lines hidden (view full) ---

183 int error;
184
185 args = arg;
186
187 up = &upbuf;
188 up->config = args->config;
189 up->rd = args->rd;
190 up->errmsg = NULL;
143 fup->coname = NULL;
144 if (fup->author != NULL) {
145 free(fup->author);
146 fup->author = NULL;
147 }
148 fup->expand = 0;
149 if (fup->wantmd5 != NULL) {
150 free(fup->wantmd5);

--- 38 unchanged lines hidden (view full) ---

189 int error;
190
191 args = arg;
192
193 up = &upbuf;
194 up->config = args->config;
195 up->rd = args->rd;
196 up->errmsg = NULL;
197 up->deletecount = 0;
191
192 error = updater_batch(up, 0);
193
194 /*
195 * Make sure to close the fixups even in case of an error,
196 * so that the lister thread doesn't block indefinitely.
197 */
198 fixups_close(up->config->fixups);

--- 14 unchanged lines hidden (view full) ---

213 xasprintf(&args->errmsg, "Updater failed: "
214 "Premature EOF from server");
215 } else {
216 xasprintf(&args->errmsg, "Updater failed: "
217 "Network read failure: %s", strerror(errno));
218 }
219 args->status = STATUS_TRANSIENTFAILURE;
220 break;
198
199 error = updater_batch(up, 0);
200
201 /*
202 * Make sure to close the fixups even in case of an error,
203 * so that the lister thread doesn't block indefinitely.
204 */
205 fixups_close(up->config->fixups);

--- 14 unchanged lines hidden (view full) ---

220 xasprintf(&args->errmsg, "Updater failed: "
221 "Premature EOF from server");
222 } else {
223 xasprintf(&args->errmsg, "Updater failed: "
224 "Network read failure: %s", strerror(errno));
225 }
226 args->status = STATUS_TRANSIENTFAILURE;
227 break;
228 case UPDATER_ERR_DELETELIM:
229 xasprintf(&args->errmsg, "Updater failed: "
230 "File deletion limit exceeded");
231 args->status = STATUS_FAILURE;
232 break;
221 default:
222 assert(error == 0);
223 args->status = STATUS_SUCCESS;
224 };
225 return (NULL);
226}
227
228static int

--- 27 unchanged lines hidden (view full) ---

256 if (!isfixups)
257 lprintf(1, "Updating collection %s/%s\n", coll->co_name,
258 coll->co_release);
259
260 if (coll->co_options & CO_COMPRESS)
261 stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
262
263 st = status_open(coll, coll->co_scantime, &errmsg);
233 default:
234 assert(error == 0);
235 args->status = STATUS_SUCCESS;
236 };
237 return (NULL);
238}
239
240static int

--- 27 unchanged lines hidden (view full) ---

268 if (!isfixups)
269 lprintf(1, "Updating collection %s/%s\n", coll->co_name,
270 coll->co_release);
271
272 if (coll->co_options & CO_COMPRESS)
273 stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
274
275 st = status_open(coll, coll->co_scantime, &errmsg);
264 fup = fup_new(coll, st);
265 if (st == NULL) {
276 if (st == NULL) {
266 fup_free(fup);
267 up->errmsg = errmsg;
268 return (UPDATER_ERR_MSG);
269 }
277 up->errmsg = errmsg;
278 return (UPDATER_ERR_MSG);
279 }
280 fup = fup_new(coll, st);
270 error = updater_docoll(up, fup, isfixups);
271 status_close(st, &errmsg);
272 fup_free(fup);
273 if (errmsg != NULL) {
274 /* Discard previous error. */
275 if (up->errmsg != NULL)
276 free(up->errmsg);
277 up->errmsg = errmsg;

--- 77 unchanged lines hidden (view full) ---

355 return (UPDATER_ERR_PROTO);
356
357 error = fup_prepare(fup, name);
358 if (error)
359 return (UPDATER_ERR_PROTO);
360 /* Theoritically, the file does not exist on the client.
361 Just to make sure, we'll delete it here, if it
362 exists. */
281 error = updater_docoll(up, fup, isfixups);
282 status_close(st, &errmsg);
283 fup_free(fup);
284 if (errmsg != NULL) {
285 /* Discard previous error. */
286 if (up->errmsg != NULL)
287 free(up->errmsg);
288 up->errmsg = errmsg;

--- 77 unchanged lines hidden (view full) ---

366 return (UPDATER_ERR_PROTO);
367
368 error = fup_prepare(fup, name);
369 if (error)
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
373 exists. */
363 if (access(fup->destpath, F_OK) == 0)
364 updater_delete(fup);
374 if (access(fup->destpath, F_OK) == 0) {
375 error = updater_delete(up, fup);
376 if (error)
377 return (error);
378 }
365
366 sr = &srbuf;
367 sr->sr_type = SR_CHECKOUTDEAD;
368 sr->sr_file = name;
369 sr->sr_tag = tag;
370 sr->sr_date = date;
371 sr->sr_serverattr = fattr_decode(attr);
372 if (sr->sr_serverattr == NULL)

--- 32 unchanged lines hidden (view full) ---

405 fup->expand = keyword_decode_expand(expand);
406 if (fup->expand == -1)
407 return (UPDATER_ERR_PROTO);
408 error = fup_prepare(fup, name);
409 if (error)
410 return (UPDATER_ERR_PROTO);
411
412 fup->wantmd5 = xstrdup(wantmd5);
379
380 sr = &srbuf;
381 sr->sr_type = SR_CHECKOUTDEAD;
382 sr->sr_file = name;
383 sr->sr_tag = tag;
384 sr->sr_date = date;
385 sr->sr_serverattr = fattr_decode(attr);
386 if (sr->sr_serverattr == NULL)

--- 32 unchanged lines hidden (view full) ---

419 fup->expand = keyword_decode_expand(expand);
420 if (fup->expand == -1)
421 return (UPDATER_ERR_PROTO);
422 error = fup_prepare(fup, name);
423 if (error)
424 return (UPDATER_ERR_PROTO);
425
426 fup->wantmd5 = xstrdup(wantmd5);
427 fup->temppath = tempname(fup->destpath);
413 error = updater_diff(up, fup);
414 if (error)
415 return (error);
416 break;
417 case 'u':
418 /* Update dead checked-out file. */
419 name = proto_get_ascii(&line);
420 tag = proto_get_ascii(&line);
421 date = proto_get_ascii(&line);
422 attr = proto_get_ascii(&line);
423 if (attr == NULL || line != NULL)
424 return (UPDATER_ERR_PROTO);
425
426 error = fup_prepare(fup, name);
427 if (error)
428 return (UPDATER_ERR_PROTO);
428 error = updater_diff(up, fup);
429 if (error)
430 return (error);
431 break;
432 case 'u':
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);
440
441 error = fup_prepare(fup, name);
442 if (error)
443 return (UPDATER_ERR_PROTO);
429 updater_delete(fup);
444 error = updater_delete(up, fup);
445 if (error)
446 return (error);
430 sr = &srbuf;
431 sr->sr_type = SR_CHECKOUTDEAD;
432 sr->sr_file = name;
433 sr->sr_tag = tag;
434 sr->sr_date = date;
435 sr->sr_serverattr = fattr_decode(attr);
436 if (sr->sr_serverattr == NULL)
437 return (UPDATER_ERR_PROTO);

--- 35 unchanged lines hidden (view full) ---

473 tmp = fattr_forcheckout(sr->sr_serverattr,
474 coll->co_umask);
475 fattr_override(sr->sr_clientattr, tmp, FA_MASK);
476 fattr_free(tmp);
477 fattr_mergedefault(sr->sr_clientattr);
478 error = fup_prepare(fup, name);
479 if (error)
480 return (UPDATER_ERR_PROTO);
447 sr = &srbuf;
448 sr->sr_type = SR_CHECKOUTDEAD;
449 sr->sr_file = name;
450 sr->sr_tag = tag;
451 sr->sr_date = date;
452 sr->sr_serverattr = fattr_decode(attr);
453 if (sr->sr_serverattr == NULL)
454 return (UPDATER_ERR_PROTO);

--- 35 unchanged lines hidden (view full) ---

490 tmp = fattr_forcheckout(sr->sr_serverattr,
491 coll->co_umask);
492 fattr_override(sr->sr_clientattr, tmp, FA_MASK);
493 fattr_free(tmp);
494 fattr_mergedefault(sr->sr_clientattr);
495 error = fup_prepare(fup, name);
496 if (error)
497 return (UPDATER_ERR_PROTO);
498 fup->temppath = tempname(fup->destpath);
481 if (*cmd == 'Y')
482 error = updater_checkout(up, fup, 1);
483 else
484 error = updater_checkout(up, fup, 0);
485 if (error)
486 return (error);
487 break;
488 case 'D':
489 /* Delete file. */
490 name = proto_get_ascii(&line);
491 if (name == NULL || line != NULL)
492 return (UPDATER_ERR_PROTO);
493 error = fup_prepare(fup, name);
494 if (error)
495 return (UPDATER_ERR_PROTO);
499 if (*cmd == 'Y')
500 error = updater_checkout(up, fup, 1);
501 else
502 error = updater_checkout(up, fup, 0);
503 if (error)
504 return (error);
505 break;
506 case 'D':
507 /* Delete file. */
508 name = proto_get_ascii(&line);
509 if (name == NULL || line != NULL)
510 return (UPDATER_ERR_PROTO);
511 error = fup_prepare(fup, name);
512 if (error)
513 return (UPDATER_ERR_PROTO);
496 updater_delete(fup);
514 error = updater_delete(up, fup);
515 if (error)
516 return (error);
497 error = status_delete(fup->st, name, 0);
498 if (error) {
499 up->errmsg = status_errmsg(fup->st);
500 return (UPDATER_ERR_MSG);
501 }
502 break;
503 case '!':
504 /* Warning from server. */

--- 8 unchanged lines hidden (view full) ---

513 fup_cleanup(fup);
514 }
515 if (line == NULL)
516 return (UPDATER_ERR_READ);
517 return (0);
518}
519
520/* Delete file. */
517 error = status_delete(fup->st, name, 0);
518 if (error) {
519 up->errmsg = status_errmsg(fup->st);
520 return (UPDATER_ERR_MSG);
521 }
522 break;
523 case '!':
524 /* Warning from server. */

--- 8 unchanged lines hidden (view full) ---

533 fup_cleanup(fup);
534 }
535 if (line == NULL)
536 return (UPDATER_ERR_READ);
537 return (0);
538}
539
540/* Delete file. */
521static void
522updater_delete(struct file_update *fup)
541static int
542updater_delete(struct updater *up, struct file_update *fup)
523{
543{
544 struct config *config;
524 struct coll *coll;
545 struct coll *coll;
525 int error;
526
546
527 /* XXX - delete limit handling */
547 config = up->config;
528 coll = fup->coll;
529 if (coll->co_options & CO_DELETE) {
530 lprintf(1, " Delete %s\n", fup->coname);
548 coll = fup->coll;
549 if (coll->co_options & CO_DELETE) {
550 lprintf(1, " Delete %s\n", fup->coname);
531 error = fattr_delete(fup->destpath);
532 if (error) {
533 lprintf(-1, "Cannot delete \"%s\": %s\n",
534 fup->destpath, strerror(errno));
535 return;
536 }
551 if (config->deletelim >= 0 &&
552 up->deletecount >= config->deletelim)
553 return (UPDATER_ERR_DELETELIM);
554 up->deletecount++;
555 updater_deletefile(fup->destpath);
537 if (coll->co_options & CO_CHECKOUTMODE)
538 updater_prunedirs(coll->co_prefix, fup->destpath);
539 } else {
540 lprintf(1," NoDelete %s\n", fup->coname);
541 }
556 if (coll->co_options & CO_CHECKOUTMODE)
557 updater_prunedirs(coll->co_prefix, fup->destpath);
558 } else {
559 lprintf(1," NoDelete %s\n", fup->coname);
560 }
561 return (0);
542}
543
562}
563
564static void
565updater_deletefile(const char *path)
566{
567 int error;
568
569 error = fattr_delete(path);
570 if (error && errno != ENOENT) {
571 lprintf(-1, "Cannot delete \"%s\": %s\n",
572 path, strerror(errno));
573 }
574}
575
544static int
545updater_setattrs(struct updater *up, struct file_update *fup, char *name,
546 char *tag, char *date, char *revnum, char *revdate, struct fattr *rcsattr)
547{
548 struct statusrec sr;
549 struct status *st;
550 struct coll *coll;
551 struct fattr *fileattr, *fa;

--- 56 unchanged lines hidden (view full) ---

608 fattr_free(fileattr);
609 if (error) {
610 up->errmsg = status_errmsg(st);
611 return (UPDATER_ERR_MSG);
612 }
613 return (0);
614}
615
576static int
577updater_setattrs(struct updater *up, struct file_update *fup, char *name,
578 char *tag, char *date, char *revnum, char *revdate, struct fattr *rcsattr)
579{
580 struct statusrec sr;
581 struct status *st;
582 struct coll *coll;
583 struct fattr *fileattr, *fa;

--- 56 unchanged lines hidden (view full) ---

640 fattr_free(fileattr);
641 if (error) {
642 up->errmsg = status_errmsg(st);
643 return (UPDATER_ERR_MSG);
644 }
645 return (0);
646}
647
616/*
617 * Check that the file we created/updated has a correct MD5 checksum.
618 * If it doesn't and that this is not a fixup update, add a fixup
619 * request to checkout the whole file. If it's already a fixup update,
620 * we just fail.
621 */
622static void
623updater_checkmd5(struct updater *up, struct file_update *fup, const char *md5,
624 int isfixup)
625{
626 struct statusrec *sr;
627
628 sr = &fup->srbuf;
629 if (strcmp(fup->wantmd5, md5) == 0)
630 return;
631 if (isfixup) {
632 lprintf(-1, "%s: Checksum mismatch -- file not updated\n",
633 fup->destpath);
634 return;
635 }
636 lprintf(-1, "%s: Checksum mismatch -- will transfer entire file\n",
637 fup->destpath);
638 fixups_put(up->config->fixups, fup->coll, sr->sr_file);
639}
640
641static int
648static int
642updater_updatefile(struct updater *up, struct file_update *fup, const char *to,
643 const char *from)
649updater_updatefile(struct updater *up, struct file_update *fup,
650 const char *md5, int isfixup)
644{
645 struct coll *coll;
646 struct status *st;
647 struct statusrec *sr;
648 struct fattr *fileattr;
649 int error, rv;
650
651 coll = fup->coll;
652 sr = &fup->srbuf;
653 st = fup->st;
654
651{
652 struct coll *coll;
653 struct status *st;
654 struct statusrec *sr;
655 struct fattr *fileattr;
656 int error, rv;
657
658 coll = fup->coll;
659 sr = &fup->srbuf;
660 st = fup->st;
661
662 if (strcmp(fup->wantmd5, md5) != 0) {
663 if (isfixup) {
664 lprintf(-1, "%s: Checksum mismatch -- "
665 "file not updated\n", fup->destpath);
666 } else {
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);
670 }
671 if (coll->co_options & CO_KEEPBADFILES)
672 lprintf(-1, "Bad version saved in %s\n", fup->temppath);
673 else
674 updater_deletefile(fup->temppath);
675 return (0);
676 }
677
655 fattr_umask(sr->sr_clientattr, coll->co_umask);
678 fattr_umask(sr->sr_clientattr, coll->co_umask);
656 rv = fattr_install(sr->sr_clientattr, to, from);
679 rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath);
657 if (rv == -1) {
680 if (rv == -1) {
658 if (from == NULL)
659 xasprintf(&up->errmsg, "Cannot install \"%s\": %s",
660 to, strerror(errno));
661 else
662 xasprintf(&up->errmsg,
663 "Cannot install \"%s\" to \"%s\": %s",
664 from, to, strerror(errno));
681 xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
682 fup->temppath, fup->destpath, strerror(errno));
665 return (UPDATER_ERR_MSG);
666 }
667
668 /* XXX Executes */
669 /*
670 * We weren't necessarily able to set all the file attributes to the
671 * desired values, and any executes may have altered the attributes.
672 * To make sure we record the actual attribute values, we fetch
673 * them from the file.
674 *
675 * However, we preserve the link count as received from the
676 * server. This is important for preserving hard links in mirror
677 * mode.
678 */
683 return (UPDATER_ERR_MSG);
684 }
685
686 /* XXX Executes */
687 /*
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.
692 *
693 * However, we preserve the link count as received from the
694 * server. This is important for preserving hard links in mirror
695 * mode.
696 */
679 fileattr = fattr_frompath(to, FATTR_NOFOLLOW);
697 fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
680 if (fileattr == NULL) {
698 if (fileattr == NULL) {
681 xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", to,
699 xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
682 strerror(errno));
683 return (UPDATER_ERR_MSG);
684 }
685 fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
686 fattr_free(sr->sr_clientattr);
687 sr->sr_clientattr = fileattr;
688
689 /*

--- 20 unchanged lines hidden (view full) ---

710static int
711updater_diff(struct updater *up, struct file_update *fup)
712{
713 char md5[MD5_DIGEST_SIZE];
714 struct coll *coll;
715 struct statusrec *sr;
716 struct fattr *fa, *tmp;
717 char *author, *path, *revnum, *revdate;
700 strerror(errno));
701 return (UPDATER_ERR_MSG);
702 }
703 fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
704 fattr_free(sr->sr_clientattr);
705 sr->sr_clientattr = fileattr;
706
707 /*

--- 20 unchanged lines hidden (view full) ---

728static int
729updater_diff(struct updater *up, struct file_update *fup)
730{
731 char md5[MD5_DIGEST_SIZE];
732 struct coll *coll;
733 struct statusrec *sr;
734 struct fattr *fa, *tmp;
735 char *author, *path, *revnum, *revdate;
718 char *line, *cmd, *temppath;
736 char *line, *cmd;
719 int error;
720
737 int error;
738
721 temppath = NULL;
722 coll = fup->coll;
723 sr = &fup->srbuf;
724 path = fup->destpath;
725
726 lprintf(1, " Edit %s\n", fup->coname);
727 while ((line = stream_getln(up->rd, NULL)) != NULL) {
728 if (strcmp(line, ".") == 0)
729 break;
730 cmd = proto_get_ascii(&line);
739 coll = fup->coll;
740 sr = &fup->srbuf;
741 path = fup->destpath;
742
743 lprintf(1, " Edit %s\n", fup->coname);
744 while ((line = stream_getln(up->rd, NULL)) != NULL) {
745 if (strcmp(line, ".") == 0)
746 break;
747 cmd = proto_get_ascii(&line);
731 if (cmd == NULL || strcmp(cmd, "D") != 0) {
732 error = UPDATER_ERR_PROTO;
733 goto bad;
734 }
748 if (cmd == NULL || strcmp(cmd, "D") != 0)
749 return (UPDATER_ERR_PROTO);
735 revnum = proto_get_ascii(&line);
736 proto_get_ascii(&line); /* XXX - diffbase */
737 revdate = proto_get_ascii(&line);
738 author = proto_get_ascii(&line);
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);
739 if (author == NULL || line != NULL) {
740 error = UPDATER_ERR_PROTO;
741 goto bad;
742 }
754 if (author == NULL || line != NULL)
755 return (UPDATER_ERR_PROTO);
743 if (sr->sr_revnum != NULL)
744 free(sr->sr_revnum);
745 if (sr->sr_revdate != NULL)
746 free(sr->sr_revdate);
747 if (fup->author != NULL)
748 free(fup->author);
749 sr->sr_revnum = xstrdup(revnum);
750 sr->sr_revdate = xstrdup(revdate);
751 fup->author = xstrdup(author);
752 if (fup->orig == NULL) {
753 /* First patch, the "origin" file is the one we have. */
754 fup->orig = stream_open_file(path, O_RDONLY);
755 if (fup->orig == NULL) {
756 xasprintf(&up->errmsg, "%s: Cannot open: %s",
757 path, strerror(errno));
756 if (sr->sr_revnum != NULL)
757 free(sr->sr_revnum);
758 if (sr->sr_revdate != NULL)
759 free(sr->sr_revdate);
760 if (fup->author != NULL)
761 free(fup->author);
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));
758 error = UPDATER_ERR_MSG;
759 goto bad;
771 return (UPDATER_ERR_MSG);
760 }
761 } else {
762 /* Subsequent patches. */
763 stream_close(fup->orig);
764 fup->orig = fup->to;
765 stream_rewind(fup->orig);
772 }
773 } else {
774 /* Subsequent patches. */
775 stream_close(fup->orig);
776 fup->orig = fup->to;
777 stream_rewind(fup->orig);
766 unlink(temppath);
767 free(temppath);
778 unlink(fup->temppath);
779 free(fup->temppath);
780 fup->temppath = tempname(path);
768 }
781 }
769 temppath = tempname(path);
770 fup->to = stream_open_file(temppath,
771 O_RDWR | O_CREAT | O_EXCL, 0600);
782 fup->to = stream_open_file(fup->temppath,
783 O_RDWR | O_CREAT | O_TRUNC, 0600);
772 if (fup->to == NULL) {
773 xasprintf(&up->errmsg, "%s: Cannot open: %s",
784 if (fup->to == NULL) {
785 xasprintf(&up->errmsg, "%s: Cannot open: %s",
774 temppath, strerror(errno));
775 error = UPDATER_ERR_MSG;
776 goto bad;
786 fup->temppath, strerror(errno));
787 return (UPDATER_ERR_MSG);
777 }
778 lprintf(2, " Add delta %s %s %s\n", sr->sr_revnum,
779 sr->sr_revdate, fup->author);
780 error = updater_diff_batch(up, fup);
781 if (error)
788 }
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);
792 if (error)
782 goto bad;
793 return (error);
783 }
794 }
784 if (line == NULL) {
785 error = UPDATER_ERR_READ;
786 goto bad;
787 }
795 if (line == NULL)
796 return (UPDATER_ERR_READ);
788
789 fa = fattr_frompath(path, FATTR_FOLLOW);
790 tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask);
791 fattr_override(fa, tmp, FA_MASK);
792 fattr_free(tmp);
793 fattr_maskout(fa, FA_MODTIME);
794 sr->sr_clientattr = fa;
795
797
798 fa = fattr_frompath(path, FATTR_FOLLOW);
799 tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask);
800 fattr_override(fa, tmp, FA_MASK);
801 fattr_free(tmp);
802 fattr_maskout(fa, FA_MODTIME);
803 sr->sr_clientattr = fa;
804
796 error = updater_updatefile(up, fup, path, temppath);
797 if (error)
798 goto bad;
799
800 if (MD5_File(path, md5) == -1) {
805 if (MD5_File(fup->temppath, md5) == -1) {
801 xasprintf(&up->errmsg,
802 "Cannot calculate checksum for \"%s\": %s",
803 path, strerror(errno));
806 xasprintf(&up->errmsg,
807 "Cannot calculate checksum for \"%s\": %s",
808 path, strerror(errno));
804 error = UPDATER_ERR_MSG;
805 goto bad;
809 return (UPDATER_ERR_MSG);
806 }
810 }
807 updater_checkmd5(up, fup, md5, 0);
808 free(temppath);
809 return (0);
810bad:
811 assert(error);
812 if (temppath != NULL)
813 free(temppath);
811 error = updater_updatefile(up, fup, md5, 0);
814 return (error);
815}
816
817static int
818updater_diff_batch(struct updater *up, struct file_update *fup)
819{
820 struct stream *rd;
821 char *cmd, *line, *state, *tok;

--- 107 unchanged lines hidden (view full) ---

929 error = mkdirhier(path, coll->co_umask);
930 if (error) {
931 xasprintf(&up->errmsg,
932 "Cannot create directories leading to \"%s\": %s",
933 path, strerror(errno));
934 return (UPDATER_ERR_MSG);
935 }
936
812 return (error);
813}
814
815static int
816updater_diff_batch(struct updater *up, struct file_update *fup)
817{
818 struct stream *rd;
819 char *cmd, *line, *state, *tok;

--- 107 unchanged lines hidden (view full) ---

927 error = mkdirhier(path, coll->co_umask);
928 if (error) {
929 xasprintf(&up->errmsg,
930 "Cannot create directories leading to \"%s\": %s",
931 path, strerror(errno));
932 return (UPDATER_ERR_MSG);
933 }
934
937 to = stream_open_file(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
935 to = stream_open_file(fup->temppath,
936 O_WRONLY | O_CREAT | O_TRUNC, 0600);
938 if (to == NULL) {
939 xasprintf(&up->errmsg, "%s: Cannot create: %s",
937 if (to == NULL) {
938 xasprintf(&up->errmsg, "%s: Cannot create: %s",
940 path, strerror(errno));
939 fup->temppath, strerror(errno));
941 return (UPDATER_ERR_MSG);
942 }
943 stream_filter_start(to, STREAM_FILTER_MD5, md5);
944 line = stream_getln(up->rd, &size);
945 first = 1;
946 while (line != NULL) {
947 if (line[size - 1] == '\n')
948 size--;

--- 26 unchanged lines hidden (view full) ---

975 /* Get the checksum line. */
976 line = stream_getln(up->rd, NULL);
977 if (line == NULL)
978 return (UPDATER_ERR_READ);
979 cmd = proto_get_ascii(&line);
980 fup->wantmd5 = proto_get_ascii(&line);
981 if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
982 return (UPDATER_ERR_PROTO);
940 return (UPDATER_ERR_MSG);
941 }
942 stream_filter_start(to, STREAM_FILTER_MD5, md5);
943 line = stream_getln(up->rd, &size);
944 first = 1;
945 while (line != NULL) {
946 if (line[size - 1] == '\n')
947 size--;

--- 26 unchanged lines hidden (view full) ---

974 /* Get the checksum line. */
975 line = stream_getln(up->rd, NULL);
976 if (line == 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);
983 updater_checkmd5(up, fup, md5, isfixup);
982 error = updater_updatefile(up, fup, md5, isfixup);
984 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
983 fup->wantmd5 = NULL; /* So that it doesn't get freed. */
985 error = updater_updatefile(up, fup, path, NULL);
986 if (error)
987 return (error);
988 return (0);
989bad:
984 if (error)
985 return (error);
986 return (0);
987bad:
990 xasprintf(&up->errmsg, "%s: Cannot write: %s", path, strerror(errno));
988 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
989 strerror(errno));
991 return (UPDATER_ERR_MSG);
992}
993
994/*
995 * Remove all empty directories below file.
996 * This function will trash the path passed to it.
997 */
998static void

--- 14 unchanged lines hidden ---
990 return (UPDATER_ERR_MSG);
991}
992
993/*
994 * Remove all empty directories below file.
995 * This function will trash the path passed to it.
996 */
997static void

--- 14 unchanged lines hidden ---