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. */ 64struct 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 81struct updater { 82 struct config *config; 83 struct stream *rd; 84 char *errmsg; 85 int deletecount; 86}; 87 88static struct file_update *fup_new(struct coll *, struct status *); 89static int fup_prepare(struct file_update *, char *, int); 90static void fup_cleanup(struct file_update *); 91static void fup_free(struct file_update *); 92 93static void updater_prunedirs(char *, char *); 94static int updater_batch(struct updater *, int); 95static int updater_docoll(struct updater *, struct file_update *, int); 96static int updater_delete(struct updater *, struct file_update *); 97static void updater_deletefile(const char *); 98static int updater_checkout(struct updater *, struct file_update *, int); 99static int updater_addfile(struct updater *, struct file_update *, 100 char *, int); 101int updater_addelta(struct rcsfile *, struct stream *, char *); 102static int updater_setattrs(struct updater *, struct file_update *, 103 char *, char *, char *, char *, char *, struct fattr *); 104static int updater_setdirattrs(struct updater *, struct coll *, 105 struct file_update *, char *, char *); 106static int updater_updatefile(struct updater *, struct file_update *fup, 107 const char *, int); 108static int updater_updatenode(struct updater *, struct coll *, 109 struct file_update *, char *, char *); 110static int updater_diff(struct updater *, struct file_update *); 111static int updater_diff_batch(struct updater *, struct file_update *); 112static int updater_diff_apply(struct updater *, struct file_update *, 113 char *); 114static int updater_rcsedit(struct updater *, struct file_update *, char *, 115 char *); 116int updater_append_file(struct updater *, struct file_update *, 117 off_t); 118static int updater_rsync(struct updater *, struct file_update *, size_t); 119static int updater_read_checkout(struct stream *, struct stream *); 120 121static struct file_update * 122fup_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 133static int 134fup_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. */ 162static void 163fup_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 214static void 215fup_free(struct file_update *fup) 216{ 217 218 fup_cleanup(fup); 219 free(fup); 220} 221 222void * 223updater(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 278static int 279updater_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 343static int 344updater_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. */ 839static int 840updater_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 862static void 863updater_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 874static int 875updater_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 946static int 947updater_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 */ 1029static int 1030updater_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 1075static int 1076updater_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 */ 1165static int 1166updater_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); 1221bad: 1222 if (state != NULL) 1223 free(state); 1224 return (error); 1225} 1226 1227int 1228updater_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. */ 1258static int 1259updater_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 */ 1352static int 1353updater_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); 1417bad: 1418 xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath, 1419 strerror(errno)); 1420 return (UPDATER_ERR_MSG); 1421} 1422 1423static int 1424updater_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); 1505bad: 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 */ 1515static void 1516updater_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 */ 1534static int 1535updater_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 1697finish: 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 */ 1736int 1737updater_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 1825int 1826updater_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); 1902bad: 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 */ 1912static int 1913updater_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. */ 1954static int 1955updater_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. */ 2040bad: 2041 free(buf); 2042 return (error); 2043} 2044