Annotation of embedaddon/rsync/generator.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Routines that are exclusive to the generator process.
! 3: *
! 4: * Copyright (C) 1996-2000 Andrew Tridgell
! 5: * Copyright (C) 1996 Paul Mackerras
! 6: * Copyright (C) 2002 Martin Pool <mbp@samba.org>
! 7: * Copyright (C) 2003-2009 Wayne Davison
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify
! 10: * it under the terms of the GNU General Public License as published by
! 11: * the Free Software Foundation; either version 3 of the License, or
! 12: * (at your option) any later version.
! 13: *
! 14: * This program is distributed in the hope that it will be useful,
! 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 17: * GNU General Public License for more details.
! 18: *
! 19: * You should have received a copy of the GNU General Public License along
! 20: * with this program; if not, visit the http://fsf.org website.
! 21: */
! 22:
! 23: #include "rsync.h"
! 24:
! 25: extern int verbose;
! 26: extern int dry_run;
! 27: extern int do_xfers;
! 28: extern int stdout_format_has_i;
! 29: extern int logfile_format_has_i;
! 30: extern int am_root;
! 31: extern int am_server;
! 32: extern int am_daemon;
! 33: extern int inc_recurse;
! 34: extern int do_progress;
! 35: extern int relative_paths;
! 36: extern int implied_dirs;
! 37: extern int keep_dirlinks;
! 38: extern int preserve_acls;
! 39: extern int preserve_xattrs;
! 40: extern int preserve_links;
! 41: extern int preserve_devices;
! 42: extern int preserve_specials;
! 43: extern int preserve_hard_links;
! 44: extern int preserve_executability;
! 45: extern int preserve_perms;
! 46: extern int preserve_times;
! 47: extern int delete_mode;
! 48: extern int delete_before;
! 49: extern int delete_during;
! 50: extern int delete_after;
! 51: extern int msgdone_cnt;
! 52: extern int ignore_errors;
! 53: extern int remove_source_files;
! 54: extern int delay_updates;
! 55: extern int update_only;
! 56: extern int ignore_existing;
! 57: extern int ignore_non_existing;
! 58: extern int inplace;
! 59: extern int append_mode;
! 60: extern int make_backups;
! 61: extern int csum_length;
! 62: extern int ignore_times;
! 63: extern int size_only;
! 64: extern OFF_T max_size;
! 65: extern OFF_T min_size;
! 66: extern int io_error;
! 67: extern int flist_eof;
! 68: extern int allowed_lull;
! 69: extern int sock_f_out;
! 70: extern int ignore_timeout;
! 71: extern int protocol_version;
! 72: extern int file_total;
! 73: extern int fuzzy_basis;
! 74: extern int always_checksum;
! 75: extern int checksum_len;
! 76: extern char *partial_dir;
! 77: extern char *basis_dir[MAX_BASIS_DIRS+1];
! 78: extern int compare_dest;
! 79: extern int copy_dest;
! 80: extern int link_dest;
! 81: extern int whole_file;
! 82: extern int list_only;
! 83: extern int read_batch;
! 84: extern int safe_symlinks;
! 85: extern long block_size; /* "long" because popt can't set an int32. */
! 86: extern int unsort_ndx;
! 87: extern int max_delete;
! 88: extern int force_delete;
! 89: extern int one_file_system;
! 90: extern struct stats stats;
! 91: extern dev_t filesystem_dev;
! 92: extern mode_t orig_umask;
! 93: extern uid_t our_uid;
! 94: extern char *backup_dir;
! 95: extern char *backup_suffix;
! 96: extern int backup_suffix_len;
! 97: extern struct file_list *cur_flist, *first_flist, *dir_flist;
! 98: extern struct filter_list_struct daemon_filter_list;
! 99:
! 100: int ignore_perishable = 0;
! 101: int non_perishable_cnt = 0;
! 102: int maybe_ATTRS_REPORT = 0;
! 103:
! 104: static dev_t dev_zero;
! 105: static int deletion_count = 0; /* used to implement --max-delete */
! 106: static int deldelay_size = 0, deldelay_cnt = 0;
! 107: static char *deldelay_buf = NULL;
! 108: static int deldelay_fd = -1;
! 109: static int loopchk_limit;
! 110: static int dir_tweaking;
! 111: static int symlink_timeset_failed_flags;
! 112: static int need_retouch_dir_times;
! 113: static int need_retouch_dir_perms;
! 114: static const char *solo_file = NULL;
! 115:
! 116: /* For calling delete_item() and delete_dir_contents(). */
! 117: #define DEL_NO_UID_WRITE (1<<0) /* file/dir has our uid w/o write perm */
! 118: #define DEL_RECURSE (1<<1) /* if dir, delete all contents */
! 119: #define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */
! 120: #define DEL_FOR_FILE (1<<3) /* making room for a replacement file */
! 121: #define DEL_FOR_DIR (1<<4) /* making room for a replacement dir */
! 122: #define DEL_FOR_SYMLINK (1<<5) /* making room for a replacement symlink */
! 123: #define DEL_FOR_DEVICE (1<<6) /* making room for a replacement device */
! 124: #define DEL_FOR_SPECIAL (1<<7) /* making room for a replacement special */
! 125:
! 126: #define DEL_MAKE_ROOM (DEL_FOR_FILE|DEL_FOR_DIR|DEL_FOR_SYMLINK|DEL_FOR_DEVICE|DEL_FOR_SPECIAL)
! 127:
! 128: enum nonregtype {
! 129: TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK
! 130: };
! 131:
! 132: enum delret {
! 133: DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY
! 134: };
! 135:
! 136: /* Forward declarations. */
! 137: static enum delret delete_dir_contents(char *fname, uint16 flags);
! 138: #ifdef SUPPORT_HARD_LINKS
! 139: static void handle_skipped_hlink(struct file_struct *file, int itemizing,
! 140: enum logcode code, int f_out);
! 141: #endif
! 142:
! 143: static int is_backup_file(char *fn)
! 144: {
! 145: int k = strlen(fn) - backup_suffix_len;
! 146: return k > 0 && strcmp(fn+k, backup_suffix) == 0;
! 147: }
! 148:
! 149: /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
! 150: * delete recursively.
! 151: *
! 152: * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
! 153: * a directory! (The buffer is used for recursion, but returned unchanged.)
! 154: */
! 155: static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
! 156: {
! 157: enum delret ret;
! 158: char *what;
! 159: int ok;
! 160:
! 161: if (verbose > 2) {
! 162: rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
! 163: fbuf, (int)mode, (int)flags);
! 164: }
! 165:
! 166: if (flags & DEL_NO_UID_WRITE)
! 167: do_chmod(fbuf, mode | S_IWUSR);
! 168:
! 169: if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
! 170: /* This only happens on the first call to delete_item() since
! 171: * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */
! 172: ignore_perishable = 1;
! 173: /* If DEL_RECURSE is not set, this just reports emptiness. */
! 174: ret = delete_dir_contents(fbuf, flags);
! 175: ignore_perishable = 0;
! 176: if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT)
! 177: goto check_ret;
! 178: /* OK: try to delete the directory. */
! 179: }
! 180:
! 181: if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && ++deletion_count > max_delete)
! 182: return DR_AT_LIMIT;
! 183:
! 184: if (S_ISDIR(mode)) {
! 185: what = "rmdir";
! 186: ok = do_rmdir(fbuf) == 0;
! 187: } else if (make_backups > 0 && (backup_dir || !is_backup_file(fbuf))) {
! 188: what = "make_backup";
! 189: ok = make_backup(fbuf);
! 190: } else {
! 191: what = "unlink";
! 192: ok = robust_unlink(fbuf) == 0;
! 193: }
! 194:
! 195: if (ok) {
! 196: if (!(flags & DEL_MAKE_ROOM))
! 197: log_delete(fbuf, mode);
! 198: ret = DR_SUCCESS;
! 199: } else {
! 200: if (S_ISDIR(mode) && errno == ENOTEMPTY) {
! 201: rprintf(FINFO, "cannot delete non-empty directory: %s\n",
! 202: fbuf);
! 203: ret = DR_NOT_EMPTY;
! 204: } else if (errno != ENOENT) {
! 205: rsyserr(FERROR, errno, "delete_file: %s(%s) failed",
! 206: what, fbuf);
! 207: ret = DR_FAILURE;
! 208: } else {
! 209: deletion_count--;
! 210: ret = DR_SUCCESS;
! 211: }
! 212: }
! 213:
! 214: check_ret:
! 215: if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) {
! 216: const char *desc;
! 217: switch (flags & DEL_MAKE_ROOM) {
! 218: case DEL_FOR_FILE: desc = "regular file"; break;
! 219: case DEL_FOR_DIR: desc = "directory"; break;
! 220: case DEL_FOR_SYMLINK: desc = "symlink"; break;
! 221: case DEL_FOR_DEVICE: desc = "device file"; break;
! 222: case DEL_FOR_SPECIAL: desc = "special file"; break;
! 223: default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
! 224: }
! 225: rprintf(FERROR_XFER, "could not make way for new %s: %s\n",
! 226: desc, fbuf);
! 227: }
! 228: return ret;
! 229: }
! 230:
! 231: /* The directory is about to be deleted: if DEL_RECURSE is given, delete all
! 232: * its contents, otherwise just checks for content. Returns DR_SUCCESS or
! 233: * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
! 234: * buffer is used for recursion, but returned unchanged.)
! 235: */
! 236: static enum delret delete_dir_contents(char *fname, uint16 flags)
! 237: {
! 238: struct file_list *dirlist;
! 239: enum delret ret;
! 240: unsigned remainder;
! 241: void *save_filters;
! 242: int j, dlen;
! 243: char *p;
! 244:
! 245: if (verbose > 3) {
! 246: rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
! 247: fname, flags);
! 248: }
! 249:
! 250: dlen = strlen(fname);
! 251: save_filters = push_local_filters(fname, dlen);
! 252:
! 253: non_perishable_cnt = 0;
! 254: dirlist = get_dirlist(fname, dlen, 0);
! 255: ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;
! 256:
! 257: if (!dirlist->used)
! 258: goto done;
! 259:
! 260: if (!(flags & DEL_RECURSE)) {
! 261: ret = DR_NOT_EMPTY;
! 262: goto done;
! 263: }
! 264:
! 265: p = fname + dlen;
! 266: if (dlen != 1 || *fname != '/')
! 267: *p++ = '/';
! 268: remainder = MAXPATHLEN - (p - fname);
! 269:
! 270: /* We do our own recursion, so make delete_item() non-recursive. */
! 271: flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
! 272: | DEL_DIR_IS_EMPTY;
! 273:
! 274: for (j = dirlist->used; j--; ) {
! 275: struct file_struct *fp = dirlist->files[j];
! 276:
! 277: if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
! 278: if (verbose > 1) {
! 279: rprintf(FINFO,
! 280: "mount point, %s, pins parent directory\n",
! 281: f_name(fp, NULL));
! 282: }
! 283: ret = DR_NOT_EMPTY;
! 284: continue;
! 285: }
! 286:
! 287: strlcpy(p, fp->basename, remainder);
! 288: if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
! 289: do_chmod(fname, fp->mode | S_IWUSR);
! 290: /* Save stack by recursing to ourself directly. */
! 291: if (S_ISDIR(fp->mode)) {
! 292: if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
! 293: ret = DR_NOT_EMPTY;
! 294: }
! 295: if (delete_item(fname, fp->mode, flags) != DR_SUCCESS)
! 296: ret = DR_NOT_EMPTY;
! 297: }
! 298:
! 299: fname[dlen] = '\0';
! 300:
! 301: done:
! 302: flist_free(dirlist);
! 303: pop_local_filters(save_filters);
! 304:
! 305: if (ret == DR_NOT_EMPTY) {
! 306: rprintf(FINFO, "cannot delete non-empty directory: %s\n",
! 307: fname);
! 308: }
! 309: return ret;
! 310: }
! 311:
! 312: static int start_delete_delay_temp(void)
! 313: {
! 314: char fnametmp[MAXPATHLEN];
! 315: int save_dry_run = dry_run;
! 316:
! 317: dry_run = 0;
! 318: if (!get_tmpname(fnametmp, "deldelay")
! 319: || (deldelay_fd = do_mkstemp(fnametmp, 0600)) < 0) {
! 320: rprintf(FINFO, "NOTE: Unable to create delete-delay temp file%s.\n",
! 321: inc_recurse ? "" : " -- switching to --delete-after");
! 322: delete_during = 0;
! 323: delete_after = !inc_recurse;
! 324: dry_run = save_dry_run;
! 325: return 0;
! 326: }
! 327: unlink(fnametmp);
! 328: dry_run = save_dry_run;
! 329: return 1;
! 330: }
! 331:
! 332: static int flush_delete_delay(void)
! 333: {
! 334: if (deldelay_fd < 0 && !start_delete_delay_temp())
! 335: return 0;
! 336: if (write(deldelay_fd, deldelay_buf, deldelay_cnt) != deldelay_cnt) {
! 337: rsyserr(FERROR, errno, "flush of delete-delay buffer");
! 338: delete_during = 0;
! 339: delete_after = !inc_recurse;
! 340: close(deldelay_fd);
! 341: return 0;
! 342: }
! 343: deldelay_cnt = 0;
! 344: return 1;
! 345: }
! 346:
! 347: static int remember_delete(struct file_struct *file, const char *fname, int flags)
! 348: {
! 349: int len;
! 350:
! 351: if (deldelay_cnt == deldelay_size && !flush_delete_delay())
! 352: return 0;
! 353:
! 354: if (flags & DEL_NO_UID_WRITE)
! 355: deldelay_buf[deldelay_cnt++] = '!';
! 356:
! 357: while (1) {
! 358: len = snprintf(deldelay_buf + deldelay_cnt,
! 359: deldelay_size - deldelay_cnt,
! 360: "%x %s%c",
! 361: (int)file->mode, fname, '\0');
! 362: if ((deldelay_cnt += len) <= deldelay_size)
! 363: break;
! 364: deldelay_cnt -= len;
! 365: if (!flush_delete_delay())
! 366: return 0;
! 367: }
! 368:
! 369: return 1;
! 370: }
! 371:
! 372: static int read_delay_line(char *buf, int *flags_p)
! 373: {
! 374: static int read_pos = 0;
! 375: int j, len, mode;
! 376: char *bp, *past_space;
! 377:
! 378: while (1) {
! 379: for (j = read_pos; j < deldelay_cnt && deldelay_buf[j]; j++) {}
! 380: if (j < deldelay_cnt)
! 381: break;
! 382: if (deldelay_fd < 0) {
! 383: if (j > read_pos)
! 384: goto invalid_data;
! 385: return -1;
! 386: }
! 387: deldelay_cnt -= read_pos;
! 388: if (deldelay_cnt == deldelay_size)
! 389: goto invalid_data;
! 390: if (deldelay_cnt && read_pos) {
! 391: memmove(deldelay_buf, deldelay_buf + read_pos,
! 392: deldelay_cnt);
! 393: }
! 394: len = read(deldelay_fd, deldelay_buf + deldelay_cnt,
! 395: deldelay_size - deldelay_cnt);
! 396: if (len == 0) {
! 397: if (deldelay_cnt) {
! 398: rprintf(FERROR,
! 399: "ERROR: unexpected EOF in delete-delay file.\n");
! 400: }
! 401: return -1;
! 402: }
! 403: if (len < 0) {
! 404: rsyserr(FERROR, errno,
! 405: "reading delete-delay file");
! 406: return -1;
! 407: }
! 408: deldelay_cnt += len;
! 409: read_pos = 0;
! 410: }
! 411:
! 412: bp = deldelay_buf + read_pos;
! 413: if (*bp == '!') {
! 414: bp++;
! 415: *flags_p = DEL_NO_UID_WRITE;
! 416: } else
! 417: *flags_p = 0;
! 418:
! 419: if (sscanf(bp, "%x ", &mode) != 1) {
! 420: invalid_data:
! 421: rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n");
! 422: return -1;
! 423: }
! 424: past_space = strchr(bp, ' ') + 1;
! 425: len = j - read_pos - (past_space - bp) + 1; /* count the '\0' */
! 426: read_pos = j + 1;
! 427:
! 428: if (len > MAXPATHLEN) {
! 429: rprintf(FERROR, "ERROR: filename too long in delete-delay file.\n");
! 430: return -1;
! 431: }
! 432:
! 433: /* The caller needs the name in a MAXPATHLEN buffer, so we copy it
! 434: * instead of returning a pointer to our buffer. */
! 435: memcpy(buf, past_space, len);
! 436:
! 437: return mode;
! 438: }
! 439:
! 440: static void do_delayed_deletions(char *delbuf)
! 441: {
! 442: int mode, flags;
! 443:
! 444: if (deldelay_fd >= 0) {
! 445: if (deldelay_cnt && !flush_delete_delay())
! 446: return;
! 447: lseek(deldelay_fd, 0, 0);
! 448: }
! 449: while ((mode = read_delay_line(delbuf, &flags)) >= 0)
! 450: delete_item(delbuf, mode, flags | DEL_RECURSE);
! 451: if (deldelay_fd >= 0)
! 452: close(deldelay_fd);
! 453: }
! 454:
! 455: /* This function is used to implement per-directory deletion, and is used by
! 456: * all the --delete-WHEN options. Note that the fbuf pointer must point to a
! 457: * MAXPATHLEN buffer with the name of the directory in it (the functions we
! 458: * call will append names onto the end, but the old dir value will be restored
! 459: * on exit). */
! 460: static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
! 461: {
! 462: static int already_warned = 0;
! 463: struct file_list *dirlist;
! 464: char delbuf[MAXPATHLEN];
! 465: int dlen, i;
! 466:
! 467: if (!fbuf) {
! 468: change_local_filter_dir(NULL, 0, 0);
! 469: return;
! 470: }
! 471:
! 472: if (verbose > 2)
! 473: rprintf(FINFO, "delete_in_dir(%s)\n", fbuf);
! 474:
! 475: if (allowed_lull)
! 476: maybe_send_keepalive();
! 477:
! 478: if (io_error && !ignore_errors) {
! 479: if (already_warned)
! 480: return;
! 481: rprintf(FINFO,
! 482: "IO error encountered -- skipping file deletion\n");
! 483: already_warned = 1;
! 484: return;
! 485: }
! 486:
! 487: dlen = strlen(fbuf);
! 488: change_local_filter_dir(fbuf, dlen, F_DEPTH(file));
! 489:
! 490: if (one_file_system) {
! 491: if (file->flags & FLAG_TOP_DIR)
! 492: filesystem_dev = *fs_dev;
! 493: else if (filesystem_dev != *fs_dev)
! 494: return;
! 495: }
! 496:
! 497: dirlist = get_dirlist(fbuf, dlen, 0);
! 498:
! 499: /* If an item in dirlist is not found in flist, delete it
! 500: * from the filesystem. */
! 501: for (i = dirlist->used; i--; ) {
! 502: struct file_struct *fp = dirlist->files[i];
! 503: if (!F_IS_ACTIVE(fp))
! 504: continue;
! 505: if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
! 506: if (verbose > 1)
! 507: rprintf(FINFO, "cannot delete mount point: %s\n",
! 508: f_name(fp, NULL));
! 509: continue;
! 510: }
! 511: /* Here we want to match regardless of file type. Replacement
! 512: * of a file with one of another type is handled separately by
! 513: * a delete_item call with a DEL_MAKE_ROOM flag. */
! 514: if (flist_find_ignore_dirness(cur_flist, fp) < 0) {
! 515: int flags = DEL_RECURSE;
! 516: if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
! 517: flags |= DEL_NO_UID_WRITE;
! 518: f_name(fp, delbuf);
! 519: if (delete_during == 2) {
! 520: if (!remember_delete(fp, delbuf, flags))
! 521: break;
! 522: } else
! 523: delete_item(delbuf, fp->mode, flags);
! 524: }
! 525: }
! 526:
! 527: flist_free(dirlist);
! 528: }
! 529:
! 530: /* This deletes any files on the receiving side that are not present on the
! 531: * sending side. This is used by --delete-before and --delete-after. */
! 532: static void do_delete_pass(void)
! 533: {
! 534: char fbuf[MAXPATHLEN];
! 535: STRUCT_STAT st;
! 536: int j;
! 537:
! 538: /* dry_run is incremented when the destination doesn't exist yet. */
! 539: if (dry_run > 1 || list_only)
! 540: return;
! 541:
! 542: for (j = 0; j < cur_flist->used; j++) {
! 543: struct file_struct *file = cur_flist->sorted[j];
! 544:
! 545: f_name(file, fbuf);
! 546:
! 547: if (!(file->flags & FLAG_CONTENT_DIR)) {
! 548: change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file));
! 549: continue;
! 550: }
! 551:
! 552: if (verbose > 1 && file->flags & FLAG_TOP_DIR)
! 553: rprintf(FINFO, "deleting in %s\n", fbuf);
! 554:
! 555: if (link_stat(fbuf, &st, keep_dirlinks) < 0
! 556: || !S_ISDIR(st.st_mode))
! 557: continue;
! 558:
! 559: delete_in_dir(fbuf, file, &st.st_dev);
! 560: }
! 561: delete_in_dir(NULL, NULL, &dev_zero);
! 562:
! 563: if (do_progress && !am_server)
! 564: rprintf(FINFO, " \r");
! 565: }
! 566:
! 567: static inline int time_differs(struct file_struct *file, stat_x *sxp)
! 568: {
! 569: return cmp_time(sxp->st.st_mtime, file->modtime);
! 570: }
! 571:
! 572: static inline int perms_differ(struct file_struct *file, stat_x *sxp)
! 573: {
! 574: if (preserve_perms)
! 575: return !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS);
! 576:
! 577: if (preserve_executability)
! 578: return (sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0);
! 579:
! 580: return 0;
! 581: }
! 582:
! 583: static inline int ownership_differs(struct file_struct *file, stat_x *sxp)
! 584: {
! 585: if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))
! 586: return 1;
! 587:
! 588: if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))
! 589: return 1;
! 590:
! 591: return 0;
! 592: }
! 593:
! 594: #ifdef SUPPORT_ACLS
! 595: static inline int acls_differ(const char *fname, struct file_struct *file, stat_x *sxp)
! 596: {
! 597: if (preserve_acls) {
! 598: if (!ACL_READY(*sxp))
! 599: get_acl(fname, sxp);
! 600: if (set_acl(NULL, file, sxp, file->mode))
! 601: return 1;
! 602: }
! 603:
! 604: return 0;
! 605: }
! 606: #endif
! 607:
! 608: #ifdef SUPPORT_XATTRS
! 609: static inline int xattrs_differ(const char *fname, struct file_struct *file, stat_x *sxp)
! 610: {
! 611: if (preserve_xattrs) {
! 612: if (!XATTR_READY(*sxp))
! 613: get_xattr(fname, sxp);
! 614: if (xattr_diff(file, sxp, 0))
! 615: return 1;
! 616: }
! 617:
! 618: return 0;
! 619: }
! 620: #endif
! 621:
! 622: int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
! 623: {
! 624: if (S_ISLNK(file->mode)) {
! 625: #ifdef CAN_SET_SYMLINK_TIMES
! 626: if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
! 627: return 0;
! 628: #endif
! 629: #ifdef CAN_CHMOD_SYMLINK
! 630: if (perms_differ(file, sxp))
! 631: return 0;
! 632: #endif
! 633: #ifdef CAN_CHOWN_SYMLINK
! 634: if (ownership_differs(file, sxp))
! 635: return 0;
! 636: #endif
! 637: #if defined SUPPORT_ACLS && 0 /* no current symlink-ACL support */
! 638: if (acls_differ(fname, file, sxp))
! 639: return 0;
! 640: #endif
! 641: #if defined SUPPORT_XATTRS && !defined NO_SYMLINK_XATTRS
! 642: if (xattrs_differ(fname, file, sxp))
! 643: return 0;
! 644: #endif
! 645: } else {
! 646: if (preserve_times && time_differs(file, sxp))
! 647: return 0;
! 648: if (perms_differ(file, sxp))
! 649: return 0;
! 650: if (ownership_differs(file, sxp))
! 651: return 0;
! 652: #ifdef SUPPORT_ACLS
! 653: if (acls_differ(fname, file, sxp))
! 654: return 0;
! 655: #endif
! 656: #ifdef SUPPORT_XATTRS
! 657: if (xattrs_differ(fname, file, sxp))
! 658: return 0;
! 659: #endif
! 660: }
! 661:
! 662: return 1;
! 663: }
! 664:
! 665: void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statret,
! 666: stat_x *sxp, int32 iflags, uchar fnamecmp_type,
! 667: const char *xname)
! 668: {
! 669: if (statret >= 0) { /* A from-dest-dir statret can == 1! */
! 670: int keep_time = !preserve_times ? 0
! 671: : S_ISDIR(file->mode) ? preserve_times & PRESERVE_DIR_TIMES
! 672: : S_ISLNK(file->mode) ? preserve_times & PRESERVE_LINK_TIMES
! 673: : 1;
! 674:
! 675: if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
! 676: iflags |= ITEM_REPORT_SIZE;
! 677: if (file->flags & FLAG_TIME_FAILED) { /* symlinks only */
! 678: if (iflags & ITEM_LOCAL_CHANGE)
! 679: iflags |= symlink_timeset_failed_flags;
! 680: } else if (keep_time
! 681: ? cmp_time(file->modtime, sxp->st.st_mtime) != 0
! 682: : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
! 683: && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
! 684: iflags |= ITEM_REPORT_TIME;
! 685: #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
! 686: if (S_ISLNK(file->mode)) {
! 687: ;
! 688: } else
! 689: #endif
! 690: if (preserve_perms) {
! 691: if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
! 692: iflags |= ITEM_REPORT_PERMS;
! 693: } else if (preserve_executability
! 694: && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
! 695: iflags |= ITEM_REPORT_PERMS;
! 696: if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid)
! 697: iflags |= ITEM_REPORT_OWNER;
! 698: if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
! 699: && sxp->st.st_gid != (gid_t)F_GROUP(file))
! 700: iflags |= ITEM_REPORT_GROUP;
! 701: #ifdef SUPPORT_ACLS
! 702: if (preserve_acls && !S_ISLNK(file->mode)) {
! 703: if (!ACL_READY(*sxp))
! 704: get_acl(fnamecmp, sxp);
! 705: if (set_acl(NULL, file, sxp, file->mode))
! 706: iflags |= ITEM_REPORT_ACL;
! 707: }
! 708: #endif
! 709: #ifdef SUPPORT_XATTRS
! 710: if (preserve_xattrs) {
! 711: if (!XATTR_READY(*sxp))
! 712: get_xattr(fnamecmp, sxp);
! 713: if (xattr_diff(file, sxp, 1))
! 714: iflags |= ITEM_REPORT_XATTR;
! 715: }
! 716: #endif
! 717: } else {
! 718: #ifdef SUPPORT_XATTRS
! 719: if (preserve_xattrs && xattr_diff(file, NULL, 1))
! 720: iflags |= ITEM_REPORT_XATTR;
! 721: #endif
! 722: iflags |= ITEM_IS_NEW;
! 723: }
! 724:
! 725: iflags &= 0xffff;
! 726: if ((iflags & (SIGNIFICANT_ITEM_FLAGS|ITEM_REPORT_XATTR) || verbose > 1
! 727: || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) {
! 728: if (protocol_version >= 29) {
! 729: if (ndx >= 0)
! 730: write_ndx(sock_f_out, ndx);
! 731: write_shortint(sock_f_out, iflags);
! 732: if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
! 733: write_byte(sock_f_out, fnamecmp_type);
! 734: if (iflags & ITEM_XNAME_FOLLOWS)
! 735: write_vstring(sock_f_out, xname, strlen(xname));
! 736: #ifdef SUPPORT_XATTRS
! 737: if (preserve_xattrs && do_xfers
! 738: && iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
! 739: send_xattr_request(NULL, file,
! 740: iflags & ITEM_REPORT_XATTR ? sock_f_out : -1);
! 741: }
! 742: #endif
! 743: } else if (ndx >= 0) {
! 744: enum logcode code = logfile_format_has_i ? FINFO : FCLIENT;
! 745: log_item(code, file, &stats, iflags, xname);
! 746: }
! 747: }
! 748: }
! 749:
! 750:
! 751: /* Perform our quick-check heuristic for determining if a file is unchanged. */
! 752: int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
! 753: {
! 754: if (st->st_size != F_LENGTH(file))
! 755: return 0;
! 756:
! 757: /* if always checksum is set then we use the checksum instead
! 758: of the file time to determine whether to sync */
! 759: if (always_checksum > 0 && S_ISREG(st->st_mode)) {
! 760: char sum[MAX_DIGEST_LEN];
! 761: file_checksum(fn, sum, st->st_size);
! 762: return memcmp(sum, F_SUM(file), checksum_len) == 0;
! 763: }
! 764:
! 765: if (size_only > 0)
! 766: return 1;
! 767:
! 768: if (ignore_times)
! 769: return 0;
! 770:
! 771: return cmp_time(st->st_mtime, file->modtime) == 0;
! 772: }
! 773:
! 774:
! 775: /*
! 776: * set (initialize) the size entries in the per-file sum_struct
! 777: * calculating dynamic block and checksum sizes.
! 778: *
! 779: * This is only called from generate_and_send_sums() but is a separate
! 780: * function to encapsulate the logic.
! 781: *
! 782: * The block size is a rounded square root of file length.
! 783: *
! 784: * The checksum size is determined according to:
! 785: * blocksum_bits = BLOCKSUM_BIAS + 2*log2(file_len) - log2(block_len)
! 786: * provided by Donovan Baarda which gives a probability of rsync
! 787: * algorithm corrupting data and falling back using the whole md4
! 788: * checksums.
! 789: *
! 790: * This might be made one of several selectable heuristics.
! 791: */
! 792: static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
! 793: {
! 794: int32 blength;
! 795: int s2length;
! 796: int64 l;
! 797:
! 798: if (len < 0) {
! 799: /* The file length overflowed our int64 var, so we can't process this file. */
! 800: sum->count = -1; /* indicate overflow error */
! 801: return;
! 802: }
! 803:
! 804: if (block_size)
! 805: blength = block_size;
! 806: else if (len <= BLOCK_SIZE * BLOCK_SIZE)
! 807: blength = BLOCK_SIZE;
! 808: else {
! 809: int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE;
! 810: int32 c;
! 811: int cnt;
! 812: for (c = 1, l = len, cnt = 0; l >>= 2; c <<= 1, cnt++) {}
! 813: if (c < 0 || c >= max_blength)
! 814: blength = max_blength;
! 815: else {
! 816: blength = 0;
! 817: do {
! 818: blength |= c;
! 819: if (len < (int64)blength * blength)
! 820: blength &= ~c;
! 821: c >>= 1;
! 822: } while (c >= 8); /* round to multiple of 8 */
! 823: blength = MAX(blength, BLOCK_SIZE);
! 824: }
! 825: }
! 826:
! 827: if (protocol_version < 27) {
! 828: s2length = csum_length;
! 829: } else if (csum_length == SUM_LENGTH) {
! 830: s2length = SUM_LENGTH;
! 831: } else {
! 832: int32 c;
! 833: int b = BLOCKSUM_BIAS;
! 834: for (l = len; l >>= 1; b += 2) {}
! 835: for (c = blength; (c >>= 1) && b; b--) {}
! 836: /* add a bit, subtract rollsum, round up. */
! 837: s2length = (b + 1 - 32 + 7) / 8; /* --optimize in compiler-- */
! 838: s2length = MAX(s2length, csum_length);
! 839: s2length = MIN(s2length, SUM_LENGTH);
! 840: }
! 841:
! 842: sum->flength = len;
! 843: sum->blength = blength;
! 844: sum->s2length = s2length;
! 845: sum->remainder = (int32)(len % blength);
! 846: sum->count = (int32)(l = (len / blength) + (sum->remainder != 0));
! 847:
! 848: if ((int64)sum->count != l)
! 849: sum->count = -1;
! 850:
! 851: if (sum->count && verbose > 2) {
! 852: rprintf(FINFO,
! 853: "count=%.0f rem=%ld blength=%ld s2length=%d flength=%.0f\n",
! 854: (double)sum->count, (long)sum->remainder, (long)sum->blength,
! 855: sum->s2length, (double)sum->flength);
! 856: }
! 857: }
! 858:
! 859:
! 860: /*
! 861: * Generate and send a stream of signatures/checksums that describe a buffer
! 862: *
! 863: * Generate approximately one checksum every block_len bytes.
! 864: */
! 865: static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
! 866: {
! 867: int32 i;
! 868: struct map_struct *mapbuf;
! 869: struct sum_struct sum;
! 870: OFF_T offset = 0;
! 871:
! 872: sum_sizes_sqroot(&sum, len);
! 873: if (sum.count < 0)
! 874: return -1;
! 875: write_sum_head(f_out, &sum);
! 876:
! 877: if (append_mode > 0 && f_copy < 0)
! 878: return 0;
! 879:
! 880: if (len > 0)
! 881: mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength);
! 882: else
! 883: mapbuf = NULL;
! 884:
! 885: for (i = 0; i < sum.count; i++) {
! 886: int32 n1 = (int32)MIN(len, (OFF_T)sum.blength);
! 887: char *map = map_ptr(mapbuf, offset, n1);
! 888: char sum2[SUM_LENGTH];
! 889: uint32 sum1;
! 890:
! 891: len -= n1;
! 892: offset += n1;
! 893:
! 894: if (f_copy >= 0) {
! 895: full_write(f_copy, map, n1);
! 896: if (append_mode > 0)
! 897: continue;
! 898: }
! 899:
! 900: sum1 = get_checksum1(map, n1);
! 901: get_checksum2(map, n1, sum2);
! 902:
! 903: if (verbose > 3) {
! 904: rprintf(FINFO,
! 905: "chunk[%.0f] offset=%.0f len=%ld sum1=%08lx\n",
! 906: (double)i, (double)offset - n1, (long)n1,
! 907: (unsigned long)sum1);
! 908: }
! 909: write_int(f_out, sum1);
! 910: write_buf(f_out, sum2, sum.s2length);
! 911: }
! 912:
! 913: if (mapbuf)
! 914: unmap_file(mapbuf);
! 915:
! 916: return 0;
! 917: }
! 918:
! 919:
! 920: /* Try to find a filename in the same dir as "fname" with a similar name. */
! 921: static int find_fuzzy(struct file_struct *file, struct file_list *dirlist)
! 922: {
! 923: int fname_len, fname_suf_len;
! 924: const char *fname_suf, *fname = file->basename;
! 925: uint32 lowest_dist = 25 << 16; /* ignore a distance greater than 25 */
! 926: int j, lowest_j = -1;
! 927:
! 928: fname_len = strlen(fname);
! 929: fname_suf = find_filename_suffix(fname, fname_len, &fname_suf_len);
! 930:
! 931: for (j = 0; j < dirlist->used; j++) {
! 932: struct file_struct *fp = dirlist->files[j];
! 933: const char *suf, *name;
! 934: int len, suf_len;
! 935: uint32 dist;
! 936:
! 937: if (!S_ISREG(fp->mode) || !F_LENGTH(fp)
! 938: || fp->flags & FLAG_FILE_SENT)
! 939: continue;
! 940:
! 941: name = fp->basename;
! 942:
! 943: if (F_LENGTH(fp) == F_LENGTH(file)
! 944: && cmp_time(fp->modtime, file->modtime) == 0) {
! 945: if (verbose > 4) {
! 946: rprintf(FINFO,
! 947: "fuzzy size/modtime match for %s\n",
! 948: name);
! 949: }
! 950: return j;
! 951: }
! 952:
! 953: len = strlen(name);
! 954: suf = find_filename_suffix(name, len, &suf_len);
! 955:
! 956: dist = fuzzy_distance(name, len, fname, fname_len);
! 957: /* Add some extra weight to how well the suffixes match. */
! 958: dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len)
! 959: * 10;
! 960: if (verbose > 4) {
! 961: rprintf(FINFO, "fuzzy distance for %s = %d.%05d\n",
! 962: name, (int)(dist>>16), (int)(dist&0xFFFF));
! 963: }
! 964: if (dist <= lowest_dist) {
! 965: lowest_dist = dist;
! 966: lowest_j = j;
! 967: }
! 968: }
! 969:
! 970: return lowest_j;
! 971: }
! 972:
! 973: /* Copy a file found in our --copy-dest handling. */
! 974: static int copy_altdest_file(const char *src, const char *dest, struct file_struct *file)
! 975: {
! 976: char buf[MAXPATHLEN];
! 977: const char *copy_to, *partialptr;
! 978: int save_preserve_xattrs = preserve_xattrs;
! 979: int ok, fd_w;
! 980:
! 981: if (inplace) {
! 982: /* Let copy_file open the destination in place. */
! 983: fd_w = -1;
! 984: copy_to = dest;
! 985: } else {
! 986: fd_w = open_tmpfile(buf, dest, file);
! 987: if (fd_w < 0)
! 988: return -1;
! 989: copy_to = buf;
! 990: }
! 991: cleanup_set(copy_to, NULL, NULL, -1, -1);
! 992: if (copy_file(src, copy_to, fd_w, file->mode, 0) < 0) {
! 993: if (verbose) {
! 994: rsyserr(FINFO, errno, "copy_file %s => %s",
! 995: full_fname(src), copy_to);
! 996: }
! 997: /* Try to clean up. */
! 998: unlink(copy_to);
! 999: cleanup_disable();
! 1000: return -1;
! 1001: }
! 1002: partialptr = partial_dir ? partial_dir_fname(dest) : NULL;
! 1003: preserve_xattrs = 0; /* xattrs were copied with file */
! 1004: ok = finish_transfer(dest, copy_to, src, partialptr, file, 1, 0);
! 1005: preserve_xattrs = save_preserve_xattrs;
! 1006: cleanup_disable();
! 1007: return ok ? 0 : -1;
! 1008: }
! 1009:
! 1010: /* This is only called for regular files. We return -2 if we've finished
! 1011: * handling the file, -1 if no dest-linking occurred, or a non-negative
! 1012: * value if we found an alternate basis file. */
! 1013: static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
! 1014: char *cmpbuf, stat_x *sxp, int itemizing,
! 1015: enum logcode code)
! 1016: {
! 1017: int best_match = -1;
! 1018: int match_level = 0;
! 1019: int j = 0;
! 1020:
! 1021: do {
! 1022: pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
! 1023: if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
! 1024: continue;
! 1025: switch (match_level) {
! 1026: case 0:
! 1027: best_match = j;
! 1028: match_level = 1;
! 1029: /* FALL THROUGH */
! 1030: case 1:
! 1031: if (!unchanged_file(cmpbuf, file, &sxp->st))
! 1032: continue;
! 1033: best_match = j;
! 1034: match_level = 2;
! 1035: /* FALL THROUGH */
! 1036: case 2:
! 1037: if (!unchanged_attrs(cmpbuf, file, sxp))
! 1038: continue;
! 1039: best_match = j;
! 1040: match_level = 3;
! 1041: break;
! 1042: }
! 1043: break;
! 1044: } while (basis_dir[++j] != NULL);
! 1045:
! 1046: if (!match_level)
! 1047: return -1;
! 1048:
! 1049: if (j != best_match) {
! 1050: j = best_match;
! 1051: pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
! 1052: if (link_stat(cmpbuf, &sxp->st, 0) < 0)
! 1053: return -1;
! 1054: }
! 1055:
! 1056: if (match_level == 3 && !copy_dest) {
! 1057: #ifdef SUPPORT_HARD_LINKS
! 1058: if (link_dest) {
! 1059: if (!hard_link_one(file, fname, cmpbuf, 1))
! 1060: goto try_a_copy;
! 1061: if (preserve_hard_links && F_IS_HLINKED(file))
! 1062: finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j);
! 1063: if (!maybe_ATTRS_REPORT && (verbose > 1 || stdout_format_has_i > 1)) {
! 1064: itemize(cmpbuf, file, ndx, 1, sxp,
! 1065: ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
! 1066: 0, "");
! 1067: }
! 1068: } else
! 1069: #endif
! 1070: if (itemizing)
! 1071: itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL);
! 1072: if (verbose > 1 && maybe_ATTRS_REPORT)
! 1073: rprintf(FCLIENT, "%s is uptodate\n", fname);
! 1074: return -2;
! 1075: }
! 1076:
! 1077: if (match_level >= 2) {
! 1078: #ifdef SUPPORT_HARD_LINKS
! 1079: try_a_copy: /* Copy the file locally. */
! 1080: #endif
! 1081: if (!dry_run && copy_altdest_file(cmpbuf, fname, file) < 0)
! 1082: return -1;
! 1083: if (itemizing)
! 1084: itemize(cmpbuf, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
! 1085: if (maybe_ATTRS_REPORT
! 1086: && ((!itemizing && verbose && match_level == 2)
! 1087: || (verbose > 1 && match_level == 3))) {
! 1088: code = match_level == 3 ? FCLIENT : FINFO;
! 1089: rprintf(code, "%s%s\n", fname,
! 1090: match_level == 3 ? " is uptodate" : "");
! 1091: }
! 1092: #ifdef SUPPORT_HARD_LINKS
! 1093: if (preserve_hard_links && F_IS_HLINKED(file))
! 1094: finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, -1);
! 1095: #endif
! 1096: return -2;
! 1097: }
! 1098:
! 1099: return FNAMECMP_BASIS_DIR_LOW + j;
! 1100: }
! 1101:
! 1102: /* This is only called for non-regular files. We return -2 if we've finished
! 1103: * handling the file, or -1 if no dest-linking occurred, or a non-negative
! 1104: * value if we found an alternate basis file. */
! 1105: static int try_dests_non(struct file_struct *file, char *fname, int ndx,
! 1106: char *cmpbuf, stat_x *sxp, int itemizing,
! 1107: enum logcode code)
! 1108: {
! 1109: char lnk[MAXPATHLEN];
! 1110: int best_match = -1;
! 1111: int match_level = 0;
! 1112: enum nonregtype type;
! 1113: uint32 *devp;
! 1114: int len, j = 0;
! 1115:
! 1116: #ifndef SUPPORT_LINKS
! 1117: if (S_ISLNK(file->mode))
! 1118: return -1;
! 1119: #endif
! 1120: if (S_ISDIR(file->mode)) {
! 1121: type = TYPE_DIR;
! 1122: } else if (IS_SPECIAL(file->mode))
! 1123: type = TYPE_SPECIAL;
! 1124: else if (IS_DEVICE(file->mode))
! 1125: type = TYPE_DEVICE;
! 1126: #ifdef SUPPORT_LINKS
! 1127: else if (S_ISLNK(file->mode))
! 1128: type = TYPE_SYMLINK;
! 1129: #endif
! 1130: else {
! 1131: rprintf(FERROR,
! 1132: "internal: try_dests_non() called with invalid mode (%o)\n",
! 1133: (int)file->mode);
! 1134: exit_cleanup(RERR_UNSUPPORTED);
! 1135: }
! 1136:
! 1137: do {
! 1138: pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
! 1139: if (link_stat(cmpbuf, &sxp->st, 0) < 0)
! 1140: continue;
! 1141: switch (type) {
! 1142: case TYPE_DIR:
! 1143: if (!S_ISDIR(sxp->st.st_mode))
! 1144: continue;
! 1145: break;
! 1146: case TYPE_SPECIAL:
! 1147: if (!IS_SPECIAL(sxp->st.st_mode))
! 1148: continue;
! 1149: break;
! 1150: case TYPE_DEVICE:
! 1151: if (!IS_DEVICE(sxp->st.st_mode))
! 1152: continue;
! 1153: break;
! 1154: #ifdef SUPPORT_LINKS
! 1155: case TYPE_SYMLINK:
! 1156: if (!S_ISLNK(sxp->st.st_mode))
! 1157: continue;
! 1158: break;
! 1159: #endif
! 1160: }
! 1161: if (match_level < 1) {
! 1162: match_level = 1;
! 1163: best_match = j;
! 1164: }
! 1165: switch (type) {
! 1166: case TYPE_DIR:
! 1167: case TYPE_SPECIAL:
! 1168: break;
! 1169: case TYPE_DEVICE:
! 1170: devp = F_RDEV_P(file);
! 1171: if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
! 1172: continue;
! 1173: break;
! 1174: #ifdef SUPPORT_LINKS
! 1175: case TYPE_SYMLINK:
! 1176: if ((len = readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0)
! 1177: continue;
! 1178: lnk[len] = '\0';
! 1179: if (strcmp(lnk, F_SYMLINK(file)) != 0)
! 1180: continue;
! 1181: break;
! 1182: #endif
! 1183: }
! 1184: if (match_level < 2) {
! 1185: match_level = 2;
! 1186: best_match = j;
! 1187: }
! 1188: if (unchanged_attrs(cmpbuf, file, sxp)) {
! 1189: match_level = 3;
! 1190: best_match = j;
! 1191: break;
! 1192: }
! 1193: } while (basis_dir[++j] != NULL);
! 1194:
! 1195: if (!match_level)
! 1196: return -1;
! 1197:
! 1198: if (j != best_match) {
! 1199: j = best_match;
! 1200: pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
! 1201: if (link_stat(cmpbuf, &sxp->st, 0) < 0)
! 1202: return -1;
! 1203: }
! 1204:
! 1205: if (match_level == 3) {
! 1206: #ifdef SUPPORT_HARD_LINKS
! 1207: if (link_dest
! 1208: #ifndef CAN_HARDLINK_SYMLINK
! 1209: && !S_ISLNK(file->mode)
! 1210: #endif
! 1211: #ifndef CAN_HARDLINK_SPECIAL
! 1212: && !IS_SPECIAL(file->mode) && !IS_DEVICE(file->mode)
! 1213: #endif
! 1214: && !S_ISDIR(file->mode)) {
! 1215: if (do_link(cmpbuf, fname) < 0) {
! 1216: rsyserr(FERROR_XFER, errno,
! 1217: "failed to hard-link %s with %s",
! 1218: cmpbuf, fname);
! 1219: return j;
! 1220: }
! 1221: if (preserve_hard_links && F_IS_HLINKED(file))
! 1222: finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1);
! 1223: } else
! 1224: #endif
! 1225: match_level = 2;
! 1226: if (itemizing && stdout_format_has_i
! 1227: && (verbose > 1 || stdout_format_has_i > 1)) {
! 1228: int chg = compare_dest && type != TYPE_DIR ? 0
! 1229: : ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
! 1230: char *lp = match_level == 3 ? "" : NULL;
! 1231: itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
! 1232: }
! 1233: if (verbose > 1 && maybe_ATTRS_REPORT) {
! 1234: rprintf(FCLIENT, "%s%s is uptodate\n",
! 1235: fname, type == TYPE_DIR ? "/" : "");
! 1236: }
! 1237: return -2;
! 1238: }
! 1239:
! 1240: return j;
! 1241: }
! 1242:
! 1243: static void list_file_entry(struct file_struct *f)
! 1244: {
! 1245: char permbuf[PERMSTRING_SIZE];
! 1246: double len;
! 1247:
! 1248: if (!F_IS_ACTIVE(f)) {
! 1249: /* this can happen if duplicate names were removed */
! 1250: return;
! 1251: }
! 1252:
! 1253: permstring(permbuf, f->mode);
! 1254: len = F_LENGTH(f);
! 1255:
! 1256: /* TODO: indicate '+' if the entry has an ACL. */
! 1257:
! 1258: #ifdef SUPPORT_LINKS
! 1259: if (preserve_links && S_ISLNK(f->mode)) {
! 1260: rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
! 1261: permbuf, len, timestring(f->modtime),
! 1262: f_name(f, NULL), F_SYMLINK(f));
! 1263: } else
! 1264: #endif
! 1265: {
! 1266: rprintf(FINFO, "%s %11.0f %s %s\n",
! 1267: permbuf, len, timestring(f->modtime),
! 1268: f_name(f, NULL));
! 1269: }
! 1270: }
! 1271:
! 1272: static int phase = 0;
! 1273: static int dflt_perms;
! 1274:
! 1275: static int implied_dirs_are_missing;
! 1276: /* Helper for recv_generator's skip_dir and dry_missing_dir tests. */
! 1277: static BOOL is_below(struct file_struct *file, struct file_struct *subtree)
! 1278: {
! 1279: return F_DEPTH(file) > F_DEPTH(subtree)
! 1280: && (!implied_dirs_are_missing || f_name_has_prefix(file, subtree));
! 1281: }
! 1282:
! 1283: /* Acts on the indicated item in cur_flist whose name is fname. If a dir,
! 1284: * make sure it exists, and has the right permissions/timestamp info. For
! 1285: * all other non-regular files (symlinks, etc.) we create them here. For
! 1286: * regular files that have changed, we try to find a basis file and then
! 1287: * start sending checksums. The ndx is the file's unique index value.
! 1288: *
! 1289: * The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets
! 1290: * passed to delete_item(), which can use it during a recursive delete.)
! 1291: *
! 1292: * Note that f_out is set to -1 when doing final directory-permission and
! 1293: * modification-time repair. */
! 1294: static void recv_generator(char *fname, struct file_struct *file, int ndx,
! 1295: int itemizing, enum logcode code, int f_out)
! 1296: {
! 1297: static const char *parent_dirname = "";
! 1298: /* Missing dir not created due to --dry-run; will still be scanned. */
! 1299: static struct file_struct *dry_missing_dir = NULL;
! 1300: /* Missing dir whose contents are skipped altogether due to
! 1301: * --ignore-non-existing, daemon exclude, or mkdir failure. */
! 1302: static struct file_struct *skip_dir = NULL;
! 1303: static struct file_list *fuzzy_dirlist = NULL;
! 1304: static int need_fuzzy_dirlist = 0;
! 1305: struct file_struct *fuzzy_file = NULL;
! 1306: int fd = -1, f_copy = -1;
! 1307: stat_x sx, real_sx;
! 1308: STRUCT_STAT partial_st;
! 1309: struct file_struct *back_file = NULL;
! 1310: int statret, real_ret, stat_errno;
! 1311: char *fnamecmp, *partialptr, *backupptr = NULL;
! 1312: char fnamecmpbuf[MAXPATHLEN];
! 1313: uchar fnamecmp_type;
! 1314: int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0;
! 1315: int is_dir = !S_ISDIR(file->mode) ? 0
! 1316: : inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1
! 1317: : 1;
! 1318:
! 1319: if (verbose > 2)
! 1320: rprintf(FINFO, "recv_generator(%s,%d)\n", fname, ndx);
! 1321:
! 1322: if (list_only) {
! 1323: if (is_dir < 0
! 1324: || (is_dir && !implied_dirs && file->flags & FLAG_IMPLIED_DIR))
! 1325: return;
! 1326: list_file_entry(file);
! 1327: return;
! 1328: }
! 1329:
! 1330: if (skip_dir) {
! 1331: if (is_below(file, skip_dir)) {
! 1332: if (is_dir)
! 1333: file->flags |= FLAG_MISSING_DIR;
! 1334: #ifdef SUPPORT_HARD_LINKS
! 1335: else if (F_IS_HLINKED(file))
! 1336: handle_skipped_hlink(file, itemizing, code, f_out);
! 1337: #endif
! 1338: return;
! 1339: }
! 1340: skip_dir = NULL;
! 1341: }
! 1342:
! 1343: #ifdef SUPPORT_ACLS
! 1344: sx.acc_acl = sx.def_acl = NULL;
! 1345: #endif
! 1346: #ifdef SUPPORT_XATTRS
! 1347: sx.xattr = NULL;
! 1348: #endif
! 1349: if (daemon_filter_list.head && (*fname != '.' || fname[1])) {
! 1350: if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
! 1351: if (is_dir < 0)
! 1352: return;
! 1353: #ifdef SUPPORT_HARD_LINKS
! 1354: if (F_IS_HLINKED(file))
! 1355: handle_skipped_hlink(file, itemizing, code, f_out);
! 1356: #endif
! 1357: rprintf(FERROR_XFER,
! 1358: "ERROR: daemon refused to receive %s \"%s\"\n",
! 1359: is_dir ? "directory" : "file", fname);
! 1360: if (is_dir)
! 1361: goto skipping_dir_contents;
! 1362: return;
! 1363: }
! 1364: }
! 1365:
! 1366: if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
! 1367: parent_is_dry_missing:
! 1368: if (fuzzy_dirlist) {
! 1369: flist_free(fuzzy_dirlist);
! 1370: fuzzy_dirlist = NULL;
! 1371: }
! 1372: parent_dirname = "";
! 1373: statret = -1;
! 1374: stat_errno = ENOENT;
! 1375: } else {
! 1376: const char *dn = file->dirname ? file->dirname : ".";
! 1377: dry_missing_dir = NULL;
! 1378: if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
! 1379: if (relative_paths && !implied_dirs
! 1380: && do_stat(dn, &sx.st) < 0) {
! 1381: if (dry_run)
! 1382: goto parent_is_dry_missing;
! 1383: if (create_directory_path(fname) < 0) {
! 1384: rsyserr(FERROR_XFER, errno,
! 1385: "recv_generator: mkdir %s failed",
! 1386: full_fname(dn));
! 1387: }
! 1388: }
! 1389: if (fuzzy_dirlist) {
! 1390: flist_free(fuzzy_dirlist);
! 1391: fuzzy_dirlist = NULL;
! 1392: }
! 1393: if (fuzzy_basis)
! 1394: need_fuzzy_dirlist = 1;
! 1395: #ifdef SUPPORT_ACLS
! 1396: if (!preserve_perms)
! 1397: dflt_perms = default_perms_for_dir(dn);
! 1398: #endif
! 1399: }
! 1400: parent_dirname = dn;
! 1401:
! 1402: if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
! 1403: strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
! 1404: fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
! 1405: need_fuzzy_dirlist = 0;
! 1406: }
! 1407:
! 1408: statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
! 1409: stat_errno = errno;
! 1410: }
! 1411:
! 1412: if (ignore_non_existing > 0 && statret == -1 && stat_errno == ENOENT) {
! 1413: if (is_dir) {
! 1414: if (is_dir < 0)
! 1415: return;
! 1416: skip_dir = file;
! 1417: file->flags |= FLAG_MISSING_DIR;
! 1418: }
! 1419: #ifdef SUPPORT_HARD_LINKS
! 1420: else if (F_IS_HLINKED(file))
! 1421: handle_skipped_hlink(file, itemizing, code, f_out);
! 1422: #endif
! 1423: if (verbose > 1) {
! 1424: rprintf(FINFO, "not creating new %s \"%s\"\n",
! 1425: is_dir ? "directory" : "file", fname);
! 1426: }
! 1427: return;
! 1428: }
! 1429:
! 1430: if (statret == 0 && !(sx.st.st_mode & S_IWUSR)
! 1431: && !am_root && sx.st.st_uid == our_uid)
! 1432: del_opts |= DEL_NO_UID_WRITE;
! 1433:
! 1434: if (ignore_existing > 0 && statret == 0
! 1435: && (!is_dir || !S_ISDIR(sx.st.st_mode))) {
! 1436: if (verbose > 1 && is_dir >= 0)
! 1437: rprintf(FINFO, "%s exists\n", fname);
! 1438: #ifdef SUPPORT_HARD_LINKS
! 1439: if (F_IS_HLINKED(file))
! 1440: handle_skipped_hlink(file, itemizing, code, f_out);
! 1441: #endif
! 1442: goto cleanup;
! 1443: }
! 1444:
! 1445: fnamecmp = fname;
! 1446:
! 1447: if (is_dir) {
! 1448: mode_t added_perms;
! 1449: if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)
! 1450: goto cleanup;
! 1451: if (am_root < 0) {
! 1452: /* For --fake-super, the dir must be useable by the copying
! 1453: * user, just like it would be for root. */
! 1454: added_perms = S_IRUSR|S_IWUSR|S_IXUSR;
! 1455: } else
! 1456: added_perms = 0;
! 1457: if (is_dir < 0) {
! 1458: /* In inc_recurse mode we want to make sure any missing
! 1459: * directories get created while we're still processing
! 1460: * the parent dir (which allows us to touch the parent
! 1461: * dir's mtime right away). We will handle the dir in
! 1462: * full later (right before we handle its contents). */
! 1463: if (statret == 0
! 1464: && (S_ISDIR(sx.st.st_mode)
! 1465: || delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_DIR) != 0))
! 1466: goto cleanup; /* Any errors get reported later. */
! 1467: if (do_mkdir(fname, (file->mode|added_perms) & 0700) == 0)
! 1468: file->flags |= FLAG_DIR_CREATED;
! 1469: goto cleanup;
! 1470: }
! 1471: /* The file to be received is a directory, so we need
! 1472: * to prepare appropriately. If there is already a
! 1473: * file of that name and it is *not* a directory, then
! 1474: * we need to delete it. If it doesn't exist, then
! 1475: * (perhaps recursively) create it. */
! 1476: if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
! 1477: if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_DIR) != 0)
! 1478: goto skipping_dir_contents;
! 1479: statret = -1;
! 1480: }
! 1481: if (dry_run && statret != 0) {
! 1482: if (!dry_missing_dir)
! 1483: dry_missing_dir = file;
! 1484: file->flags |= FLAG_MISSING_DIR;
! 1485: }
! 1486: real_ret = statret;
! 1487: real_sx = sx;
! 1488: if (file->flags & FLAG_DIR_CREATED)
! 1489: statret = -1;
! 1490: if (!preserve_perms) { /* See comment in non-dir code below. */
! 1491: file->mode = dest_mode(file->mode, sx.st.st_mode,
! 1492: dflt_perms, statret == 0);
! 1493: }
! 1494: if (statret != 0 && basis_dir[0] != NULL) {
! 1495: int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
! 1496: itemizing, code);
! 1497: if (j == -2) {
! 1498: itemizing = 0;
! 1499: code = FNONE;
! 1500: statret = 1;
! 1501: } else if (j >= 0) {
! 1502: statret = 1;
! 1503: fnamecmp = fnamecmpbuf;
! 1504: }
! 1505: }
! 1506: if (itemizing && f_out != -1) {
! 1507: itemize(fnamecmp, file, ndx, statret, &sx,
! 1508: statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
! 1509: }
! 1510: if (real_ret != 0 && do_mkdir(fname,file->mode|added_perms) < 0 && errno != EEXIST) {
! 1511: if (!relative_paths || errno != ENOENT
! 1512: || create_directory_path(fname) < 0
! 1513: || (do_mkdir(fname, file->mode|added_perms) < 0 && errno != EEXIST)) {
! 1514: rsyserr(FERROR_XFER, errno,
! 1515: "recv_generator: mkdir %s failed",
! 1516: full_fname(fname));
! 1517: skipping_dir_contents:
! 1518: rprintf(FERROR,
! 1519: "*** Skipping any contents from this failed directory ***\n");
! 1520: skip_dir = file;
! 1521: file->flags |= FLAG_MISSING_DIR;
! 1522: goto cleanup;
! 1523: }
! 1524: }
! 1525:
! 1526: #ifdef SUPPORT_XATTRS
! 1527: if (preserve_xattrs && statret == 1)
! 1528: copy_xattrs(fnamecmpbuf, fname);
! 1529: #endif
! 1530: if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
! 1531: && verbose && code != FNONE && f_out != -1)
! 1532: rprintf(code, "%s/\n", fname);
! 1533:
! 1534: /* We need to ensure that the dirs in the transfer have both
! 1535: * readable and writable permissions during the time we are
! 1536: * putting files within them. This is then restored to the
! 1537: * former permissions after the transfer is done. */
! 1538: #ifdef HAVE_CHMOD
! 1539: if (!am_root && (file->mode & S_IRWXU) != S_IRWXU && dir_tweaking) {
! 1540: mode_t mode = file->mode | S_IRWXU;
! 1541: if (do_chmod(fname, mode) < 0) {
! 1542: rsyserr(FERROR_XFER, errno,
! 1543: "failed to modify permissions on %s",
! 1544: full_fname(fname));
! 1545: }
! 1546: need_retouch_dir_perms = 1;
! 1547: }
! 1548: #endif
! 1549:
! 1550: if (real_ret != 0 && one_file_system)
! 1551: real_sx.st.st_dev = filesystem_dev;
! 1552: if (inc_recurse) {
! 1553: if (one_file_system) {
! 1554: uint32 *devp = F_DIR_DEV_P(file);
! 1555: DEV_MAJOR(devp) = major(real_sx.st.st_dev);
! 1556: DEV_MINOR(devp) = minor(real_sx.st.st_dev);
! 1557: }
! 1558: }
! 1559: else if (delete_during && f_out != -1 && !phase
! 1560: && !(file->flags & FLAG_MISSING_DIR)) {
! 1561: if (file->flags & FLAG_CONTENT_DIR)
! 1562: delete_in_dir(fname, file, &real_sx.st.st_dev);
! 1563: else
! 1564: change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
! 1565: }
! 1566: goto cleanup;
! 1567: }
! 1568:
! 1569: /* If we're not preserving permissions, change the file-list's
! 1570: * mode based on the local permissions and some heuristics. */
! 1571: if (!preserve_perms) {
! 1572: int exists = statret == 0 && !S_ISDIR(sx.st.st_mode);
! 1573: file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
! 1574: exists);
! 1575: }
! 1576:
! 1577: #ifdef SUPPORT_HARD_LINKS
! 1578: if (preserve_hard_links && F_HLINK_NOT_FIRST(file)
! 1579: && hard_link_check(file, ndx, fname, statret, &sx, itemizing, code))
! 1580: goto cleanup;
! 1581: #endif
! 1582:
! 1583: if (preserve_links && S_ISLNK(file->mode)) {
! 1584: #ifdef SUPPORT_LINKS
! 1585: const char *sl = F_SYMLINK(file);
! 1586: if (safe_symlinks && unsafe_symlink(sl, fname)) {
! 1587: if (verbose) {
! 1588: if (solo_file) {
! 1589: /* fname contains the destination path, but we
! 1590: * want to report the source path. */
! 1591: fname = f_name(file, NULL);
! 1592: }
! 1593: rprintf(FINFO,
! 1594: "ignoring unsafe symlink \"%s\" -> \"%s\"\n",
! 1595: fname, sl);
! 1596: }
! 1597: return;
! 1598: }
! 1599: if (statret == 0) {
! 1600: char lnk[MAXPATHLEN];
! 1601: int len;
! 1602:
! 1603: if (!S_ISLNK(sx.st.st_mode))
! 1604: statret = -1;
! 1605: else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0
! 1606: && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') {
! 1607: /* The link is pointing to the right place. */
! 1608: set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
! 1609: if (itemizing)
! 1610: itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
! 1611: #if defined SUPPORT_HARD_LINKS && defined CAN_HARDLINK_SYMLINK
! 1612: if (preserve_hard_links && F_IS_HLINKED(file))
! 1613: finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
! 1614: #endif
! 1615: if (remove_source_files == 1)
! 1616: goto return_with_success;
! 1617: goto cleanup;
! 1618: }
! 1619: /* Not the right symlink (or not a symlink), so
! 1620: * delete it. */
! 1621: if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_SYMLINK) != 0)
! 1622: goto cleanup;
! 1623: } else if (basis_dir[0] != NULL) {
! 1624: int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
! 1625: itemizing, code);
! 1626: if (j == -2) {
! 1627: #ifndef CAN_HARDLINK_SYMLINK
! 1628: if (link_dest) {
! 1629: /* Resort to --copy-dest behavior. */
! 1630: } else
! 1631: #endif
! 1632: if (!copy_dest)
! 1633: goto cleanup;
! 1634: itemizing = 0;
! 1635: code = FNONE;
! 1636: } else if (j >= 0)
! 1637: statret = 1;
! 1638: }
! 1639: #ifdef SUPPORT_HARD_LINKS
! 1640: if (preserve_hard_links && F_HLINK_NOT_LAST(file)) {
! 1641: cur_flist->in_progress++;
! 1642: goto cleanup;
! 1643: }
! 1644: #endif
! 1645: if (do_symlink(sl, fname) != 0) {
! 1646: rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
! 1647: full_fname(fname), sl);
! 1648: } else {
! 1649: set_file_attrs(fname, file, NULL, NULL, 0);
! 1650: if (itemizing) {
! 1651: itemize(fname, file, ndx, statret, &sx,
! 1652: ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
! 1653: }
! 1654: if (code != FNONE && verbose)
! 1655: rprintf(code, "%s -> %s\n", fname, sl);
! 1656: #ifdef SUPPORT_HARD_LINKS
! 1657: if (preserve_hard_links && F_IS_HLINKED(file))
! 1658: finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1);
! 1659: #endif
! 1660: /* This does not check remove_source_files == 1
! 1661: * because this is one of the items that the old
! 1662: * --remove-sent-files option would remove. */
! 1663: if (remove_source_files)
! 1664: goto return_with_success;
! 1665: }
! 1666: #endif
! 1667: goto cleanup;
! 1668: }
! 1669:
! 1670: if ((am_root && preserve_devices && IS_DEVICE(file->mode))
! 1671: || (preserve_specials && IS_SPECIAL(file->mode))) {
! 1672: dev_t rdev;
! 1673: if (IS_DEVICE(file->mode)) {
! 1674: uint32 *devp = F_RDEV_P(file);
! 1675: rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
! 1676: } else
! 1677: rdev = 0;
! 1678: if (statret == 0) {
! 1679: int del_for_flag;
! 1680: if (IS_DEVICE(file->mode)) {
! 1681: if (!IS_DEVICE(sx.st.st_mode))
! 1682: statret = -1;
! 1683: del_for_flag = DEL_FOR_DEVICE;
! 1684: } else {
! 1685: if (!IS_SPECIAL(sx.st.st_mode))
! 1686: statret = -1;
! 1687: del_for_flag = DEL_FOR_SPECIAL;
! 1688: }
! 1689: if (statret == 0
! 1690: && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
! 1691: && (IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev == rdev)) {
! 1692: /* The device or special file is identical. */
! 1693: set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
! 1694: if (itemizing)
! 1695: itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
! 1696: #ifdef SUPPORT_HARD_LINKS
! 1697: if (preserve_hard_links && F_IS_HLINKED(file))
! 1698: finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
! 1699: #endif
! 1700: if (remove_source_files == 1)
! 1701: goto return_with_success;
! 1702: goto cleanup;
! 1703: }
! 1704: if (delete_item(fname, sx.st.st_mode, del_opts | del_for_flag) != 0)
! 1705: goto cleanup;
! 1706: } else if (basis_dir[0] != NULL) {
! 1707: int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
! 1708: itemizing, code);
! 1709: if (j == -2) {
! 1710: #ifndef CAN_HARDLINK_SPECIAL
! 1711: if (link_dest) {
! 1712: /* Resort to --copy-dest behavior. */
! 1713: } else
! 1714: #endif
! 1715: if (!copy_dest)
! 1716: goto cleanup;
! 1717: itemizing = 0;
! 1718: code = FNONE;
! 1719: } else if (j >= 0)
! 1720: statret = 1;
! 1721: }
! 1722: #ifdef SUPPORT_HARD_LINKS
! 1723: if (preserve_hard_links && F_HLINK_NOT_LAST(file)) {
! 1724: cur_flist->in_progress++;
! 1725: goto cleanup;
! 1726: }
! 1727: #endif
! 1728: if (verbose > 2) {
! 1729: rprintf(FINFO, "mknod(%s, 0%o, [%ld,%ld])\n",
! 1730: fname, (int)file->mode,
! 1731: (long)major(rdev), (long)minor(rdev));
! 1732: }
! 1733: if (do_mknod(fname, file->mode, rdev) < 0) {
! 1734: rsyserr(FERROR_XFER, errno, "mknod %s failed",
! 1735: full_fname(fname));
! 1736: } else {
! 1737: set_file_attrs(fname, file, NULL, NULL, 0);
! 1738: if (itemizing) {
! 1739: itemize(fname, file, ndx, statret, &sx,
! 1740: ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
! 1741: }
! 1742: if (code != FNONE && verbose)
! 1743: rprintf(code, "%s\n", fname);
! 1744: #ifdef SUPPORT_HARD_LINKS
! 1745: if (preserve_hard_links && F_IS_HLINKED(file))
! 1746: finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1);
! 1747: #endif
! 1748: if (remove_source_files == 1)
! 1749: goto return_with_success;
! 1750: }
! 1751: goto cleanup;
! 1752: }
! 1753:
! 1754: if (!S_ISREG(file->mode)) {
! 1755: if (solo_file)
! 1756: fname = f_name(file, NULL);
! 1757: rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname);
! 1758: goto cleanup;
! 1759: }
! 1760:
! 1761: if (max_size > 0 && F_LENGTH(file) > max_size) {
! 1762: if (verbose > 1) {
! 1763: if (solo_file)
! 1764: fname = f_name(file, NULL);
! 1765: rprintf(FINFO, "%s is over max-size\n", fname);
! 1766: }
! 1767: goto cleanup;
! 1768: }
! 1769: if (min_size > 0 && F_LENGTH(file) < min_size) {
! 1770: if (verbose > 1) {
! 1771: if (solo_file)
! 1772: fname = f_name(file, NULL);
! 1773: rprintf(FINFO, "%s is under min-size\n", fname);
! 1774: }
! 1775: goto cleanup;
! 1776: }
! 1777:
! 1778: if (update_only > 0 && statret == 0
! 1779: && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
! 1780: if (verbose > 1)
! 1781: rprintf(FINFO, "%s is newer\n", fname);
! 1782: #ifdef SUPPORT_HARD_LINKS
! 1783: if (F_IS_HLINKED(file))
! 1784: handle_skipped_hlink(file, itemizing, code, f_out);
! 1785: #endif
! 1786: goto cleanup;
! 1787: }
! 1788:
! 1789: fnamecmp_type = FNAMECMP_FNAME;
! 1790:
! 1791: if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
! 1792: if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0)
! 1793: goto cleanup;
! 1794: statret = -1;
! 1795: stat_errno = ENOENT;
! 1796: }
! 1797:
! 1798: if (statret != 0 && basis_dir[0] != NULL) {
! 1799: int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
! 1800: itemizing, code);
! 1801: if (j == -2) {
! 1802: if (remove_source_files == 1)
! 1803: goto return_with_success;
! 1804: goto cleanup;
! 1805: }
! 1806: if (j >= 0) {
! 1807: fnamecmp = fnamecmpbuf;
! 1808: fnamecmp_type = j;
! 1809: statret = 0;
! 1810: }
! 1811: }
! 1812:
! 1813: real_ret = statret;
! 1814: real_sx = sx;
! 1815:
! 1816: if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
! 1817: && link_stat(partialptr, &partial_st, 0) == 0
! 1818: && S_ISREG(partial_st.st_mode)) {
! 1819: if (statret != 0)
! 1820: goto prepare_to_open;
! 1821: } else
! 1822: partialptr = NULL;
! 1823:
! 1824: if (statret != 0 && fuzzy_dirlist) {
! 1825: int j = find_fuzzy(file, fuzzy_dirlist);
! 1826: if (j >= 0) {
! 1827: fuzzy_file = fuzzy_dirlist->files[j];
! 1828: f_name(fuzzy_file, fnamecmpbuf);
! 1829: if (verbose > 2) {
! 1830: rprintf(FINFO, "fuzzy basis selected for %s: %s\n",
! 1831: fname, fnamecmpbuf);
! 1832: }
! 1833: sx.st.st_size = F_LENGTH(fuzzy_file);
! 1834: statret = 0;
! 1835: fnamecmp = fnamecmpbuf;
! 1836: fnamecmp_type = FNAMECMP_FUZZY;
! 1837: }
! 1838: }
! 1839:
! 1840: if (statret != 0) {
! 1841: #ifdef SUPPORT_HARD_LINKS
! 1842: if (preserve_hard_links && F_HLINK_NOT_LAST(file)) {
! 1843: cur_flist->in_progress++;
! 1844: goto cleanup;
! 1845: }
! 1846: #endif
! 1847: if (stat_errno == ENOENT)
! 1848: goto notify_others;
! 1849: rsyserr(FERROR_XFER, stat_errno, "recv_generator: failed to stat %s",
! 1850: full_fname(fname));
! 1851: goto cleanup;
! 1852: }
! 1853:
! 1854: if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
! 1855: ;
! 1856: else if (fnamecmp_type == FNAMECMP_FUZZY)
! 1857: ;
! 1858: else if (unchanged_file(fnamecmp, file, &sx.st)) {
! 1859: if (partialptr) {
! 1860: do_unlink(partialptr);
! 1861: handle_partial_dir(partialptr, PDIR_DELETE);
! 1862: }
! 1863: set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
! 1864: if (itemizing)
! 1865: itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
! 1866: #ifdef SUPPORT_HARD_LINKS
! 1867: if (preserve_hard_links && F_IS_HLINKED(file))
! 1868: finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
! 1869: #endif
! 1870: if (remove_source_files != 1)
! 1871: goto cleanup;
! 1872: return_with_success:
! 1873: if (!dry_run)
! 1874: send_msg_int(MSG_SUCCESS, ndx);
! 1875: goto cleanup;
! 1876: }
! 1877:
! 1878: if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file)) {
! 1879: #ifdef SUPPORT_HARD_LINKS
! 1880: if (F_IS_HLINKED(file))
! 1881: handle_skipped_hlink(file, itemizing, code, f_out);
! 1882: #endif
! 1883: goto cleanup;
! 1884: }
! 1885:
! 1886: prepare_to_open:
! 1887: if (partialptr) {
! 1888: sx.st = partial_st;
! 1889: fnamecmp = partialptr;
! 1890: fnamecmp_type = FNAMECMP_PARTIAL_DIR;
! 1891: statret = 0;
! 1892: }
! 1893:
! 1894: if (!do_xfers)
! 1895: goto notify_others;
! 1896:
! 1897: if (read_batch || whole_file) {
! 1898: if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
! 1899: if (!(backupptr = get_backup_name(fname)))
! 1900: goto cleanup;
! 1901: if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
! 1902: goto pretend_missing;
! 1903: if (copy_file(fname, backupptr, -1, back_file->mode, 1) < 0) {
! 1904: unmake_file(back_file);
! 1905: back_file = NULL;
! 1906: goto cleanup;
! 1907: }
! 1908: }
! 1909: goto notify_others;
! 1910: }
! 1911:
! 1912: if (fuzzy_dirlist) {
! 1913: int j = flist_find(fuzzy_dirlist, file);
! 1914: if (j >= 0) /* don't use changing file as future fuzzy basis */
! 1915: fuzzy_dirlist->files[j]->flags |= FLAG_FILE_SENT;
! 1916: }
! 1917:
! 1918: /* open the file */
! 1919: if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
! 1920: rsyserr(FERROR, errno, "failed to open %s, continuing",
! 1921: full_fname(fnamecmp));
! 1922: pretend_missing:
! 1923: /* pretend the file didn't exist */
! 1924: #ifdef SUPPORT_HARD_LINKS
! 1925: if (preserve_hard_links && F_HLINK_NOT_LAST(file)) {
! 1926: cur_flist->in_progress++;
! 1927: goto cleanup;
! 1928: }
! 1929: #endif
! 1930: statret = real_ret = -1;
! 1931: goto notify_others;
! 1932: }
! 1933:
! 1934: if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
! 1935: if (!(backupptr = get_backup_name(fname))) {
! 1936: close(fd);
! 1937: goto cleanup;
! 1938: }
! 1939: if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
! 1940: close(fd);
! 1941: goto pretend_missing;
! 1942: }
! 1943: if (robust_unlink(backupptr) && errno != ENOENT) {
! 1944: rsyserr(FERROR_XFER, errno, "unlink %s",
! 1945: full_fname(backupptr));
! 1946: unmake_file(back_file);
! 1947: back_file = NULL;
! 1948: close(fd);
! 1949: goto cleanup;
! 1950: }
! 1951: if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
! 1952: int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
! 1953: if (errno == ENOENT && make_bak_dir(backupptr) == 0) {
! 1954: if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0)
! 1955: save_errno = errno ? errno : save_errno;
! 1956: else
! 1957: save_errno = 0;
! 1958: }
! 1959: if (save_errno) {
! 1960: rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(backupptr));
! 1961: unmake_file(back_file);
! 1962: back_file = NULL;
! 1963: close(fd);
! 1964: goto cleanup;
! 1965: }
! 1966: }
! 1967: fnamecmp_type = FNAMECMP_BACKUP;
! 1968: }
! 1969:
! 1970: if (verbose > 3) {
! 1971: rprintf(FINFO, "gen mapped %s of size %.0f\n",
! 1972: fnamecmp, (double)sx.st.st_size);
! 1973: }
! 1974:
! 1975: if (verbose > 2)
! 1976: rprintf(FINFO, "generating and sending sums for %d\n", ndx);
! 1977:
! 1978: notify_others:
! 1979: if (remove_source_files && !delay_updates && !phase && !dry_run)
! 1980: increment_active_files(ndx, itemizing, code);
! 1981: if (inc_recurse && !dry_run)
! 1982: cur_flist->in_progress++;
! 1983: #ifdef SUPPORT_HARD_LINKS
! 1984: if (preserve_hard_links && F_IS_HLINKED(file))
! 1985: file->flags |= FLAG_FILE_SENT;
! 1986: #endif
! 1987: write_ndx(f_out, ndx);
! 1988: if (itemizing) {
! 1989: int iflags = ITEM_TRANSFER;
! 1990: if (always_checksum > 0)
! 1991: iflags |= ITEM_REPORT_CHANGE;
! 1992: if (fnamecmp_type != FNAMECMP_FNAME)
! 1993: iflags |= ITEM_BASIS_TYPE_FOLLOWS;
! 1994: if (fnamecmp_type == FNAMECMP_FUZZY)
! 1995: iflags |= ITEM_XNAME_FOLLOWS;
! 1996: itemize(fnamecmp, file, -1, real_ret, &real_sx, iflags, fnamecmp_type,
! 1997: fuzzy_file ? fuzzy_file->basename : NULL);
! 1998: #ifdef SUPPORT_ACLS
! 1999: if (preserve_acls)
! 2000: free_acl(&real_sx);
! 2001: #endif
! 2002: #ifdef SUPPORT_XATTRS
! 2003: if (preserve_xattrs)
! 2004: free_xattr(&real_sx);
! 2005: #endif
! 2006: }
! 2007:
! 2008: if (!do_xfers) {
! 2009: #ifdef SUPPORT_HARD_LINKS
! 2010: if (preserve_hard_links && F_IS_HLINKED(file))
! 2011: finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
! 2012: #endif
! 2013: goto cleanup;
! 2014: }
! 2015: if (read_batch)
! 2016: goto cleanup;
! 2017:
! 2018: if (statret != 0 || whole_file)
! 2019: write_sum_head(f_out, NULL);
! 2020: else if (sx.st.st_size <= 0) {
! 2021: write_sum_head(f_out, NULL);
! 2022: close(fd);
! 2023: } else {
! 2024: if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
! 2025: rprintf(FWARNING,
! 2026: "WARNING: file is too large for checksum sending: %s\n",
! 2027: fnamecmp);
! 2028: write_sum_head(f_out, NULL);
! 2029: }
! 2030: close(fd);
! 2031: }
! 2032:
! 2033: cleanup:
! 2034: if (back_file) {
! 2035: int save_preserve_xattrs = preserve_xattrs;
! 2036: if (f_copy >= 0)
! 2037: close(f_copy);
! 2038: #ifdef SUPPORT_XATTRS
! 2039: if (preserve_xattrs) {
! 2040: copy_xattrs(fname, backupptr);
! 2041: preserve_xattrs = 0;
! 2042: }
! 2043: #endif
! 2044: set_file_attrs(backupptr, back_file, NULL, NULL, 0);
! 2045: preserve_xattrs = save_preserve_xattrs;
! 2046: if (verbose > 1) {
! 2047: rprintf(FINFO, "backed up %s to %s\n",
! 2048: fname, backupptr);
! 2049: }
! 2050: unmake_file(back_file);
! 2051: }
! 2052:
! 2053: #ifdef SUPPORT_ACLS
! 2054: if (preserve_acls)
! 2055: free_acl(&sx);
! 2056: #endif
! 2057: #ifdef SUPPORT_XATTRS
! 2058: if (preserve_xattrs)
! 2059: free_xattr(&sx);
! 2060: #endif
! 2061: return;
! 2062: }
! 2063:
! 2064: #ifdef SUPPORT_HARD_LINKS
! 2065: static void handle_skipped_hlink(struct file_struct *file, int itemizing,
! 2066: enum logcode code, int f_out)
! 2067: {
! 2068: char fbuf[MAXPATHLEN];
! 2069: int new_last_ndx;
! 2070: struct file_list *save_flist = cur_flist;
! 2071:
! 2072: /* If we skip the last item in a chain of links and there was a
! 2073: * prior non-skipped hard-link waiting to finish, finish it now. */
! 2074: if ((new_last_ndx = skip_hard_link(file, &cur_flist)) < 0)
! 2075: return;
! 2076:
! 2077: file = cur_flist->files[new_last_ndx - cur_flist->ndx_start];
! 2078: cur_flist->in_progress--; /* undo prior increment */
! 2079: f_name(file, fbuf);
! 2080: recv_generator(fbuf, file, new_last_ndx, itemizing, code, f_out);
! 2081:
! 2082: cur_flist = save_flist;
! 2083: }
! 2084: #endif
! 2085:
! 2086: static void touch_up_dirs(struct file_list *flist, int ndx)
! 2087: {
! 2088: static int counter = 0;
! 2089: struct file_struct *file;
! 2090: char *fname;
! 2091: BOOL fix_dir_perms;
! 2092: int i, start, end;
! 2093:
! 2094: if (ndx < 0) {
! 2095: start = 0;
! 2096: end = flist->used - 1;
! 2097: } else
! 2098: start = end = ndx;
! 2099:
! 2100: /* Fix any directory permissions that were modified during the
! 2101: * transfer and/or re-set any tweaked modified-time values. */
! 2102: for (i = start; i <= end; i++, counter++) {
! 2103: file = flist->files[i];
! 2104: if (!S_ISDIR(file->mode)
! 2105: || (!implied_dirs && file->flags & FLAG_IMPLIED_DIR))
! 2106: continue;
! 2107: if (verbose > 3) {
! 2108: fname = f_name(file, NULL);
! 2109: rprintf(FINFO, "touch_up_dirs: %s (%d)\n",
! 2110: NS(fname), i);
! 2111: }
! 2112: /* Be sure not to retouch permissions with --fake-super. */
! 2113: fix_dir_perms = !am_root && !(file->mode & S_IWUSR);
! 2114: if (!F_IS_ACTIVE(file) || file->flags & FLAG_MISSING_DIR
! 2115: || !(need_retouch_dir_times || fix_dir_perms))
! 2116: continue;
! 2117: fname = f_name(file, NULL);
! 2118: if (fix_dir_perms)
! 2119: do_chmod(fname, file->mode);
! 2120: if (need_retouch_dir_times) {
! 2121: STRUCT_STAT st;
! 2122: if (link_stat(fname, &st, 0) == 0
! 2123: && cmp_time(st.st_mtime, file->modtime) != 0)
! 2124: set_modtime(fname, file->modtime, file->mode);
! 2125: }
! 2126: if (counter >= loopchk_limit) {
! 2127: if (allowed_lull)
! 2128: maybe_send_keepalive();
! 2129: else
! 2130: maybe_flush_socket(0);
! 2131: counter = 0;
! 2132: }
! 2133: }
! 2134: }
! 2135:
! 2136: void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
! 2137: {
! 2138: struct file_struct *file;
! 2139: struct file_list *flist;
! 2140: char fbuf[MAXPATHLEN];
! 2141: int ndx;
! 2142:
! 2143: while (1) {
! 2144: #ifdef SUPPORT_HARD_LINKS
! 2145: if (preserve_hard_links && (ndx = get_hlink_num()) != -1) {
! 2146: int send_failed = (ndx == -2);
! 2147: if (send_failed)
! 2148: ndx = get_hlink_num();
! 2149: flist = flist_for_ndx(ndx, "check_for_finished_files.1");
! 2150: file = flist->files[ndx - flist->ndx_start];
! 2151: assert(file->flags & FLAG_HLINKED);
! 2152: if (send_failed)
! 2153: handle_skipped_hlink(file, itemizing, code, sock_f_out);
! 2154: else
! 2155: finish_hard_link(file, f_name(file, fbuf), ndx, NULL, itemizing, code, -1);
! 2156: flist->in_progress--;
! 2157: continue;
! 2158: }
! 2159: #endif
! 2160:
! 2161: if (check_redo && (ndx = get_redo_num()) != -1) {
! 2162: csum_length = SUM_LENGTH;
! 2163: max_size = -max_size;
! 2164: min_size = -min_size;
! 2165: ignore_existing = -ignore_existing;
! 2166: ignore_non_existing = -ignore_non_existing;
! 2167: update_only = -update_only;
! 2168: always_checksum = -always_checksum;
! 2169: size_only = -size_only;
! 2170: append_mode = -append_mode;
! 2171: make_backups = -make_backups; /* avoid dup backup w/inplace */
! 2172: ignore_times++;
! 2173:
! 2174: flist = cur_flist;
! 2175: cur_flist = flist_for_ndx(ndx, "check_for_finished_files.2");
! 2176:
! 2177: file = cur_flist->files[ndx - cur_flist->ndx_start];
! 2178: if (solo_file)
! 2179: strlcpy(fbuf, solo_file, sizeof fbuf);
! 2180: else
! 2181: f_name(file, fbuf);
! 2182: recv_generator(fbuf, file, ndx, itemizing, code, sock_f_out);
! 2183: cur_flist->to_redo--;
! 2184:
! 2185: cur_flist = flist;
! 2186:
! 2187: csum_length = SHORT_SUM_LENGTH;
! 2188: max_size = -max_size;
! 2189: min_size = -min_size;
! 2190: ignore_existing = -ignore_existing;
! 2191: ignore_non_existing = -ignore_non_existing;
! 2192: update_only = -update_only;
! 2193: always_checksum = -always_checksum;
! 2194: size_only = -size_only;
! 2195: append_mode = -append_mode;
! 2196: make_backups = -make_backups;
! 2197: ignore_times--;
! 2198: continue;
! 2199: }
! 2200:
! 2201: if (cur_flist == first_flist)
! 2202: break;
! 2203:
! 2204: /* We only get here if inc_recurse is enabled. */
! 2205: if (first_flist->in_progress || first_flist->to_redo)
! 2206: break;
! 2207:
! 2208: write_ndx(sock_f_out, NDX_DONE);
! 2209: if (!read_batch)
! 2210: maybe_flush_socket(1);
! 2211:
! 2212: if (delete_during == 2 || !dir_tweaking) {
! 2213: /* Skip directory touch-up. */
! 2214: } else if (first_flist->parent_ndx >= 0)
! 2215: touch_up_dirs(dir_flist, first_flist->parent_ndx);
! 2216:
! 2217: flist_free(first_flist); /* updates first_flist */
! 2218: }
! 2219: }
! 2220:
! 2221: void generate_files(int f_out, const char *local_name)
! 2222: {
! 2223: int i, ndx, next_loopchk = 0;
! 2224: char fbuf[MAXPATHLEN];
! 2225: int itemizing;
! 2226: enum logcode code;
! 2227: int save_do_progress = do_progress;
! 2228:
! 2229: if (protocol_version >= 29) {
! 2230: itemizing = 1;
! 2231: maybe_ATTRS_REPORT = stdout_format_has_i ? 0 : ATTRS_REPORT;
! 2232: code = logfile_format_has_i ? FNONE : FLOG;
! 2233: } else if (am_daemon) {
! 2234: itemizing = logfile_format_has_i && do_xfers;
! 2235: maybe_ATTRS_REPORT = ATTRS_REPORT;
! 2236: code = itemizing || !do_xfers ? FCLIENT : FINFO;
! 2237: } else if (!am_server) {
! 2238: itemizing = stdout_format_has_i;
! 2239: maybe_ATTRS_REPORT = stdout_format_has_i ? 0 : ATTRS_REPORT;
! 2240: code = itemizing ? FNONE : FINFO;
! 2241: } else {
! 2242: itemizing = 0;
! 2243: maybe_ATTRS_REPORT = ATTRS_REPORT;
! 2244: code = FINFO;
! 2245: }
! 2246: solo_file = local_name;
! 2247: dir_tweaking = !(list_only || solo_file || dry_run);
! 2248: need_retouch_dir_times = preserve_times & PRESERVE_DIR_TIMES;
! 2249: loopchk_limit = allowed_lull ? allowed_lull * 5 : 200;
! 2250: symlink_timeset_failed_flags = ITEM_REPORT_TIME
! 2251: | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
! 2252: implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
! 2253:
! 2254: if (verbose > 2)
! 2255: rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());
! 2256:
! 2257: if (delete_before && !solo_file && cur_flist->used > 0)
! 2258: do_delete_pass();
! 2259: if (delete_during == 2) {
! 2260: deldelay_size = BIGPATHBUFLEN * 4;
! 2261: deldelay_buf = new_array(char, deldelay_size);
! 2262: if (!deldelay_buf)
! 2263: out_of_memory("delete-delay");
! 2264: }
! 2265: do_progress = 0;
! 2266:
! 2267: if (append_mode > 0 || whole_file < 0)
! 2268: whole_file = 0;
! 2269: if (verbose >= 2) {
! 2270: rprintf(FINFO, "delta-transmission %s\n",
! 2271: whole_file
! 2272: ? "disabled for local transfer or --whole-file"
! 2273: : "enabled");
! 2274: }
! 2275:
! 2276: /* Since we often fill up the outgoing socket and then just sit around
! 2277: * waiting for the other 2 processes to do their thing, we don't want
! 2278: * to exit on a timeout. If the data stops flowing, the receiver will
! 2279: * notice that and let us know via the message pipe (or its closing). */
! 2280: ignore_timeout = 1;
! 2281:
! 2282: dflt_perms = (ACCESSPERMS & ~orig_umask);
! 2283:
! 2284: do {
! 2285: #ifdef SUPPORT_HARD_LINKS
! 2286: if (preserve_hard_links && inc_recurse) {
! 2287: while (!flist_eof && file_total < FILECNT_LOOKAHEAD/2)
! 2288: wait_for_receiver();
! 2289: }
! 2290: #endif
! 2291:
! 2292: if (inc_recurse && cur_flist->parent_ndx >= 0) {
! 2293: struct file_struct *fp = dir_flist->files[cur_flist->parent_ndx];
! 2294: if (solo_file)
! 2295: strlcpy(fbuf, solo_file, sizeof fbuf);
! 2296: else
! 2297: f_name(fp, fbuf);
! 2298: ndx = cur_flist->ndx_start - 1;
! 2299: recv_generator(fbuf, fp, ndx, itemizing, code, f_out);
! 2300: if (delete_during && dry_run < 2 && !list_only
! 2301: && !(fp->flags & FLAG_MISSING_DIR)) {
! 2302: if (fp->flags & FLAG_CONTENT_DIR) {
! 2303: dev_t dirdev;
! 2304: if (one_file_system) {
! 2305: uint32 *devp = F_DIR_DEV_P(fp);
! 2306: dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
! 2307: } else
! 2308: dirdev = MAKEDEV(0, 0);
! 2309: delete_in_dir(fbuf, fp, &dirdev);
! 2310: } else
! 2311: change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
! 2312: }
! 2313: }
! 2314: for (i = cur_flist->low; i <= cur_flist->high; i++) {
! 2315: struct file_struct *file = cur_flist->sorted[i];
! 2316:
! 2317: if (!F_IS_ACTIVE(file))
! 2318: continue;
! 2319:
! 2320: if (unsort_ndx)
! 2321: ndx = F_NDX(file);
! 2322: else
! 2323: ndx = i + cur_flist->ndx_start;
! 2324:
! 2325: if (solo_file)
! 2326: strlcpy(fbuf, solo_file, sizeof fbuf);
! 2327: else
! 2328: f_name(file, fbuf);
! 2329: recv_generator(fbuf, file, ndx, itemizing, code, f_out);
! 2330:
! 2331: check_for_finished_files(itemizing, code, 0);
! 2332:
! 2333: if (i + cur_flist->ndx_start >= next_loopchk) {
! 2334: if (allowed_lull)
! 2335: maybe_send_keepalive();
! 2336: else
! 2337: maybe_flush_socket(0);
! 2338: next_loopchk += loopchk_limit;
! 2339: }
! 2340: }
! 2341:
! 2342: if (!inc_recurse) {
! 2343: write_ndx(f_out, NDX_DONE);
! 2344: break;
! 2345: }
! 2346:
! 2347: while (1) {
! 2348: check_for_finished_files(itemizing, code, 1);
! 2349: if (cur_flist->next || flist_eof)
! 2350: break;
! 2351: wait_for_receiver();
! 2352: }
! 2353: } while ((cur_flist = cur_flist->next) != NULL);
! 2354:
! 2355: if (delete_during)
! 2356: delete_in_dir(NULL, NULL, &dev_zero);
! 2357: phase++;
! 2358: if (verbose > 2)
! 2359: rprintf(FINFO, "generate_files phase=%d\n", phase);
! 2360:
! 2361: while (1) {
! 2362: check_for_finished_files(itemizing, code, 1);
! 2363: if (msgdone_cnt)
! 2364: break;
! 2365: wait_for_receiver();
! 2366: }
! 2367:
! 2368: phase++;
! 2369: if (verbose > 2)
! 2370: rprintf(FINFO, "generate_files phase=%d\n", phase);
! 2371:
! 2372: write_ndx(f_out, NDX_DONE);
! 2373:
! 2374: /* Reduce round-trip lag-time for a useless delay-updates phase. */
! 2375: if (protocol_version >= 29 && !delay_updates)
! 2376: write_ndx(f_out, NDX_DONE);
! 2377:
! 2378: /* Read MSG_DONE for the redo phase (and any prior messages). */
! 2379: while (1) {
! 2380: check_for_finished_files(itemizing, code, 0);
! 2381: if (msgdone_cnt > 1)
! 2382: break;
! 2383: wait_for_receiver();
! 2384: }
! 2385:
! 2386: if (protocol_version >= 29) {
! 2387: phase++;
! 2388: if (verbose > 2)
! 2389: rprintf(FINFO, "generate_files phase=%d\n", phase);
! 2390: if (delay_updates)
! 2391: write_ndx(f_out, NDX_DONE);
! 2392: /* Read MSG_DONE for delay-updates phase & prior messages. */
! 2393: while (msgdone_cnt == 2)
! 2394: wait_for_receiver();
! 2395: }
! 2396:
! 2397: do_progress = save_do_progress;
! 2398: if (delete_during == 2)
! 2399: do_delayed_deletions(fbuf);
! 2400: if (delete_after && !solo_file && file_total > 0)
! 2401: do_delete_pass();
! 2402:
! 2403: if ((need_retouch_dir_perms || need_retouch_dir_times)
! 2404: && dir_tweaking && (!inc_recurse || delete_during == 2))
! 2405: touch_up_dirs(dir_flist, -1);
! 2406:
! 2407: if (max_delete >= 0 && deletion_count > max_delete) {
! 2408: rprintf(FWARNING,
! 2409: "Deletions stopped due to --max-delete limit (%d skipped)\n",
! 2410: deletion_count - max_delete);
! 2411: io_error |= IOERR_DEL_LIMIT;
! 2412: }
! 2413:
! 2414: if (verbose > 2)
! 2415: rprintf(FINFO, "generate_files finished\n");
! 2416: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>