--- /dev/null
+This patch adds the options --detect-renamed-lax and --detect-moved.
+These modify the --detect-renamed algorithm to adopt a matching file
+without verifying that the content is as expected. The former blindly
+accepts a file that matches in size and modified time. The latter
+requires that the filename also match (ignoring any renamed files).
+
+This patch is EXPERIMENTAL, though it did work correctly in my light
+testing.
+
+To use this patch, run these commands for a successful build:
+
+ patch -p1 <patches/detect-renamed.diff
+ patch -p1 <patches/detect-renamed-lax.diff
+ ./configure (optional if already run)
+ make
+
+FIXME: If a run with --detect-renamed-lax stages a different-basename
+destination file and then gets interrupted, a subsequent run that
+switches to --detect-moved blindly accepts the staged file.
+
+-- Matt McCutchen <hashproduct+rsync@gmail.com>
+
+--- old/generator.c
++++ new/generator.c
+@@ -188,7 +188,9 @@ static int fattr_find(struct file_struct
+ continue;
+ }
+ }
+- ok_match = mid;
++ /* --detect-moved doesn't allow non-basename matches */
++ if (detect_renamed != 3)
++ ok_match = mid;
+ diff = u_strcmp(fmid->basename, f->basename);
+ if (diff == 0) {
+ good_match = mid;
+@@ -1826,6 +1828,21 @@ static void recv_generator(char *fname,
+ fnamecmp = partialptr;
+ fnamecmp_type = FNAMECMP_PARTIAL_DIR;
+ statret = 0;
++ if (detect_renamed > 1 && unchanged_file(fnamecmp, file, &sx.st)) {
++ /* Adopt the partial file. */
++ finish_transfer(fname, fnamecmp, NULL, NULL, file, 1, 1);
++ handle_partial_dir(partialptr, PDIR_DELETE);
++ if (itemizing)
++ itemize(fnamecmp, file, ndx, -1, &sx,
++ ITEM_LOCAL_CHANGE, fnamecmp_type, NULL);
++#ifdef SUPPORT_HARD_LINKS
++ if (preserve_hard_links && F_IS_HLINKED(file))
++ finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
++#endif
++ if (remove_source_files == 1)
++ goto return_with_success;
++ goto cleanup;
++ }
+ }
+
+ if (!do_xfers)
+--- old/options.c
++++ new/options.c
+@@ -385,6 +385,8 @@ void usage(enum logcode F)
+ rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
+ rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n");
+ rprintf(F," --detect-renamed try to find renamed files to speed up the transfer\n");
++ rprintf(F," --detect-renamed-lax ... and assume identical to source files (risky!)\n");
++ rprintf(F," --detect-moved ... only if basenames match (less risky)\n");
+ rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
+ rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n");
+ rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n");
+@@ -563,7 +565,9 @@ static struct poptOption long_options[]
+ {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
+ {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
+ {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
+- {"detect-renamed", 0, POPT_ARG_NONE, &detect_renamed, 0, 0, 0 },
++ {"detect-renamed", 0, POPT_ARG_VAL, &detect_renamed, 1, 0, 0 },
++ {"detect-renamed-lax",0, POPT_ARG_VAL, &detect_renamed, 2, 0, 0 },
++ {"detect-moved", 0, POPT_ARG_VAL, &detect_renamed, 3, 0, 0 },
+ {"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 0, 0 },
+ {"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 },
+ {"no-compress", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 },
+@@ -1895,8 +1899,14 @@ void server_options(char **args, int *ar
+ }
+ }
+ /* Both sides need to know in case this disables incremental recursion. */
+- if (detect_renamed)
+- args[ac++] = "--detect-renamed";
++ if (detect_renamed) {
++ if (detect_renamed == 1)
++ args[ac++] = "--detect-renamed";
++ else if (detect_renamed == 2)
++ args[ac++] = "--detect-renamed-lax";
++ else
++ args[ac++] = "--detect-moved";
++ }
+
+ if (modify_window_set) {
+ if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
+--- old/rsync.yo
++++ new/rsync.yo
+@@ -385,6 +385,8 @@ to the detailed description below for a
+ -T, --temp-dir=DIR create temporary files in directory DIR
+ -y, --fuzzy find similar file for basis if no dest file
+ --detect-renamed try to find renamed files to speed the xfer
++ --detect-renamed-lax ...& assume identical to src files (risky!)
++ --detect-moved ... only if basenames match (less risky)
+ --compare-dest=DIR also compare received files relative to DIR
+ --copy-dest=DIR ... and include copies of unchanged files
+ --link-dest=DIR hardlink to files in DIR when unchanged
+@@ -1446,6 +1448,17 @@ the bf(--partial-dir) option, that direc
+ potential alternate-basis files will be removed as the transfer progresses.
+ This option conflicts with bf(--inplace) and bf(--append).
+
++dit(bf(--detect-renamed-lax)) This version of bf(--detect-renamed)
++makes rsync hard-link em(dest/D) to em(dest/S) without verifying that
++em(src/S) and em(dest/S) have the same data. This poses a significant risk
++of corrupting the destination by representing a new source file by an
++unrelated destination file that coincidentally passes the quick check with the
++source file. Use this option only if you accept the risk and disk I/O is a
++bottleneck.
++
++dit(bf(--detect-moved)) A less risky variant of bf(--detect-renamed-lax) that
++only uses a destination file that has the same basename as the new source file.
++
+ dit(bf(--compare-dest=DIR)) This option instructs rsync to use em(DIR) on
+ the destination machine as an additional hierarchy to compare destination
+ files against doing transfers (if the files are missing in the destination