diff -urN rsync-3.0.2-orig/generator.c rsync-3.0.2/generator.c --- rsync-3.0.2-orig/generator.c 2008-03-28 10:30:11.000000000 -0700 +++ rsync-3.0.2/generator.c 2008-05-07 15:35:08.317364774 -0700 @@ -1508,6 +1508,7 @@ if (preserve_links && S_ISLNK(file->mode)) { #ifdef SUPPORT_LINKS + int iflags = 0; const char *sl = F_SYMLINK(file); if (safe_symlinks && unsafe_symlink(sl, fname)) { if (verbose) { @@ -1528,7 +1529,15 @@ else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0 && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') { /* The link is pointing to the right place. */ - set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); + if (inplace) { + if (verbose > 2) + rprintf(FINFO, "possibly tweaking attributes of %s\n", fname); + set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); + } else if (!unchanged_attrs(fname, file, &sx)) { + if (verbose > 2) + rprintf(FINFO, "recreating %s due to changed attributes\n", fname); + goto recreate_symlink; + } if (itemizing) itemize(fname, file, ndx, 0, &sx, 0, 0, NULL); #if defined SUPPORT_HARD_LINKS && defined CAN_HARDLINK_SYMLINK @@ -1538,7 +1547,9 @@ if (remove_source_files == 1) goto return_with_success; goto cleanup; - } + } else + iflags = ITEM_REPORT_CHANGE; + recreate_symlink: /* Not the right symlink (or not a symlink), so * delete it. */ if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_SYMLINK) != 0) @@ -1572,18 +1583,20 @@ set_file_attrs(fname, file, NULL, NULL, 0); if (itemizing) { itemize(fname, file, ndx, statret, &sx, - ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL); + ITEM_LOCAL_CHANGE|iflags, 0, NULL); } - if (code != FNONE && verbose) + if ((iflags & ITEM_REPORT_CHANGE) && code != FNONE && verbose) rprintf(code, "%s -> %s\n", fname, sl); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1); #endif - /* This does not check remove_source_files == 1 - * because this is one of the items that the old - * --remove-sent-files option would remove. */ - if (remove_source_files) + /* When the symlink value changed, we do not check + * remove_source_files == 1 because this is one of the + * items that the old --remove-sent-files option would + * remove. */ + if ((iflags & ITEM_REPORT_CHANGE) ? remove_source_files + : remove_source_files == 1) goto return_with_success; } #endif @@ -1592,6 +1605,7 @@ if ((am_root && preserve_devices && IS_DEVICE(file->mode)) || (preserve_specials && IS_SPECIAL(file->mode))) { + int iflags = 0; uint32 *devp = F_RDEV_P(file); dev_t rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); if (statret == 0) { @@ -1609,7 +1623,15 @@ && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT) && sx.st.st_rdev == rdev) { /* The device or special file is identical. */ - set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); + if (inplace) { + if (verbose > 2) + rprintf(FINFO, "possibly tweaking attributes of %s\n", fname); + set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); + } else if (!unchanged_attrs(fname, file, &sx)) { + if (verbose > 2) + rprintf(FINFO, "recreating %s due to changed attributes\n", fname); + goto recreate_D; + } if (itemizing) itemize(fname, file, ndx, 0, &sx, 0, 0, NULL); #ifdef SUPPORT_HARD_LINKS @@ -1619,7 +1641,9 @@ if (remove_source_files == 1) goto return_with_success; goto cleanup; - } + } else + iflags = ITEM_REPORT_CHANGE; + recreate_D: if (delete_item(fname, sx.st.st_mode, del_opts | del_for_flag) != 0) goto cleanup; } else if (basis_dir[0] != NULL) { @@ -1656,9 +1680,9 @@ set_file_attrs(fname, file, NULL, NULL, 0); if (itemizing) { itemize(fname, file, ndx, statret, &sx, - ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL); + ITEM_LOCAL_CHANGE|iflags, 0, NULL); } - if (code != FNONE && verbose) + if ((iflags & ITEM_REPORT_CHANGE) && code != FNONE && verbose) rprintf(code, "%s\n", fname); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) @@ -1776,13 +1800,31 @@ else if (fnamecmp_type == FNAMECMP_FUZZY) ; else if (unchanged_file(fnamecmp, file, &sx.st)) { + /* fnamecmp == fname, fnamecmp_type == FNAMECMP_FNAME */ + int iflags = 0; + if (partialptr) { do_unlink(partialptr); handle_partial_dir(partialptr, PDIR_DELETE); } - set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); + if (inplace) { + /* Currently, we call set_file_attrs on all tweakable + * files, though ideally it would have no effect when + * unchanged_attrs returns true. */ + if (verbose > 2) + rprintf(FINFO, "possibly tweaking attributes of %s\n", fname); + set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); + } else if (!unchanged_attrs(fname, file, &sx)) { + /* Need to recreate the file. + * copy_altdest_file sets its attributes, etc. */ + if (verbose > 2) + rprintf(FINFO, "recreating %s due to changed attributes\n", fname); + if (!dry_run && copy_altdest_file(fnamecmp, fname, file)) + goto cleanup; + iflags |= ITEM_LOCAL_CHANGE; + } if (itemizing) - itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL); + itemize(fnamecmp, file, ndx, statret, &sx, iflags, 0, NULL); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);