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