1 /* $OpenBSD: uploader.c,v 1.29 2021/06/30 13:10:04 claudio Exp $ */ 2 /* 3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2019 Florian Obser <florian@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include <sys/mman.h> 19 #include <sys/stat.h> 20 21 #include <assert.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <inttypes.h> 25 #include <math.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <time.h> 30 #include <unistd.h> 31 32 #include "extern.h" 33 34 enum uploadst { 35 UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */ 36 UPLOAD_WRITE, /* wait to write to sender */ 37 UPLOAD_FINISHED /* nothing more to do in phase */ 38 }; 39 40 /* 41 * Used to keep track of data flowing from the receiver to the sender. 42 * This is managed by the receiver process. 43 */ 44 struct upload { 45 enum uploadst state; 46 char *buf; /* if not NULL, pending upload */ 47 size_t bufsz; /* size of buf */ 48 size_t bufmax; /* maximum size of buf */ 49 size_t bufpos; /* position in buf */ 50 size_t idx; /* current transfer index */ 51 mode_t oumask; /* umask for creating files */ 52 char *root; /* destination directory path */ 53 int rootfd; /* destination directory */ 54 size_t csumlen; /* checksum length */ 55 int fdout; /* write descriptor to sender */ 56 const struct flist *fl; /* file list */ 57 size_t flsz; /* size of file list */ 58 int *newdir; /* non-zero if mkdir'd */ 59 }; 60 61 /* 62 * Log a directory by emitting the file and a trailing slash, just to 63 * show the operator that we're a directory. 64 */ 65 static void 66 log_dir(struct sess *sess, const struct flist *f) 67 { 68 size_t sz; 69 70 if (sess->opts->server) 71 return; 72 sz = strlen(f->path); 73 assert(sz > 0); 74 LOG1("%s%s", f->path, (f->path[sz - 1] == '/') ? "" : "/"); 75 } 76 77 /* 78 * Log a link by emitting the file and the target, just to show the 79 * operator that we're a link. 80 */ 81 static void 82 log_symlink(struct sess *sess, const struct flist *f) 83 { 84 85 if (!sess->opts->server) 86 LOG1("%s -> %s", f->path, f->link); 87 } 88 89 /* 90 * Simply log the filename. 91 */ 92 static void 93 log_file(struct sess *sess, const struct flist *f) 94 { 95 96 if (!sess->opts->server) 97 LOG1("%s", f->path); 98 } 99 100 /* 101 * Prepare the overall block set's metadata. 102 * We always have at least one block. 103 * The block size is an important part of the algorithm. 104 * I use the same heuristic as the reference rsync, but implemented in a 105 * bit more of a straightforward way. 106 * In general, the individual block length is the rounded square root of 107 * the total file size. 108 * The minimum block length is 700. 109 */ 110 static void 111 init_blkset(struct blkset *p, off_t sz) 112 { 113 double v; 114 115 if (sz >= (BLOCK_SIZE_MIN * BLOCK_SIZE_MIN)) { 116 /* Simple rounded-up integer square root. */ 117 118 v = sqrt(sz); 119 p->len = ceil(v); 120 121 /* 122 * Always be a multiple of eight. 123 * There's no reason to do this, but rsync does. 124 */ 125 126 if ((p->len % 8) > 0) 127 p->len += 8 - (p->len % 8); 128 } else 129 p->len = BLOCK_SIZE_MIN; 130 131 p->size = sz; 132 if ((p->blksz = sz / p->len) == 0) 133 p->rem = sz; 134 else 135 p->rem = sz % p->len; 136 137 /* If we have a remainder, then we need an extra block. */ 138 139 if (p->rem) 140 p->blksz++; 141 } 142 143 /* 144 * For each block, prepare the block's metadata. 145 * We use the mapped "map" file to set our checksums. 146 */ 147 static void 148 init_blk(struct blk *p, const struct blkset *set, off_t offs, 149 size_t idx, const void *map, const struct sess *sess) 150 { 151 152 p->idx = idx; 153 /* Block length inherits for all but the last. */ 154 p->len = idx < set->blksz - 1 ? set->len : set->rem; 155 p->offs = offs; 156 157 p->chksum_short = hash_fast(map, p->len); 158 hash_slow(map, p->len, p->chksum_long, sess); 159 } 160 161 /* 162 * Handle a symbolic link. 163 * If we encounter directories existing in the symbolic link's place, 164 * then try to unlink the directory. 165 * Otherwise, simply overwrite with the symbolic link by renaming. 166 * Return <0 on failure 0 on success. 167 */ 168 static int 169 pre_link(struct upload *p, struct sess *sess) 170 { 171 struct stat st; 172 const struct flist *f; 173 int rc, newlink = 0, updatelink = 0; 174 char *b, *temp = NULL; 175 176 f = &p->fl[p->idx]; 177 assert(S_ISLNK(f->st.mode)); 178 179 if (!sess->opts->preserve_links) { 180 WARNX("%s: ignoring symlink", f->path); 181 return 0; 182 } 183 if (sess->opts->dry_run) { 184 log_symlink(sess, f); 185 return 0; 186 } 187 188 /* 189 * See if the symlink already exists. 190 * If it's a directory, then try to unlink the directory prior 191 * to overwriting with a symbolic link. 192 * If it's a non-directory, we just overwrite it. 193 */ 194 195 assert(p->rootfd != -1); 196 rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); 197 198 if (rc == -1 && errno != ENOENT) { 199 ERR("%s: fstatat", f->path); 200 return -1; 201 } 202 if (rc != -1 && !S_ISLNK(st.st_mode)) { 203 if (S_ISDIR(st.st_mode) && 204 unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { 205 ERR("%s: unlinkat", f->path); 206 return -1; 207 } 208 rc = -1; 209 } 210 211 /* 212 * If the symbolic link already exists, then make sure that it 213 * points to the correct place. 214 */ 215 216 if (rc != -1) { 217 b = symlinkat_read(p->rootfd, f->path); 218 if (b == NULL) { 219 ERRX1("symlinkat_read"); 220 return -1; 221 } 222 if (strcmp(f->link, b)) { 223 free(b); 224 b = NULL; 225 LOG3("%s: updating symlink: %s", f->path, f->link); 226 updatelink = 1; 227 } 228 free(b); 229 b = NULL; 230 } 231 232 /* 233 * Create the temporary file as a symbolic link, then rename the 234 * temporary file as the real one, overwriting anything there. 235 */ 236 237 if (rc == -1 || updatelink) { 238 LOG3("%s: creating symlink: %s", f->path, f->link); 239 if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { 240 ERRX1("mktemplate"); 241 return -1; 242 } 243 if (mkstemplinkat(f->link, p->rootfd, temp) == NULL) { 244 ERR("mkstemplinkat"); 245 free(temp); 246 return -1; 247 } 248 newlink = 1; 249 } 250 251 rsync_set_metadata_at(sess, newlink, 252 p->rootfd, f, newlink ? temp : f->path); 253 254 if (newlink) { 255 if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { 256 ERR("%s: renameat %s", temp, f->path); 257 (void)unlinkat(p->rootfd, temp, 0); 258 free(temp); 259 return -1; 260 } 261 free(temp); 262 } 263 264 log_symlink(sess, f); 265 return 0; 266 } 267 268 /* 269 * See pre_link(), but for devices. 270 * FIXME: this is very similar to the other pre_xxx() functions. 271 * Return <0 on failure 0 on success. 272 */ 273 static int 274 pre_dev(struct upload *p, struct sess *sess) 275 { 276 struct stat st; 277 const struct flist *f; 278 int rc, newdev = 0, updatedev = 0; 279 char *temp = NULL; 280 281 f = &p->fl[p->idx]; 282 assert(S_ISBLK(f->st.mode) || S_ISCHR(f->st.mode)); 283 284 if (!sess->opts->devices || getuid() != 0) { 285 WARNX("skipping non-regular file %s", f->path); 286 return 0; 287 } 288 if (sess->opts->dry_run) { 289 log_file(sess, f); 290 return 0; 291 } 292 293 /* 294 * See if the dev already exists. 295 * If a non-device exists in its place, we'll replace that. 296 * If it replaces a directory, remove the directory first. 297 */ 298 299 assert(p->rootfd != -1); 300 rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); 301 302 if (rc == -1 && errno != ENOENT) { 303 ERR("%s: fstatat", f->path); 304 return -1; 305 } 306 if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) { 307 if (S_ISDIR(st.st_mode) && 308 unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { 309 ERR("%s: unlinkat", f->path); 310 return -1; 311 } 312 rc = -1; 313 } 314 315 /* Make sure existing device is of the correct type. */ 316 317 if (rc != -1) { 318 if ((f->st.mode & (S_IFCHR|S_IFBLK)) != 319 (st.st_mode & (S_IFCHR|S_IFBLK)) || 320 f->st.rdev != st.st_rdev) { 321 LOG3("%s: updating device", f->path); 322 updatedev = 1; 323 } 324 } 325 326 if (rc == -1 || updatedev) { 327 newdev = 1; 328 if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { 329 ERRX1("mktemplate"); 330 return -1; 331 } 332 if (mkstempnodat(p->rootfd, temp, 333 f->st.mode & (S_IFCHR|S_IFBLK), f->st.rdev) == NULL) { 334 ERR("mkstempnodat"); 335 free(temp); 336 return -1; 337 } 338 } 339 340 rsync_set_metadata_at(sess, newdev, 341 p->rootfd, f, newdev ? temp : f->path); 342 343 if (newdev) { 344 if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { 345 ERR("%s: renameat %s", temp, f->path); 346 (void)unlinkat(p->rootfd, temp, 0); 347 free(temp); 348 return -1; 349 } 350 free(temp); 351 } 352 353 log_file(sess, f); 354 return 0; 355 } 356 357 /* 358 * See pre_link(), but for FIFOs. 359 * FIXME: this is very similar to the other pre_xxx() functions. 360 * Return <0 on failure 0 on success. 361 */ 362 static int 363 pre_fifo(struct upload *p, struct sess *sess) 364 { 365 struct stat st; 366 const struct flist *f; 367 int rc, newfifo = 0; 368 char *temp = NULL; 369 370 f = &p->fl[p->idx]; 371 assert(S_ISFIFO(f->st.mode)); 372 373 if (!sess->opts->specials) { 374 WARNX("skipping non-regular file %s", f->path); 375 return 0; 376 } 377 if (sess->opts->dry_run) { 378 log_file(sess, f); 379 return 0; 380 } 381 382 /* 383 * See if the fifo already exists. 384 * If it exists as a non-FIFO, unlink it (if a directory) then 385 * mark it from replacement. 386 */ 387 388 assert(p->rootfd != -1); 389 rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); 390 391 if (rc == -1 && errno != ENOENT) { 392 ERR("%s: fstatat", f->path); 393 return -1; 394 } 395 if (rc != -1 && !S_ISFIFO(st.st_mode)) { 396 if (S_ISDIR(st.st_mode) && 397 unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { 398 ERR("%s: unlinkat", f->path); 399 return -1; 400 } 401 rc = -1; 402 } 403 404 if (rc == -1) { 405 newfifo = 1; 406 if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { 407 ERRX1("mktemplate"); 408 return -1; 409 } 410 if (mkstempfifoat(p->rootfd, temp) == NULL) { 411 ERR("mkstempfifoat"); 412 free(temp); 413 return -1; 414 } 415 } 416 417 rsync_set_metadata_at(sess, newfifo, 418 p->rootfd, f, newfifo ? temp : f->path); 419 420 if (newfifo) { 421 if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { 422 ERR("%s: renameat %s", temp, f->path); 423 (void)unlinkat(p->rootfd, temp, 0); 424 free(temp); 425 return -1; 426 } 427 free(temp); 428 } 429 430 log_file(sess, f); 431 return 0; 432 } 433 434 /* 435 * See pre_link(), but for socket files. 436 * FIXME: this is very similar to the other pre_xxx() functions. 437 * Return <0 on failure 0 on success. 438 */ 439 static int 440 pre_sock(struct upload *p, struct sess *sess) 441 { 442 struct stat st; 443 const struct flist *f; 444 int rc, newsock = 0; 445 char *temp = NULL; 446 447 f = &p->fl[p->idx]; 448 assert(S_ISSOCK(f->st.mode)); 449 450 if (!sess->opts->specials) { 451 WARNX("skipping non-regular file %s", f->path); 452 return 0; 453 } 454 if (sess->opts->dry_run) { 455 log_file(sess, f); 456 return 0; 457 } 458 459 /* 460 * See if the fifo already exists. 461 * If it exists as a non-FIFO, unlink it (if a directory) then 462 * mark it from replacement. 463 */ 464 465 assert(p->rootfd != -1); 466 rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); 467 468 if (rc == -1 && errno != ENOENT) { 469 ERR("%s: fstatat", f->path); 470 return -1; 471 } 472 if (rc != -1 && !S_ISSOCK(st.st_mode)) { 473 if (S_ISDIR(st.st_mode) && 474 unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { 475 ERR("%s: unlinkat", f->path); 476 return -1; 477 } 478 rc = -1; 479 } 480 481 if (rc == -1) { 482 newsock = 1; 483 if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { 484 ERRX1("mktemplate"); 485 return -1; 486 } 487 if (mkstempsock(p->root, temp) == NULL) { 488 ERR("mkstempsock"); 489 free(temp); 490 return -1; 491 } 492 } 493 494 rsync_set_metadata_at(sess, newsock, 495 p->rootfd, f, newsock ? temp : f->path); 496 497 if (newsock) { 498 if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { 499 ERR("%s: renameat %s", temp, f->path); 500 (void)unlinkat(p->rootfd, temp, 0); 501 free(temp); 502 return -1; 503 } 504 free(temp); 505 } 506 507 log_file(sess, f); 508 return 0; 509 } 510 511 /* 512 * If not found, create the destination directory in prefix order. 513 * Create directories using the existing umask. 514 * Return <0 on failure 0 on success. 515 */ 516 static int 517 pre_dir(const struct upload *p, struct sess *sess) 518 { 519 struct stat st; 520 int rc; 521 const struct flist *f; 522 523 f = &p->fl[p->idx]; 524 assert(S_ISDIR(f->st.mode)); 525 526 if (!sess->opts->recursive) { 527 WARNX("%s: ignoring directory", f->path); 528 return 0; 529 } 530 if (sess->opts->dry_run) { 531 log_dir(sess, f); 532 return 0; 533 } 534 535 assert(p->rootfd != -1); 536 rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); 537 538 if (rc == -1 && errno != ENOENT) { 539 ERR("%s: fstatat", f->path); 540 return -1; 541 } 542 if (rc != -1 && !S_ISDIR(st.st_mode)) { 543 ERRX("%s: not a directory", f->path); 544 return -1; 545 } else if (rc != -1) { 546 /* 547 * FIXME: we should fchmod the permissions here as well, 548 * as we may locally have shut down writing into the 549 * directory and that doesn't work. 550 */ 551 LOG3("%s: updating directory", f->path); 552 return 0; 553 } 554 555 /* 556 * We want to make the directory with default permissions (using 557 * our old umask, which we've since unset), then adjust 558 * permissions (assuming preserve_perms or new) afterward in 559 * case it's u-w or something. 560 */ 561 562 LOG3("%s: creating directory", f->path); 563 if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) { 564 ERR("%s: mkdirat", f->path); 565 return -1; 566 } 567 568 p->newdir[p->idx] = 1; 569 log_dir(sess, f); 570 return 0; 571 } 572 573 /* 574 * Process the directory time and mode for "idx" in the file list. 575 * Returns zero on failure, non-zero on success. 576 */ 577 static int 578 post_dir(struct sess *sess, const struct upload *u, size_t idx) 579 { 580 struct timespec tv[2]; 581 int rc; 582 struct stat st; 583 const struct flist *f; 584 585 f = &u->fl[idx]; 586 assert(S_ISDIR(f->st.mode)); 587 588 /* We already warned about the directory in pre_process_dir(). */ 589 590 if (!sess->opts->recursive) 591 return 1; 592 if (sess->opts->dry_run) 593 return 1; 594 595 if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) { 596 ERR("%s: fstatat", f->path); 597 return 0; 598 } 599 if (!S_ISDIR(st.st_mode)) { 600 WARNX("%s: not a directory", f->path); 601 return 0; 602 } 603 604 /* 605 * Update the modification time if we're a new directory *or* if 606 * we're preserving times and the time has changed. 607 * FIXME: run rsync_set_metadata()? 608 */ 609 610 if (u->newdir[idx] || 611 (sess->opts->preserve_times && 612 st.st_mtime != f->st.mtime)) { 613 tv[0].tv_sec = time(NULL); 614 tv[0].tv_nsec = 0; 615 tv[1].tv_sec = f->st.mtime; 616 tv[1].tv_nsec = 0; 617 rc = utimensat(u->rootfd, f->path, tv, 0); 618 if (rc == -1) { 619 ERR("%s: utimensat", f->path); 620 return 0; 621 } 622 LOG4("%s: updated date", f->path); 623 } 624 625 /* 626 * Update the mode if we're a new directory *or* if we're 627 * preserving modes and it has changed. 628 */ 629 630 if (u->newdir[idx] || 631 (sess->opts->preserve_perms && st.st_mode != f->st.mode)) { 632 rc = fchmodat(u->rootfd, f->path, f->st.mode, 0); 633 if (rc == -1) { 634 ERR("%s: fchmodat", f->path); 635 return 0; 636 } 637 LOG4("%s: updated mode", f->path); 638 } 639 640 return 1; 641 } 642 643 /* 644 * Try to open the file at the current index. 645 * If the file does not exist, returns with >0. 646 * Return <0 on failure, 0 on success w/nothing to be done, >0 on 647 * success and the file needs attention. 648 */ 649 static int 650 pre_file(const struct upload *p, int *filefd, struct stat *st, 651 struct sess *sess) 652 { 653 const struct flist *f; 654 int rc; 655 656 f = &p->fl[p->idx]; 657 assert(S_ISREG(f->st.mode)); 658 659 if (sess->opts->dry_run) { 660 log_file(sess, f); 661 if (!io_write_int(sess, p->fdout, p->idx)) { 662 ERRX1("io_write_int"); 663 return -1; 664 } 665 return 0; 666 } 667 668 /* 669 * For non dry-run cases, we'll write the acknowledgement later 670 * in the rsync_uploader() function. 671 */ 672 673 *filefd = -1; 674 rc = fstatat(p->rootfd, f->path, st, AT_SYMLINK_NOFOLLOW); 675 676 if (rc == -1) { 677 if (errno == ENOENT) 678 return 1; 679 680 ERR("%s: fstatat", f->path); 681 return -1; 682 } 683 if (!S_ISREG(st->st_mode)) { 684 if (S_ISDIR(st->st_mode) && 685 unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { 686 ERR("%s: unlinkat", f->path); 687 return -1; 688 } 689 return 1; 690 } 691 692 /* quick check if file is the same */ 693 if (st->st_size == f->st.size && 694 st->st_mtime == f->st.mtime) { 695 LOG3("%s: skipping: up to date", f->path); 696 if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) { 697 ERRX1("rsync_set_metadata"); 698 return -1; 699 } 700 return 0; 701 } 702 703 *filefd = openat(p->rootfd, f->path, O_RDONLY | O_NOFOLLOW, 0); 704 if (*filefd == -1 && errno != ENOENT) { 705 ERR("%s: openat", f->path); 706 return -1; 707 } 708 709 /* file needs attention */ 710 return 1; 711 } 712 713 /* 714 * Allocate an uploader object in the correct state to start. 715 * Returns NULL on failure or the pointer otherwise. 716 * On success, upload_free() must be called with the allocated pointer. 717 */ 718 struct upload * 719 upload_alloc(const char *root, int rootfd, int fdout, 720 size_t clen, const struct flist *fl, size_t flsz, mode_t msk) 721 { 722 struct upload *p; 723 724 if ((p = calloc(1, sizeof(struct upload))) == NULL) { 725 ERR("calloc"); 726 return NULL; 727 } 728 729 p->state = UPLOAD_FIND_NEXT; 730 p->oumask = msk; 731 p->root = strdup(root); 732 if (p->root == NULL) { 733 ERR("strdup"); 734 free(p); 735 return NULL; 736 } 737 p->rootfd = rootfd; 738 p->csumlen = clen; 739 p->fdout = fdout; 740 p->fl = fl; 741 p->flsz = flsz; 742 p->newdir = calloc(flsz, sizeof(int)); 743 if (p->newdir == NULL) { 744 ERR("calloc"); 745 free(p->root); 746 free(p); 747 return NULL; 748 } 749 return p; 750 } 751 752 /* 753 * Perform all cleanups and free. 754 * Passing a NULL to this function is ok. 755 */ 756 void 757 upload_free(struct upload *p) 758 { 759 760 if (p == NULL) 761 return; 762 free(p->root); 763 free(p->newdir); 764 free(p->buf); 765 free(p); 766 } 767 768 /* 769 * Iterates through all available files and conditionally gets the file 770 * ready for processing to check whether it's up to date. 771 * If not up to date or empty, sends file information to the sender. 772 * If returns 0, we've processed all files there are to process. 773 * If returns >0, we're waiting for POLLIN or POLLOUT data. 774 * Otherwise returns <0, which is an error. 775 */ 776 int 777 rsync_uploader(struct upload *u, int *fileinfd, 778 struct sess *sess, int *fileoutfd) 779 { 780 struct blkset blk; 781 struct stat st; 782 void *mbuf, *bufp; 783 ssize_t msz; 784 size_t i, pos, sz; 785 off_t offs; 786 int c; 787 788 /* Once finished this should never get called again. */ 789 assert(u->state != UPLOAD_FINISHED); 790 791 /* 792 * If we have an upload in progress, then keep writing until the 793 * buffer has been fully written. 794 * We must only have the output file descriptor working and also 795 * have a valid buffer to write. 796 */ 797 798 if (u->state == UPLOAD_WRITE) { 799 assert(u->buf != NULL); 800 assert(*fileoutfd != -1); 801 assert(*fileinfd == -1); 802 803 /* 804 * Unfortunately, we need to chunk these: if we're 805 * the server side of things, then we're multiplexing 806 * output and need to wrap this in chunks. 807 * This is a major deficiency of rsync. 808 * FIXME: add a "fast-path" mode that simply dumps out 809 * the buffer non-blocking if we're not mplexing. 810 */ 811 812 if (u->bufpos < u->bufsz) { 813 sz = MAX_CHUNK < (u->bufsz - u->bufpos) ? 814 MAX_CHUNK : (u->bufsz - u->bufpos); 815 c = io_write_buf(sess, u->fdout, 816 u->buf + u->bufpos, sz); 817 if (c == 0) { 818 ERRX1("io_write_nonblocking"); 819 return -1; 820 } 821 u->bufpos += sz; 822 if (u->bufpos < u->bufsz) 823 return 1; 824 } 825 826 /* 827 * Let the UPLOAD_FIND_NEXT state handle things if we 828 * finish, as we'll need to write a POLLOUT message and 829 * not have a writable descriptor yet. 830 */ 831 832 u->state = UPLOAD_FIND_NEXT; 833 u->idx++; 834 return 1; 835 } 836 837 /* 838 * If we invoke the uploader without a file currently open, then 839 * we iterate through til the next available regular file and 840 * start the opening process. 841 * This means we must have the output file descriptor working. 842 */ 843 844 if (u->state == UPLOAD_FIND_NEXT) { 845 assert(*fileinfd == -1); 846 assert(*fileoutfd != -1); 847 848 for ( ; u->idx < u->flsz; u->idx++) { 849 if (S_ISDIR(u->fl[u->idx].st.mode)) 850 c = pre_dir(u, sess); 851 else if (S_ISLNK(u->fl[u->idx].st.mode)) 852 c = pre_link(u, sess); 853 else if (S_ISREG(u->fl[u->idx].st.mode)) 854 c = pre_file(u, fileinfd, &st, sess); 855 else if (S_ISBLK(u->fl[u->idx].st.mode) || 856 S_ISCHR(u->fl[u->idx].st.mode)) 857 c = pre_dev(u, sess); 858 else if (S_ISFIFO(u->fl[u->idx].st.mode)) 859 c = pre_fifo(u, sess); 860 else if (S_ISSOCK(u->fl[u->idx].st.mode)) 861 c = pre_sock(u, sess); 862 else 863 c = 0; 864 865 if (c < 0) 866 return -1; 867 else if (c > 0) 868 break; 869 } 870 871 /* 872 * Whether we've finished writing files or not, we 873 * disable polling on the output channel. 874 */ 875 876 *fileoutfd = -1; 877 if (u->idx == u->flsz) { 878 assert(*fileinfd == -1); 879 if (!io_write_int(sess, u->fdout, -1)) { 880 ERRX1("io_write_int"); 881 return -1; 882 } 883 u->state = UPLOAD_FINISHED; 884 LOG4("uploader: finished"); 885 return 0; 886 } 887 888 /* Go back to the event loop, if necessary. */ 889 890 u->state = UPLOAD_WRITE; 891 } 892 893 /* Initialies our blocks. */ 894 895 assert(u->state == UPLOAD_WRITE); 896 memset(&blk, 0, sizeof(struct blkset)); 897 blk.csum = u->csumlen; 898 899 if (*fileinfd != -1 && st.st_size > 0) { 900 init_blkset(&blk, st.st_size); 901 assert(blk.blksz); 902 903 blk.blks = calloc(blk.blksz, sizeof(struct blk)); 904 if (blk.blks == NULL) { 905 ERR("calloc"); 906 close(*fileinfd); 907 *fileinfd = -1; 908 return -1; 909 } 910 911 if ((mbuf = malloc(blk.len)) == NULL) { 912 ERR("malloc"); 913 close(*fileinfd); 914 *fileinfd = -1; 915 free(blk.blks); 916 return -1; 917 } 918 919 offs = 0; 920 i = 0; 921 do { 922 msz = pread(*fileinfd, mbuf, blk.len, offs); 923 if ((size_t)msz != blk.len && (size_t)msz != blk.rem) { 924 ERR("pread"); 925 close(*fileinfd); 926 *fileinfd = -1; 927 free(mbuf); 928 free(blk.blks); 929 return -1; 930 } 931 init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); 932 offs += blk.len; 933 LOG3( 934 "i=%ld, offs=%lld, msz=%ld, blk.len=%lu, blk.rem=%lu", 935 i, offs, msz, blk.len, blk.rem); 936 i++; 937 } while (i < blk.blksz); 938 939 free(mbuf); 940 close(*fileinfd); 941 *fileinfd = -1; 942 LOG3("%s: mapped %jd B with %zu blocks", 943 u->fl[u->idx].path, (intmax_t)blk.size, 944 blk.blksz); 945 } else { 946 if (*fileinfd != -1) { 947 close(*fileinfd); 948 *fileinfd = -1; 949 } 950 blk.len = MAX_CHUNK; /* Doesn't matter. */ 951 LOG3("%s: not mapped", u->fl[u->idx].path); 952 } 953 954 assert(*fileinfd == -1); 955 956 /* Make sure the block metadata buffer is big enough. */ 957 958 u->bufsz = 959 sizeof(int32_t) + /* identifier */ 960 sizeof(int32_t) + /* block count */ 961 sizeof(int32_t) + /* block length */ 962 sizeof(int32_t) + /* checksum length */ 963 sizeof(int32_t) + /* block remainder */ 964 blk.blksz * 965 (sizeof(int32_t) + /* short checksum */ 966 blk.csum); /* long checksum */ 967 968 if (u->bufsz > u->bufmax) { 969 if ((bufp = realloc(u->buf, u->bufsz)) == NULL) { 970 ERR("realloc"); 971 free(blk.blks); 972 return -1; 973 } 974 u->buf = bufp; 975 u->bufmax = u->bufsz; 976 } 977 978 u->bufpos = pos = 0; 979 io_buffer_int(u->buf, &pos, u->bufsz, u->idx); 980 io_buffer_int(u->buf, &pos, u->bufsz, blk.blksz); 981 io_buffer_int(u->buf, &pos, u->bufsz, blk.len); 982 io_buffer_int(u->buf, &pos, u->bufsz, blk.csum); 983 io_buffer_int(u->buf, &pos, u->bufsz, blk.rem); 984 for (i = 0; i < blk.blksz; i++) { 985 io_buffer_int(u->buf, &pos, u->bufsz, 986 blk.blks[i].chksum_short); 987 io_buffer_buf(u->buf, &pos, u->bufsz, 988 blk.blks[i].chksum_long, blk.csum); 989 } 990 assert(pos == u->bufsz); 991 992 /* Reenable the output poller and clean up. */ 993 994 *fileoutfd = u->fdout; 995 free(blk.blks); 996 return 1; 997 } 998 999 /* 1000 * Fix up the directory permissions and times post-order. 1001 * We can't fix up directory permissions in place because the server may 1002 * want us to have overly-tight permissions---say, those that don't 1003 * allow writing into the directory. 1004 * We also need to do our directory times post-order because making 1005 * files within the directory will change modification times. 1006 * Returns zero on failure, non-zero on success. 1007 */ 1008 int 1009 rsync_uploader_tail(struct upload *u, struct sess *sess) 1010 { 1011 size_t i; 1012 1013 1014 if (!sess->opts->preserve_times && 1015 !sess->opts->preserve_perms) 1016 return 1; 1017 1018 LOG2("fixing up directory times and permissions"); 1019 1020 for (i = 0; i < u->flsz; i++) 1021 if (S_ISDIR(u->fl[i].st.mode)) 1022 if (!post_dir(sess, u, i)) 1023 return 0; 1024 1025 return 1; 1026 } 1027