From: Wayne Davison Date: Fri, 18 Jan 2013 19:54:01 +0000 (-0800) Subject: Improve handling of existing files for alt-dest opts. X-Git-Tag: v3.1.0pre1~42 X-Git-Url: http://git.samba.org/samba.git/?p=rsync.git;a=commitdiff_plain;h=e1ded589839627986937817bd102bdab380593a9 Improve handling of existing files for alt-dest opts. Fixes bug #5644. --- diff --git a/generator.c b/generator.c index 973e03bd..f95e57f6 100644 --- a/generator.c +++ b/generator.c @@ -844,10 +844,14 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru /* This is only called for regular files. We return -2 if we've finished * handling the file, -1 if no dest-linking occurred, or a non-negative - * value if we found an alternate basis file. */ + * value if we found an alternate basis file. If we're called with the + * find_exact_for_existing flag, the destination file already exists, so + * we only try to find an exact alt-dest match. In this case, the returns + * can be -2 & -1 (both as above) as well as -3, which means that we + * removed the dest file but failed to create a hard link for it. */ static int try_dests_reg(struct file_struct *file, char *fname, int ndx, - char *cmpbuf, stat_x *sxp, int itemizing, - enum logcode code) + char *cmpbuf, stat_x *sxp, int find_exact_for_existing, + int itemizing, enum logcode code) { int best_match = -1; int match_level = 0; @@ -889,10 +893,17 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx, } if (match_level == 3 && !copy_dest) { + if (find_exact_for_existing) { + if (do_unlink(fname) < 0 && errno != ENOENT) + return -1; + } #ifdef SUPPORT_HARD_LINKS if (link_dest) { - if (!hard_link_one(file, fname, cmpbuf, 1)) + if (!hard_link_one(file, fname, cmpbuf, 1)) { + if (find_exact_for_existing) + return -3; goto try_a_copy; + } if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j); if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) { @@ -902,13 +913,18 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx, } } else #endif - if (itemizing) - itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL); + { + if (itemizing) + itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL); + } if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) rprintf(FCLIENT, "%s is uptodate\n", fname); return -2; } + if (find_exact_for_existing) + return -1; + if (match_level >= 2) { #ifdef SUPPORT_HARD_LINKS try_a_copy: /* Copy the file locally. */ @@ -1640,9 +1656,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, stat_errno = ENOENT; } - if (statret != 0 && basis_dir[0] != NULL) { + if (basis_dir[0] != NULL && (statret != 0 || !copy_dest)) { int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx, - itemizing, code); + statret == 0, itemizing, code); if (j == -2) { if (remove_source_files == 1) goto return_with_success; @@ -1652,6 +1668,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, fnamecmp = fnamecmpbuf; fnamecmp_type = j; statret = 0; + } else if (j == -3) { + statret = -1; + stat_errno = ENOENT; } } diff --git a/rsync.yo b/rsync.yo index a0620899..655301f6 100644 --- a/rsync.yo +++ b/rsync.yo @@ -1773,6 +1773,8 @@ directory). If a file is found in em(DIR) that is identical to the sender's file, the file will NOT be transferred to the destination directory. This is useful for creating a sparse backup of just files that have changed from an earlier backup. +This option is typically used to copy into an empty (or newly created) +directory. Beginning in version 2.6.4, multiple bf(--compare-dest) directories may be provided, which will cause rsync to search the list in the order specified @@ -1785,6 +1787,10 @@ selected to try to speed up the transfer. If em(DIR) is a relative path, it is relative to the destination directory. See also bf(--copy-dest) and bf(--link-dest). +NOTE: beginning with version 3.1.0, rsync will remove a file from a non-empty +destination hierarchy if an exact match is found in one of the compare-dest +hierarchies (making the end result more closely match a fresh copy). + dit(bf(--copy-dest=DIR)) This option behaves like bf(--compare-dest), but rsync will also copy unchanged files found in em(DIR) to the destination directory using a local copy. @@ -1822,10 +1828,11 @@ If a match is not found, a basis file from one of the em(DIR)s will be selected to try to speed up the transfer. This option works best when copying into an empty destination hierarchy, as -rsync treats existing files as definitive (so it never looks in the link-dest -dirs when a destination file already exists), and as malleable (so it might -change the attributes of a destination file, which affects all the hard-linked -versions). +existing files may get their attributes tweaked, and that can affect alternate +destination files via hard-links. Also, itemizing of changes can get a bit +muddled. Note that prior to version 3.1.0, an alternate-directory exact match +would never be found (nor linked into the destination) when a destination file +already exists. Note that if you combine this option with bf(--ignore-times), rsync will not link any files together because it only links identical files together as a