From 4afbc05092aaa1a9496258f9e1a3575ba39978c1 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 1 Mar 2005 19:48:25 +0000 Subject: [PATCH] A better implementation of --copy-dest than what was in CVS earlier. Still need to consider security, timeouts, and error-checking completeness. --- copy-dest.diff | 181 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 copy-dest.diff diff --git a/copy-dest.diff b/copy-dest.diff new file mode 100644 index 0000000..5f2dc13 --- /dev/null +++ b/copy-dest.diff @@ -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 -- 2.34.1