Annotation of embedaddon/rsync/patches/clone-dest.diff, revision 1.1.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>