| 1 | This patch adds the options --detect-renamed-lax and --detect-moved. |
| 2 | These modify the --detect-renamed algorithm to adopt a matching file |
| 3 | without verifying that the content is as expected. The former blindly |
| 4 | accepts a file that matches in size and modified time. The latter |
| 5 | requires that the filename also match (ignoring any renamed files). |
| 6 | |
| 7 | This patch is EXPERIMENTAL, though it did work correctly in my light |
| 8 | testing. |
| 9 | |
| 10 | To use this patch, run these commands for a successful build: |
| 11 | |
| 12 | patch -p1 <patches/detect-renamed.diff |
| 13 | patch -p1 <patches/detect-renamed-lax.diff |
| 14 | ./configure (optional if already run) |
| 15 | make |
| 16 | |
| 17 | FIXME: If a run with --detect-renamed-lax stages a different-basename |
| 18 | destination file and then gets interrupted, a subsequent run that |
| 19 | switches to --detect-moved blindly accepts the staged file. |
| 20 | |
| 21 | -- Matt McCutchen <hashproduct+rsync@gmail.com> |
| 22 | |
| 23 | --- old/generator.c |
| 24 | +++ new/generator.c |
| 25 | @@ -188,7 +188,9 @@ static int fattr_find(struct file_struct |
| 26 | continue; |
| 27 | } |
| 28 | } |
| 29 | - ok_match = mid; |
| 30 | + /* --detect-moved doesn't allow non-basename matches */ |
| 31 | + if (detect_renamed != 3) |
| 32 | + ok_match = mid; |
| 33 | diff = u_strcmp(fmid->basename, f->basename); |
| 34 | if (diff == 0) { |
| 35 | good_match = mid; |
| 36 | @@ -1831,6 +1833,21 @@ static void recv_generator(char *fname, |
| 37 | fnamecmp = partialptr; |
| 38 | fnamecmp_type = FNAMECMP_PARTIAL_DIR; |
| 39 | statret = 0; |
| 40 | + if (detect_renamed > 1 && unchanged_file(fnamecmp, file, &sx.st)) { |
| 41 | + /* Adopt the partial file. */ |
| 42 | + finish_transfer(fname, fnamecmp, NULL, NULL, file, 1, 1); |
| 43 | + handle_partial_dir(partialptr, PDIR_DELETE); |
| 44 | + if (itemizing) |
| 45 | + itemize(fnamecmp, file, ndx, -1, &sx, |
| 46 | + ITEM_LOCAL_CHANGE, fnamecmp_type, NULL); |
| 47 | +#ifdef SUPPORT_HARD_LINKS |
| 48 | + if (preserve_hard_links && F_IS_HLINKED(file)) |
| 49 | + finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1); |
| 50 | +#endif |
| 51 | + if (remove_source_files == 1) |
| 52 | + goto return_with_success; |
| 53 | + goto cleanup; |
| 54 | + } |
| 55 | } |
| 56 | |
| 57 | if (!do_xfers) |
| 58 | --- old/options.c |
| 59 | +++ new/options.c |
| 60 | @@ -385,6 +385,8 @@ void usage(enum logcode F) |
| 61 | rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n"); |
| 62 | rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n"); |
| 63 | rprintf(F," --detect-renamed try to find renamed files to speed up the transfer\n"); |
| 64 | + rprintf(F," --detect-renamed-lax ... and assume identical to source files (risky!)\n"); |
| 65 | + rprintf(F," --detect-moved ... only if basenames match (less risky)\n"); |
| 66 | rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n"); |
| 67 | rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n"); |
| 68 | rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n"); |
| 69 | @@ -563,7 +565,9 @@ static struct poptOption long_options[] |
| 70 | {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 }, |
| 71 | {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 }, |
| 72 | {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 }, |
| 73 | - {"detect-renamed", 0, POPT_ARG_NONE, &detect_renamed, 0, 0, 0 }, |
| 74 | + {"detect-renamed", 0, POPT_ARG_VAL, &detect_renamed, 1, 0, 0 }, |
| 75 | + {"detect-renamed-lax",0, POPT_ARG_VAL, &detect_renamed, 2, 0, 0 }, |
| 76 | + {"detect-moved", 0, POPT_ARG_VAL, &detect_renamed, 3, 0, 0 }, |
| 77 | {"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 0, 0 }, |
| 78 | {"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 }, |
| 79 | {"no-compress", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 }, |
| 80 | @@ -1889,8 +1893,14 @@ void server_options(char **args, int *ar |
| 81 | args[ac++] = "--super"; |
| 82 | if (size_only) |
| 83 | args[ac++] = "--size-only"; |
| 84 | - if (detect_renamed) |
| 85 | - args[ac++] = "--detect-renamed"; |
| 86 | + if (detect_renamed) { |
| 87 | + if (detect_renamed == 1) |
| 88 | + args[ac++] = "--detect-renamed"; |
| 89 | + else if (detect_renamed == 2) |
| 90 | + args[ac++] = "--detect-renamed-lax"; |
| 91 | + else |
| 92 | + args[ac++] = "--detect-moved"; |
| 93 | + } |
| 94 | } else { |
| 95 | if (skip_compress) { |
| 96 | if (asprintf(&arg, "--skip-compress=%s", skip_compress) < 0) |
| 97 | --- old/rsync.yo |
| 98 | +++ new/rsync.yo |
| 99 | @@ -385,6 +385,8 @@ to the detailed description below for a |
| 100 | -T, --temp-dir=DIR create temporary files in directory DIR |
| 101 | -y, --fuzzy find similar file for basis if no dest file |
| 102 | --detect-renamed try to find renamed files to speed the xfer |
| 103 | + --detect-renamed-lax ...& assume identical to src files (risky!) |
| 104 | + --detect-moved ... only if basenames match (less risky) |
| 105 | --compare-dest=DIR also compare received files relative to DIR |
| 106 | --copy-dest=DIR ... and include copies of unchanged files |
| 107 | --link-dest=DIR hardlink to files in DIR when unchanged |
| 108 | @@ -1446,6 +1448,17 @@ the bf(--partial-dir) option, that direc |
| 109 | potential alternate-basis files will be removed as the transfer progresses. |
| 110 | This option conflicts with bf(--inplace) and bf(--append). |
| 111 | |
| 112 | +dit(bf(--detect-renamed-lax)) This version of bf(--detect-renamed) |
| 113 | +makes rsync hard-link em(dest/D) to em(dest/S) without verifying that |
| 114 | +em(src/S) and em(dest/S) have the same data. This poses a significant risk |
| 115 | +of corrupting the destination by representing a new source file by an |
| 116 | +unrelated destination file that coincidentally passes the quick check with the |
| 117 | +source file. Use this option only if you accept the risk and disk I/O is a |
| 118 | +bottleneck. |
| 119 | + |
| 120 | +dit(bf(--detect-moved)) A less risky variant of bf(--detect-renamed-lax) that |
| 121 | +only uses a destination file that has the same basename as the new source file. |
| 122 | + |
| 123 | dit(bf(--compare-dest=DIR)) This option instructs rsync to use em(DIR) on |
| 124 | the destination machine as an additional hierarchy to compare destination |
| 125 | files against doing transfers (if the files are missing in the destination |