A better implementation of --copy-dest than what was in CVS
authorWayne Davison <wayned@samba.org>
Tue, 1 Mar 2005 19:48:25 +0000 (19:48 +0000)
committerWayne Davison <wayned@samba.org>
Tue, 1 Mar 2005 19:48:25 +0000 (19:48 +0000)
earlier.  Still need to consider security, timeouts, and
error-checking completeness.

copy-dest.diff [new file with mode: 0644]

diff --git a/copy-dest.diff b/copy-dest.diff
new file mode 100644 (file)
index 0000000..5f2dc13
--- /dev/null
@@ -0,0 +1,181 @@
+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-01 19:42:49
++++ generator.c        2005-03-01 19:43:39
+@@ -65,6 +65,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;
+@@ -831,6 +832,8 @@ static void recv_generator(char *fname, 
+                               case 1:
+                                       if (!unchanged_file(fnamecmpbuf, file, &st))
+                                               continue;
++                                      if (copy_dest)
++                                              break;
+                                       fallback_match = i;
+                                       match_level = 2;
+                                       /* FALL THROUGH */
+@@ -848,8 +851,19 @@ static void recv_generator(char *fname, 
+                               pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
+                                        basis_dir[i], fname);
+                       }
++                      if ((copy_dest && match_level == 3 && !dry_run)
++#ifdef HAVE_LINK
++                          || (link_dest && match_level == 2 && !dry_run)
++#endif
++                          ) {
++                              /* Copy the file locally. */
++                              if (copy_file(fnamecmpbuf, fname, file->mode) < 0) {
++                                      fnamecmp = fnamecmpbuf;
++                                      fnamecmp_type = i;
++                              } else
++                                      set_perms(fname, file, NULL, 0);
+ #ifdef HAVE_LINK
+-                      if (link_dest && match_level == 3 && !dry_run) {
++                      } else if (link_dest && match_level == 3 && !dry_run) {
+                               if (do_link(fnamecmpbuf, fname) < 0) {
+                                       if (verbose) {
+                                               rsyserr(FINFO, errno,
+@@ -860,9 +874,8 @@ static void recv_generator(char *fname, 
+                                       fnamecmp = fnamecmpbuf;
+                                       fnamecmp_type = i;
+                               }
+-                      } else
+ #endif
+-                      {
++                      } else {
+                               fnamecmp = fnamecmpbuf;
+                               fnamecmp_type = i;
+                       }
+--- orig/options.c     2005-03-01 05:49:24
++++ options.c  2005-02-23 02:05:34
+@@ -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;
+@@ -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-01 19:42:49
++++ rsync.yo   2005-02-23 02:05:34
+@@ -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
+@@ -554,8 +555,8 @@ bound.
+ The option implies bf(--partial) (since an interrupted transfer does not delete
+ the file), but conflicts with bf(--partial-dir) and bf(--delay-updates).
+-Prior to rsync 2.6.4 bf(--inplace) was also incompatible with bf(--compare-dest)
+-and bf(--link-dest).
++Prior to rsync 2.6.4 bf(--inplace) was also incompatible with bf(--compare-dest),
++bf(--copy-dest), and bf(--link-dest).
+ WARNING: The file's data will be in an inconsistent state during the
+ transfer (and possibly afterward if the transfer gets interrupted), so you
+@@ -949,9 +950,19 @@ finds an existing file.  That first disc
+ and also determines if the transfer needs to happen.
+ 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 the data in the em(DIR) for an efficient 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.
++
++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.
+@@ -965,7 +976,7 @@ the list in the order specified), and if
+ 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:51:27
++++ 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