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&nbsp;-&#8288;-&#8288;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>