File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / patches / clone-dest.diff
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    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>