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