This adds the option --copy-dest, which works just like --link-dest
except that identical files are copied into the destination instead
of hard-linked.

--- orig/generator.c	2005-03-09 23:46:28
+++ generator.c	2005-03-11 11:24:17
@@ -66,6 +66,7 @@ extern int always_checksum;
 extern char *partial_dir;
 extern char *basis_dir[];
 extern int compare_dest;
+extern int copy_dest;
 extern int link_dest;
 extern int whole_file;
 extern int local_server;
@@ -873,6 +874,8 @@ static void recv_generator(char *fname, 
 					continue;
 				best_match = i;
 				match_level = 2;
+				if (copy_dest)
+					break;
 				/* FALL THROUGH */
 			case 2:
 				if (!unchanged_attrs(file, &st))
@@ -910,7 +913,20 @@ static void recv_generator(char *fname, 
 				match_level = 2;
 			}
 #endif
-			if (compare_dest || (match_level && match_level < 3)) {
+			if (match_level == 2) {
+				/* Copy the file locally. */
+				if (copy_file(fnamecmpbuf, fname, file->mode) < 0) {
+					if (verbose) {
+						rsyserr(FINFO, errno,
+							"copy_file %s => %s",
+							full_fname(fnamecmpbuf),
+							safe_fname(fname));
+					}
+					match_level = 0;
+					statret = -1;
+				} else
+					set_perms(fname, file, NULL, 0);
+			} else if (compare_dest || match_level == 1) {
 				fnamecmp = fnamecmpbuf;
 				fnamecmp_type = i;
 			}
@@ -973,11 +989,9 @@ static void recv_generator(char *fname, 
 			return;
 		}
 		/* Only --compare-dest gets here. */
-		if (unchanged_attrs(file, &st)) {
-			itemize(file, ndx, real_ret, &real_st,
-				ITEM_NO_DEST_AND_NO_UPDATE, 0, NULL);
-			return;
-		}
+		itemize(file, ndx, real_ret, &real_st,
+			ITEM_NO_DEST_AND_NO_UPDATE, 0, NULL);
+		return;
 	}
 
 prepare_to_open:
--- orig/options.c	2005-03-09 18:53:53
+++ options.c	2005-03-02 10:05:21
@@ -143,6 +143,7 @@ char *backup_dir = NULL;
 char backup_dir_buf[MAXPATHLEN];
 int rsync_port = 0;
 int compare_dest = 0;
+int copy_dest = 0;
 int link_dest = 0;
 int basis_dir_cnt = 0;
 char *dest_option = NULL;
@@ -317,6 +318,7 @@ 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,"     --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");
   rprintf(F," -z, --compress              compress file data during the transfer\n");
   rprintf(F," -C, --cvs-exclude           auto-ignore files the same way CVS does\n");
@@ -355,7 +357,7 @@ void usage(enum logcode F)
 }
 
 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
-      OPT_FILTER, OPT_COMPARE_DEST, OPT_LINK_DEST,
+      OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
       OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
       OPT_REFUSED_BASE = 9000};
@@ -424,6 +426,7 @@ static struct poptOption long_options[] 
   {"timeout",          0,  POPT_ARG_INT,    &io_timeout, OPT_TIMEOUT, 0, 0 },
   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
   {"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 },
   {"fuzzy",           'y', POPT_ARG_NONE,   &fuzzy_basis, 0, 0, 0 },
   /* TODO: Should this take an optional int giving the compression level? */
@@ -838,6 +841,11 @@ int parse_arguments(int *argc, const cha
 			return 0;
 #endif
 
+		case OPT_COPY_DEST:
+			copy_dest = 1;
+			dest_option = "--copy-dest";
+			goto set_dest_dir;
+
 		case OPT_COMPARE_DEST:
 			compare_dest = 1;
 			dest_option = "--compare-dest";
@@ -928,9 +936,9 @@ int parse_arguments(int *argc, const cha
 		return 0;
 	}
 
-	if (compare_dest + link_dest > 1) {
+	if (compare_dest + copy_dest + link_dest > 1) {
 		snprintf(err_buf, sizeof err_buf,
-			"You may not mix --compare-dest and --link-dest.\n");
+			"You may not mix --compare-dest, --copy-dest, and --link-dest.\n");
 		return 0;
 	}
 
--- orig/rsync.yo	2005-03-05 18:58:26
+++ rsync.yo	2005-03-03 02:19:19
@@ -353,6 +353,7 @@ 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
      --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
  -z, --compress              compress file data during the transfer
  -C, --cvs-exclude           auto-ignore files in the same way CVS does
@@ -954,13 +955,30 @@ have changed from an earlier backup.
 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
 for an exact match.
+If a match is found that differs only in attributes, a local copy is made
+and the attributes updated.
 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.
 
 If em(DIR) is a relative path, it is relative to the destination directory.
-See also bf(--link-dest).
+See also bf(--copy-dest) and bf(--link-dest).
 
-dit(bf(--link-dest=DIR)) This option behaves like bf(--compare-dest), but
+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.  This is
+useful for doing transfers to a new destination while leaving existing
+files intact, and then doing a flash-cutover when all files have been
+successfully transferred.
+
+Multiple bf(--copy-dest) directories may be provided, which will cause
+rsync to search the list in the order specified for an unchanged file.
+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.
+
+If em(DIR) is a relative path, it is relative to the destination directory.
+See also bf(--compare-dest) and bf(--link-dest).
+
+dit(bf(--link-dest=DIR)) This option behaves like bf(--copy-dest), but
 unchanged files are hard linked from em(DIR) to the destination directory.
 The files must be identical in all preserved attributes (e.g. permissions,
 possibly ownership) in order for the files to be linked together.
@@ -971,11 +989,13 @@ quote(tt(  rsync -av --link-dest=$PWD/pr
 Beginning in version 2.6.4, multiple bf(--link-dest) directories may be
 provided, which will cause rsync to search the list in the order specified
 for an exact match.
+If a match is found that differs only in attributes, a local copy is made
+and the attributes updated.
 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.
 
 If em(DIR) is a relative path, it is relative to the destination directory.
-See also bf(--compare-dest).
+See also bf(--compare-dest) and bf(--copy-dest).
 
 Note that rsync versions prior to 2.6.1 had a bug that could prevent
 bf(--link-dest) from working properly for a non-root user when bf(-o) was specified
--- orig/testsuite/compare-dest.test	2005-02-26 19:49:59
+++ testsuite/compare-dest.test	2005-03-01 15:57:27
@@ -31,9 +31,9 @@ $RSYNC -av --exclude=/text --exclude=etc
 checkit "$RSYNC -avv --no-whole-file \
     --compare-dest=\"$alt1dir\" --compare-dest=\"$alt2dir\" \
     \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
-#checkit "$RSYNC -avv --no-whole-file \
-#    --copy-dest=\"$alt1dir\" --copy-dest=\"$alt2dir\" \
-#    \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
+checkit "$RSYNC -avv --no-whole-file \
+    --copy-dest=\"$alt1dir\" --copy-dest=\"$alt2dir\" \
+    \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
 
 # The script would have aborted on error, so getting here means we've won.
 exit 0
