Annotation of embedaddon/rsync/patches/clone-dest.diff, revision 1.1
1.1 ! misho 1: This patch adds the --clone-dest option that works link --link-dest
! 2: but without requiring the metadata of the files to match in order
! 3: to be able to share the file's data.
! 4:
! 5: NOTE: this patch is mostly untested because I don't currently have
! 6: a btrfs mount to test it out on. I still need to make sure that a
! 7: cloned file gets its destination attributes set correctly after the
! 8: clone, for instance.
! 9:
! 10: To use this patch, run these commands for a successful build:
! 11:
! 12: patch -p1 <patches/clone-dest.diff
! 13: ./configure (optional if already run)
! 14: make
! 15:
! 16: based-on: e94bad1c156fc3910f24e2b3b71a81b0b0bdeb70
! 17: diff --git a/Makefile.in b/Makefile.in
! 18: --- a/Makefile.in
! 19: +++ b/Makefile.in
! 20: @@ -50,7 +50,7 @@ popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
! 21: popt/popthelp.o popt/poptparse.o
! 22: OBJS=$(OBJS1) $(OBJS2) $(OBJS3) @SIMD@ $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
! 23:
! 24: -TLS_OBJ = tls.o syscall.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
! 25: +TLS_OBJ = tls.o syscall.o util.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o lib/wildmatch.o @BUILD_POPT@
! 26:
! 27: # Programs we must have to run the test cases
! 28: CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
! 29: @@ -155,7 +155,7 @@ getgroups$(EXEEXT): getgroups.o
! 30: getfsdev$(EXEEXT): getfsdev.o
! 31: $(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
! 32:
! 33: -TRIMSLASH_OBJ = trimslash.o syscall.o t_stub.o lib/compat.o lib/snprintf.o
! 34: +TRIMSLASH_OBJ = trimslash.o syscall.o util.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
! 35: trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
! 36: $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
! 37:
! 38: diff --git a/generator.c b/generator.c
! 39: --- a/generator.c
! 40: +++ b/generator.c
! 41: @@ -913,7 +913,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
! 42: best_match = j;
! 43: match_level = 2;
! 44: }
! 45: - if (unchanged_attrs(cmpbuf, file, sxp)) {
! 46: + if (alt_dest_type == CLONE_DEST || unchanged_attrs(cmpbuf, file, sxp)) {
! 47: best_match = j;
! 48: match_level = 3;
! 49: break;
! 50: @@ -953,7 +953,12 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
! 51: }
! 52: } else
! 53: #endif
! 54: - {
! 55: + if (alt_dest_type == CLONE_DEST) {
! 56: + if (do_clone(cmpbuf, fname, file->mode) < 0) {
! 57: + rsyserr(FERROR_XFER, errno, "failed to clone %s to %s", cmpbuf, fname);
! 58: + exit_cleanup(RERR_UNSUPPORTED);
! 59: + }
! 60: + } else {
! 61: if (itemizing)
! 62: itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL);
! 63: }
! 64: @@ -1109,7 +1114,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
! 65:
! 66: if (match_level == 3) {
! 67: #ifdef SUPPORT_HARD_LINKS
! 68: - if (alt_dest_type == LINK_DEST
! 69: + if ((alt_dest_type == LINK_DEST || alt_dest_type == CLONE_DEST)
! 70: #ifndef CAN_HARDLINK_SYMLINK
! 71: && !S_ISLNK(file->mode)
! 72: #endif
! 73: diff --git a/options.c b/options.c
! 74: --- a/options.c
! 75: +++ b/options.c
! 76: @@ -573,7 +573,7 @@ enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
! 77: OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
! 78: OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
! 79: OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_BLOCK_SIZE,
! 80: - OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR,
! 81: + OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR, OPT_CLONE_DEST,
! 82: OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS,
! 83: OPT_STOP_AFTER, OPT_STOP_AT,
! 84: OPT_REFUSED_BASE = 9000};
! 85: @@ -733,6 +733,7 @@ static struct poptOption long_options[] = {
! 86: {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
! 87: {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
! 88: {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
! 89: + {"clone-dest", 0, POPT_ARG_STRING, 0, OPT_CLONE_DEST, 0, 0 },
! 90: {"fuzzy", 'y', POPT_ARG_NONE, 0, 'y', 0, 0 },
! 91: {"no-fuzzy", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
! 92: {"no-y", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
! 93: @@ -986,6 +987,9 @@ static void set_refuse_options(void)
! 94: #ifndef SUPPORT_HARD_LINKS
! 95: parse_one_refuse_match(0, "link-dest", list_end);
! 96: #endif
! 97: +#ifndef FICLONE
! 98: + parse_one_refuse_match(0, "clone-dest", list_end);
! 99: +#endif
! 100: #ifndef HAVE_MKTIME
! 101: parse_one_refuse_match(0, "stop-at", list_end);
! 102: #endif
! 103: @@ -1315,6 +1319,8 @@ char *alt_dest_opt(int type)
! 104: return "--copy-dest";
! 105: case LINK_DEST:
! 106: return "--link-dest";
! 107: + case CLONE_DEST:
! 108: + return "--clone-dest";
! 109: default:
! 110: NOISY_DEATH("Unknown alt_dest_opt type");
! 111: }
! 112: @@ -1685,6 +1691,10 @@ int parse_arguments(int *argc_p, const char ***argv_p)
! 113: want_dest_type = LINK_DEST;
! 114: goto set_dest_dir;
! 115:
! 116: + case OPT_CLONE_DEST:
! 117: + want_dest_type = CLONE_DEST;
! 118: + goto set_dest_dir;
! 119: +
! 120: case OPT_COPY_DEST:
! 121: want_dest_type = COPY_DEST;
! 122: goto set_dest_dir;
! 123: diff --git a/rsync.1.md b/rsync.1.md
! 124: --- a/rsync.1.md
! 125: +++ b/rsync.1.md
! 126: @@ -424,6 +424,7 @@ detailed description below for a complete description.
! 127: --compare-dest=DIR also compare destination files relative to DIR
! 128: --copy-dest=DIR ... and include copies of unchanged files
! 129: --link-dest=DIR hardlink to files in DIR when unchanged
! 130: +--clone-dest=DIR clone (reflink) files from DIR when unchanged
! 131: --compress, -z compress file data during the transfer
! 132: --compress-choice=STR choose the compression algorithm (aka --zc)
! 133: --compress-level=NUM explicitly set compression level (aka --zl)
! 134: @@ -2331,6 +2332,17 @@ your home directory (remove the '=' for that).
! 135: specified (or implied by `-a`). You can work-around this bug by avoiding
! 136: the `-o` option when sending to an old rsync.
! 137:
! 138: +0. `--clone-dest=DIR`
! 139: +
! 140: + This option behaves like `--link-dest`, but unchanged files are reflinked
! 141: + from _DIR_ to the destination directory. The files do not need to match
! 142: + in attributes, as the data is cloned separately from the attributes.
! 143: +
! 144: + If _DIR_ is a relative path, it is relative to the destination directory.
! 145: + See also `--compare-dest` and `--copy-dest`.
! 146: +
! 147: + All non-regular files are hard-linked (when possible).
! 148: +
! 149: 0. `--compress`, `-z`
! 150:
! 151: With this option, rsync compresses the file data as it is sent to the
! 152: diff --git a/rsync.h b/rsync.h
! 153: --- a/rsync.h
! 154: +++ b/rsync.h
! 155: @@ -165,6 +165,11 @@
! 156: #define COMPARE_DEST 1
! 157: #define COPY_DEST 2
! 158: #define LINK_DEST 3
! 159: +#define CLONE_DEST 4
! 160: +
! 161: +#if !defined FICLONE && defined __linux__
! 162: +#define FICLONE _IOW(0x94, 9, int)
! 163: +#endif
! 164:
! 165: #define MPLEX_BASE 7
! 166:
! 167: diff --git a/syscall.c b/syscall.c
! 168: --- a/syscall.c
! 169: +++ b/syscall.c
! 170: @@ -142,6 +142,54 @@ int do_link(const char *old_path, const char *new_path)
! 171: }
! 172: #endif
! 173:
! 174: +int do_clone(const char *old_path, const char *new_path, mode_t mode)
! 175: +{
! 176: +#ifdef FICLONE
! 177: + int ifd, ofd, ret, save_errno;
! 178: +
! 179: + if (dry_run) return 0;
! 180: + RETURN_ERROR_IF_RO_OR_LO;
! 181: +
! 182: + if ((ifd = do_open(old_path, O_RDONLY, 0)) < 0) {
! 183: + save_errno = errno;
! 184: + rsyserr(FERROR_XFER, errno, "open %s", full_fname(old_path));
! 185: + errno = save_errno;
! 186: + return -1;
! 187: + }
! 188: +
! 189: + if (robust_unlink(new_path) && errno != ENOENT) {
! 190: + save_errno = errno;
! 191: + rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(new_path));
! 192: + close(ifd);
! 193: + errno = save_errno;
! 194: + return -1;
! 195: + }
! 196: +
! 197: + mode &= INITACCESSPERMS;
! 198: + if ((ofd = do_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
! 199: + save_errno = errno;
! 200: + rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(new_path));
! 201: + close(ifd);
! 202: + errno = save_errno;
! 203: + return -1;
! 204: + }
! 205: +
! 206: + ret = ioctl(ofd, FICLONE, ifd);
! 207: + save_errno = errno;
! 208: + close(ifd);
! 209: + close(ofd);
! 210: + if (ret < 0)
! 211: + unlink(new_path);
! 212: + errno = save_errno;
! 213: + return ret;
! 214: +#else
! 215: + (void)old_path;
! 216: + (void)new_path;
! 217: + errno = ENOTSUP;
! 218: + return -1;
! 219: +#endif
! 220: +}
! 221: +
! 222: int do_lchown(const char *path, uid_t owner, gid_t group)
! 223: {
! 224: if (dry_run) return 0;
! 225: diff --git a/t_stub.c b/t_stub.c
! 226: --- a/t_stub.c
! 227: +++ b/t_stub.c
! 228: @@ -37,6 +37,7 @@ size_t max_alloc = 0; /* max_alloc is needed when combined with util2.o */
! 229: char *partial_dir;
! 230: char *module_dir;
! 231: filter_rule_list daemon_filter_list;
! 232: +short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
! 233:
! 234: void rprintf(UNUSED(enum logcode code), const char *format, ...)
! 235: {
! 236: diff --git a/t_unsafe.c b/t_unsafe.c
! 237: --- a/t_unsafe.c
! 238: +++ b/t_unsafe.c
! 239: @@ -28,7 +28,6 @@ int am_root = 0;
! 240: int am_sender = 1;
! 241: int read_only = 0;
! 242: int list_only = 0;
! 243: -short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
! 244:
! 245: int
! 246: main(int argc, char **argv)
! 247: diff -Nurp a/rsync.1 b/rsync.1
! 248: --- a/rsync.1
! 249: +++ b/rsync.1
! 250: @@ -500,6 +500,7 @@ detailed description below for a complet
! 251: --compare-dest=DIR also compare destination files relative to DIR
! 252: --copy-dest=DIR ... and include copies of unchanged files
! 253: --link-dest=DIR hardlink to files in DIR when unchanged
! 254: +--clone-dest=DIR clone (reflink) files from DIR when unchanged
! 255: --compress, -z compress file data during the transfer
! 256: --compress-choice=STR choose the compression algorithm (aka --zc)
! 257: --compress-level=NUM explicitly set compression level (aka --zl)
! 258: @@ -2372,6 +2373,15 @@ Note that rsync versions prior to 2.6.1
! 259: \fB\-\-link-dest\fP from working properly for a non-super-user when \fB\-o\fP was
! 260: specified (or implied by \fB\-a\fP). You can work-around this bug by avoiding
! 261: the \fB\-o\fP option when sending to an old rsync.
! 262: +.IP "\fB\-\-clone-dest=DIR\fP"
! 263: +This option behaves like \fB\-\-link-dest\fP, but unchanged files are reflinked
! 264: +from \fIDIR\fP to the destination directory. The files do not need to match
! 265: +in attributes, as the data is cloned separately from the attributes.
! 266: +.IP
! 267: +If \fIDIR\fP is a relative path, it is relative to the destination directory.
! 268: +See also \fB\-\-compare-dest\fP and \fB\-\-copy-dest\fP.
! 269: +.IP
! 270: +All non-regular files are hard-linked (when possible).
! 271: .IP "\fB\-\-compress\fP, \fB\-z\fP"
! 272: With this option, rsync compresses the file data as it is sent to the
! 273: destination machine, which reduces the amount of data being transmitted\ \-\-
! 274: diff -Nurp a/rsync.1.html b/rsync.1.html
! 275: --- a/rsync.1.html
! 276: +++ b/rsync.1.html
! 277: @@ -415,6 +415,7 @@ detailed description below for a complet
! 278: --compare-dest=DIR also compare destination files relative to DIR
! 279: --copy-dest=DIR ... and include copies of unchanged files
! 280: --link-dest=DIR hardlink to files in DIR when unchanged
! 281: +--clone-dest=DIR clone (reflink) files from DIR when unchanged
! 282: --compress, -z compress file data during the transfer
! 283: --compress-choice=STR choose the compression algorithm (aka --zc)
! 284: --compress-level=NUM explicitly set compression level (aka --zl)
! 285: @@ -2210,6 +2211,15 @@ specified (or implied by <code>-a</code>
! 286: the <code>-o</code> option when sending to an old rsync.</p>
! 287: </dd>
! 288:
! 289: +<dt><code>--clone-dest=DIR</code></dt><dd>
! 290: +<p>This option behaves like <code>--link-dest</code>, but unchanged files are reflinked
! 291: +from <u>DIR</u> to the destination directory. The files do not need to match
! 292: +in attributes, as the data is cloned separately from the attributes.</p>
! 293: +<p>If <u>DIR</u> is a relative path, it is relative to the destination directory.
! 294: +See also <code>--compare-dest</code> and <code>--copy-dest</code>.</p>
! 295: +<p>All non-regular files are hard-linked (when possible).</p>
! 296: +</dd>
! 297: +
! 298: <dt><code>--compress</code>, <code>-z</code></dt><dd>
! 299: <p>With this option, rsync compresses the file data as it is sent to the
! 300: destination machine, which reduces the amount of data being transmitted -⁠-⁠
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>