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 -⁠-⁠
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>