1 /* $OpenBSD: uploader.c,v 1.36 2023/11/27 11:28:39 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 <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 (!sess->opts->ignore_dir_times) { 612 if (u->newdir[idx] || 613 (sess->opts->preserve_times && 614 st.st_mtime != f->st.mtime)) { 615 tv[0].tv_sec = time(NULL); 616 tv[0].tv_nsec = 0; 617 tv[1].tv_sec = f->st.mtime; 618 tv[1].tv_nsec = 0; 619 rc = utimensat(u->rootfd, f->path, tv, 0); 620 if (rc == -1) { 621 ERR("%s: utimensat", f->path); 622 return 0; 623 } 624 LOG4("%s: updated date", f->path); 625 } 626 } 627 628 /* 629 * Update the mode if we're a new directory *or* if we're 630 * preserving modes and it has changed. 631 */ 632 633 if (u->newdir[idx] || 634 (sess->opts->preserve_perms && st.st_mode != f->st.mode)) { 635 rc = fchmodat(u->rootfd, f->path, f->st.mode, 0); 636 if (rc == -1) { 637 ERR("%s: fchmodat", f->path); 638 return 0; 639 } 640 LOG4("%s: updated mode", f->path); 641 } 642 643 return 1; 644 } 645 646 /* 647 * Check if file exists in the specified root directory. 648 * Returns: 649 * -1 on error 650 * 0 if file is considered the same 651 * 1 if file exists and is possible match 652 * 2 if file exists but quick check failed 653 * 3 if file does not exist 654 * The stat pointer st is only valid for 0, 1, and 2 returns. 655 */ 656 static int 657 check_file(int rootfd, const struct flist *f, struct stat *st, 658 struct sess *sess) 659 { 660 if (fstatat(rootfd, f->path, st, AT_SYMLINK_NOFOLLOW) == -1) { 661 if (errno == ENOENT) 662 return 3; 663 664 ERR("%s: fstatat", f->path); 665 return -1; 666 } 667 668 /* non-regular file needs attention */ 669 if (!S_ISREG(st->st_mode)) 670 return 2; 671 672 /* TODO: add support for --checksum */ 673 674 /* if ignore_times is on file needs attention */ 675 if (sess->opts->ignore_times) 676 return 2; 677 678 /* quick check if file is the same */ 679 if (st->st_size == f->st.size) { 680 if (sess->opts->size_only) 681 return 0; 682 if (st->st_mtime == f->st.mtime) 683 return 0; 684 return 1; 685 } 686 687 /* file needs attention */ 688 return 2; 689 } 690 691 /* 692 * Try to open the file at the current index. 693 * If the file does not exist, returns with >0. 694 * Return <0 on failure, 0 on success w/nothing to be done, >0 on 695 * success and the file needs attention. 696 */ 697 static int 698 pre_file(const struct upload *p, int *filefd, off_t *size, 699 struct sess *sess) 700 { 701 const struct flist *f; 702 struct stat st; 703 int i, rc, match = -1; 704 705 f = &p->fl[p->idx]; 706 assert(S_ISREG(f->st.mode)); 707 708 if (sess->opts->dry_run) { 709 log_file(sess, f); 710 if (!io_write_int(sess, p->fdout, p->idx)) { 711 ERRX1("io_write_int"); 712 return -1; 713 } 714 return 0; 715 } 716 717 if (sess->opts->max_size >= 0 && f->st.size > sess->opts->max_size) { 718 WARNX("skipping over max-size file %s", f->path); 719 return 0; 720 } 721 if (sess->opts->min_size >= 0 && f->st.size < sess->opts->min_size) { 722 WARNX("skipping under min-size file %s", f->path); 723 return 0; 724 } 725 726 /* 727 * For non dry-run cases, we'll write the acknowledgement later 728 * in the rsync_uploader() function. 729 */ 730 731 *size = 0; 732 *filefd = -1; 733 734 rc = check_file(p->rootfd, f, &st, sess); 735 if (rc == -1) 736 return -1; 737 if (rc == 2 && !S_ISREG(st.st_mode)) { 738 if (S_ISDIR(st.st_mode) && 739 unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { 740 ERR("%s: unlinkat", f->path); 741 return -1; 742 } 743 } 744 if (rc == 0) { 745 if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) { 746 ERRX1("rsync_set_metadata"); 747 return -1; 748 } 749 LOG3("%s: skipping: up to date", f->path); 750 return 0; 751 } 752 753 /* check alternative locations for better match */ 754 for (i = 0; sess->opts->basedir[i] != NULL; i++) { 755 const char *root = sess->opts->basedir[i]; 756 int dfd, x; 757 758 dfd = openat(p->rootfd, root, O_RDONLY | O_DIRECTORY); 759 if (dfd == -1) 760 err(ERR_FILE_IO, "%s: openat", root); 761 x = check_file(dfd, f, &st, sess); 762 /* found a match */ 763 if (x == 0) { 764 if (rc >= 0) { 765 /* found better match, delete file in rootfd */ 766 if (unlinkat(p->rootfd, f->path, 0) == -1 && 767 errno != ENOENT) { 768 ERR("%s: unlinkat", f->path); 769 return -1; 770 } 771 } 772 LOG3("%s: skipping: up to date in %s", f->path, root); 773 /* TODO: depending on mode link or copy file */ 774 close(dfd); 775 return 0; 776 } else if (x == 1 && match == -1) { 777 /* found a local file that is a close match */ 778 match = i; 779 } 780 close(dfd); 781 } 782 if (match != -1) { 783 /* copy match from basedir into root as a start point */ 784 copy_file(p->rootfd, sess->opts->basedir[match], f); 785 if (fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == 786 -1) { 787 ERR("%s: fstatat", f->path); 788 return -1; 789 } 790 } 791 792 *size = st.st_size; 793 *filefd = openat(p->rootfd, f->path, O_RDONLY | O_NOFOLLOW); 794 if (*filefd == -1 && errno != ENOENT) { 795 ERR("%s: openat", f->path); 796 return -1; 797 } 798 799 /* file needs attention */ 800 return 1; 801 } 802 803 /* 804 * Allocate an uploader object in the correct state to start. 805 * Returns NULL on failure or the pointer otherwise. 806 * On success, upload_free() must be called with the allocated pointer. 807 */ 808 struct upload * 809 upload_alloc(const char *root, int rootfd, int fdout, 810 size_t clen, const struct flist *fl, size_t flsz, mode_t msk) 811 { 812 struct upload *p; 813 814 if ((p = calloc(1, sizeof(struct upload))) == NULL) { 815 ERR("calloc"); 816 return NULL; 817 } 818 819 p->state = UPLOAD_FIND_NEXT; 820 p->oumask = msk; 821 p->root = strdup(root); 822 if (p->root == NULL) { 823 ERR("strdup"); 824 free(p); 825 return NULL; 826 } 827 p->rootfd = rootfd; 828 p->csumlen = clen; 829 p->fdout = fdout; 830 p->fl = fl; 831 p->flsz = flsz; 832 p->newdir = calloc(flsz, sizeof(int)); 833 if (p->newdir == NULL) { 834 ERR("calloc"); 835 free(p->root); 836 free(p); 837 return NULL; 838 } 839 return p; 840 } 841 842 /* 843 * Perform all cleanups and free. 844 * Passing a NULL to this function is ok. 845 */ 846 void 847 upload_free(struct upload *p) 848 { 849 850 if (p == NULL) 851 return; 852 free(p->root); 853 free(p->newdir); 854 free(p->buf); 855 free(p); 856 } 857 858 /* 859 * Iterates through all available files and conditionally gets the file 860 * ready for processing to check whether it's up to date. 861 * If not up to date or empty, sends file information to the sender. 862 * If returns 0, we've processed all files there are to process. 863 * If returns >0, we're waiting for POLLIN or POLLOUT data. 864 * Otherwise returns <0, which is an error. 865 */ 866 int 867 rsync_uploader(struct upload *u, int *fileinfd, 868 struct sess *sess, int *fileoutfd) 869 { 870 struct blkset blk; 871 void *mbuf, *bufp; 872 ssize_t msz; 873 size_t i, pos, sz; 874 off_t offs, filesize; 875 int c; 876 877 /* Once finished this should never get called again. */ 878 assert(u->state != UPLOAD_FINISHED); 879 880 /* 881 * If we have an upload in progress, then keep writing until the 882 * buffer has been fully written. 883 * We must only have the output file descriptor working and also 884 * have a valid buffer to write. 885 */ 886 887 if (u->state == UPLOAD_WRITE) { 888 assert(u->buf != NULL); 889 assert(*fileoutfd != -1); 890 assert(*fileinfd == -1); 891 892 /* 893 * Unfortunately, we need to chunk these: if we're 894 * the server side of things, then we're multiplexing 895 * output and need to wrap this in chunks. 896 * This is a major deficiency of rsync. 897 * FIXME: add a "fast-path" mode that simply dumps out 898 * the buffer non-blocking if we're not mplexing. 899 */ 900 901 if (u->bufpos < u->bufsz) { 902 sz = MAX_CHUNK < (u->bufsz - u->bufpos) ? 903 MAX_CHUNK : (u->bufsz - u->bufpos); 904 c = io_write_buf(sess, u->fdout, 905 u->buf + u->bufpos, sz); 906 if (c == 0) { 907 ERRX1("io_write_nonblocking"); 908 return -1; 909 } 910 u->bufpos += sz; 911 if (u->bufpos < u->bufsz) 912 return 1; 913 } 914 915 /* 916 * Let the UPLOAD_FIND_NEXT state handle things if we 917 * finish, as we'll need to write a POLLOUT message and 918 * not have a writable descriptor yet. 919 */ 920 921 u->state = UPLOAD_FIND_NEXT; 922 u->idx++; 923 return 1; 924 } 925 926 /* 927 * If we invoke the uploader without a file currently open, then 928 * we iterate through til the next available regular file and 929 * start the opening process. 930 * This means we must have the output file descriptor working. 931 */ 932 933 if (u->state == UPLOAD_FIND_NEXT) { 934 assert(*fileinfd == -1); 935 assert(*fileoutfd != -1); 936 937 for ( ; u->idx < u->flsz; u->idx++) { 938 if (S_ISDIR(u->fl[u->idx].st.mode)) 939 c = pre_dir(u, sess); 940 else if (S_ISLNK(u->fl[u->idx].st.mode)) 941 c = pre_symlink(u, sess); 942 else if (S_ISREG(u->fl[u->idx].st.mode)) 943 c = pre_file(u, fileinfd, &filesize, sess); 944 else if (S_ISBLK(u->fl[u->idx].st.mode) || 945 S_ISCHR(u->fl[u->idx].st.mode)) 946 c = pre_dev(u, sess); 947 else if (S_ISFIFO(u->fl[u->idx].st.mode)) 948 c = pre_fifo(u, sess); 949 else if (S_ISSOCK(u->fl[u->idx].st.mode)) 950 c = pre_sock(u, sess); 951 else 952 c = 0; 953 954 if (c < 0) 955 return -1; 956 else if (c > 0) 957 break; 958 } 959 960 /* 961 * Whether we've finished writing files or not, we 962 * disable polling on the output channel. 963 */ 964 965 *fileoutfd = -1; 966 if (u->idx == u->flsz) { 967 assert(*fileinfd == -1); 968 if (!io_write_int(sess, u->fdout, -1)) { 969 ERRX1("io_write_int"); 970 return -1; 971 } 972 u->state = UPLOAD_FINISHED; 973 LOG4("uploader: finished"); 974 return 0; 975 } 976 977 /* Go back to the event loop, if necessary. */ 978 979 u->state = UPLOAD_WRITE; 980 } 981 982 /* Initialies our blocks. */ 983 984 assert(u->state == UPLOAD_WRITE); 985 memset(&blk, 0, sizeof(struct blkset)); 986 blk.csum = u->csumlen; 987 988 if (*fileinfd != -1 && filesize > 0) { 989 init_blkset(&blk, filesize); 990 assert(blk.blksz); 991 992 blk.blks = calloc(blk.blksz, sizeof(struct blk)); 993 if (blk.blks == NULL) { 994 ERR("calloc"); 995 close(*fileinfd); 996 *fileinfd = -1; 997 return -1; 998 } 999 1000 if ((mbuf = malloc(blk.len)) == NULL) { 1001 ERR("malloc"); 1002 close(*fileinfd); 1003 *fileinfd = -1; 1004 free(blk.blks); 1005 return -1; 1006 } 1007 1008 offs = 0; 1009 i = 0; 1010 do { 1011 msz = pread(*fileinfd, mbuf, blk.len, offs); 1012 if ((size_t)msz != blk.len && (size_t)msz != blk.rem) { 1013 ERR("pread"); 1014 close(*fileinfd); 1015 *fileinfd = -1; 1016 free(mbuf); 1017 free(blk.blks); 1018 return -1; 1019 } 1020 init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); 1021 offs += blk.len; 1022 LOG3( 1023 "i=%ld, offs=%lld, msz=%ld, blk.len=%lu, blk.rem=%lu", 1024 i, offs, msz, blk.len, blk.rem); 1025 i++; 1026 } while (i < blk.blksz); 1027 1028 free(mbuf); 1029 close(*fileinfd); 1030 *fileinfd = -1; 1031 LOG3("%s: mapped %jd B with %zu blocks", 1032 u->fl[u->idx].path, (intmax_t)blk.size, 1033 blk.blksz); 1034 } else { 1035 if (*fileinfd != -1) { 1036 close(*fileinfd); 1037 *fileinfd = -1; 1038 } 1039 blk.len = MAX_CHUNK; /* Doesn't matter. */ 1040 LOG3("%s: not mapped", u->fl[u->idx].path); 1041 } 1042 1043 assert(*fileinfd == -1); 1044 1045 /* Make sure the block metadata buffer is big enough. */ 1046 1047 u->bufsz = 1048 sizeof(int32_t) + /* identifier */ 1049 sizeof(int32_t) + /* block count */ 1050 sizeof(int32_t) + /* block length */ 1051 sizeof(int32_t) + /* checksum length */ 1052 sizeof(int32_t) + /* block remainder */ 1053 blk.blksz * 1054 (sizeof(int32_t) + /* short checksum */ 1055 blk.csum); /* long checksum */ 1056 1057 if (u->bufsz > u->bufmax) { 1058 if ((bufp = realloc(u->buf, u->bufsz)) == NULL) { 1059 ERR("realloc"); 1060 free(blk.blks); 1061 return -1; 1062 } 1063 u->buf = bufp; 1064 u->bufmax = u->bufsz; 1065 } 1066 1067 u->bufpos = pos = 0; 1068 io_buffer_int(u->buf, &pos, u->bufsz, u->idx); 1069 io_buffer_int(u->buf, &pos, u->bufsz, blk.blksz); 1070 io_buffer_int(u->buf, &pos, u->bufsz, blk.len); 1071 io_buffer_int(u->buf, &pos, u->bufsz, blk.csum); 1072 io_buffer_int(u->buf, &pos, u->bufsz, blk.rem); 1073 for (i = 0; i < blk.blksz; i++) { 1074 io_buffer_int(u->buf, &pos, u->bufsz, 1075 blk.blks[i].chksum_short); 1076 io_buffer_buf(u->buf, &pos, u->bufsz, 1077 blk.blks[i].chksum_long, blk.csum); 1078 } 1079 assert(pos == u->bufsz); 1080 1081 /* Reenable the output poller and clean up. */ 1082 1083 *fileoutfd = u->fdout; 1084 free(blk.blks); 1085 return 1; 1086 } 1087 1088 /* 1089 * Fix up the directory permissions and times post-order. 1090 * We can't fix up directory permissions in place because the server may 1091 * want us to have overly-tight permissions---say, those that don't 1092 * allow writing into the directory. 1093 * We also need to do our directory times post-order because making 1094 * files within the directory will change modification times. 1095 * Returns zero on failure, non-zero on success. 1096 */ 1097 int 1098 rsync_uploader_tail(struct upload *u, struct sess *sess) 1099 { 1100 size_t i; 1101 1102 if ((!sess->opts->preserve_times || sess->opts->ignore_dir_times) && 1103 !sess->opts->preserve_perms) 1104 return 1; 1105 1106 LOG2("fixing up directory times and permissions"); 1107 1108 for (i = 0; i < u->flsz; i++) 1109 if (S_ISDIR(u->fl[i].st.mode)) 1110 if (!post_dir(sess, u, i)) 1111 return 0; 1112 1113 return 1; 1114 } 1115