Added a comment.
[rsync/rsync-patches.git] / xattrs.diff
CommitLineData
bbdff76a
WD
1Depends-On-Patch: acls.diff
2
3After applying this patch, run these commands for a successful build:
4
27e96866 5 ./prepare-source
f787c90c 6 ./configure --enable-acl-support --enable-xattr-support
bbdff76a
WD
7 make
8
9a7eef96
WD
9--- old/Makefile.in
10+++ new/Makefile.in
4bf6f8c7 11@@ -27,13 +27,13 @@ VERSION=@VERSION@
bbdff76a
WD
12
13 HEADERS=byteorder.h config.h errcode.h proto.h rsync.h smb_acls.h lib/pool_alloc.h
14 LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
15- lib/permstring.o lib/pool_alloc.o lib/sysacls.o @LIBOBJS@
16+ lib/permstring.o lib/pool_alloc.o lib/sysacls.o lib/sysxattr.o @LIBOBJS@
4bf6f8c7
WD
17 ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
18 zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
bbdff76a
WD
19 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
20 main.o checksum.o match.o syscall.o log.o backup.o
21 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
610969d1
WD
22- fileio.o batch.o clientname.o chmod.o acls.o
23+ fileio.o batch.o clientname.o chmod.o acls.o xattr.o
bbdff76a
WD
24 OBJS3=progress.o pipe.o
25 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
26 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
9a7eef96
WD
27--- old/backup.c
28+++ new/backup.c
09cc6650
WD
29@@ -135,6 +135,9 @@ static int make_bak_dir(char *fullpath)
30 #ifdef SUPPORT_ACLS
31 dup_acl(end, fullpath, st.st_mode);
32 #endif
33+#ifdef SUPPORT_XATTRS
34+ dup_xattr(end, fullpath );
35+#endif
bbdff76a
WD
36 }
37 }
38 *p = '/';
09cc6650
WD
39@@ -191,6 +194,9 @@ static int keep_backup(char *fname)
40 #ifdef SUPPORT_ACLS
41 push_keep_backup_acl(file, fname, buf);
42 #endif
43+#ifdef SUPPORT_XATTRS
44+ push_keep_backup_xattr(file, fname, buf);
45+#endif
bbdff76a
WD
46
47 /* Check to see if this is a device file, or link */
4a65fe72 48 if ((am_root && preserve_devices && IS_DEVICE(file->mode))
09cc6650
WD
49@@ -270,6 +276,9 @@ static int keep_backup(char *fname)
50 #ifdef SUPPORT_ACLS
51 cleanup_keep_backup_acl();
52 #endif
53+#ifdef SUPPORT_XATTRS
54+ cleanup_keep_backup_xattr();
55+#endif
bbdff76a
WD
56 free(file);
57
58 if (verbose > 1) {
9a7eef96
WD
59--- old/configure.in
60+++ new/configure.in
afcb578c 61@@ -814,6 +814,30 @@ samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_
bbdff76a
WD
62 AC_MSG_RESULT(no)
63 )
64
65+AC_CHECK_HEADERS(attr/xattr.h)
66+AC_MSG_CHECKING(whether to support extended attributes)
f787c90c
WD
67+AC_ARG_ENABLE(xattr-support,
68+AC_HELP_STRING([--enable-xattr-support], [Include extended attribute support (default=no)]),
3b05e91f 69+[ case "$enableval" in
bbdff76a
WD
70+ yes)
71+ case "$host_os" in
72+ *linux*)
73+ AC_MSG_RESULT(Using Linux xattrs)
74+ AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs])
75+ ;;
76+ *)
77+ AC_MSG_RESULT(Xattrs requested but not linux. Good luck)
78+ ;;
79+ esac
80+ ;;
81+ *)
82+ AC_MSG_RESULT(no)
83+ AC_DEFINE(HAVE_NA_XATTRS, 1, [True if you don't have extended attributes])
84+ esac ],
85+ AC_MSG_RESULT(no)
86+ AC_DEFINE(HAVE_NO_XATTRL, 1, [True if you don't have extended attributes])
87+)
88+
89 AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
90 AC_OUTPUT
91
9a7eef96
WD
92--- old/flist.c
93+++ new/flist.c
09cc6650
WD
94@@ -970,6 +970,10 @@ static struct file_struct *send_file_nam
95 if (make_acl(file, fname) < 0)
bbdff76a 96 return NULL;
09cc6650
WD
97 #endif
98+#ifdef SUPPORT_XATTRS
99+ if (make_xattr(file, fname) < 0)
bbdff76a 100+ return NULL;
09cc6650 101+#endif
bbdff76a 102
3b05e91f
WD
103 if (chmod_modes && !S_ISLNK(file->mode))
104 file->mode = tweak_mode(file->mode, chmod_modes);
09cc6650 105@@ -983,10 +987,18 @@ static struct file_struct *send_file_nam
3b05e91f 106 send_file_entry(file, f);
09cc6650
WD
107 #ifdef SUPPORT_ACLS
108 send_acl(file, f);
109+#endif
110+#ifdef SUPPORT_XATTRS
111+ send_xattr(file, f);
112+#endif
bbdff76a 113 } else {
09cc6650 114+#ifdef SUPPORT_ACLS
bbdff76a 115 /* Cleanup unsent ACL(s). */
09cc6650
WD
116 send_acl(file, -1);
117 #endif
118+#ifdef SUPPORT_XATTRS
119+ send_xattr(file, -1);
120+#endif
bbdff76a
WD
121 }
122 return file;
123 }
09cc6650
WD
124@@ -1378,6 +1390,9 @@ struct file_list *recv_file_list(int f)
125 #ifdef SUPPORT_ACLS
126 receive_acl(file, f);
127 #endif
128+#ifdef SUPPORT_XATTRS
129+ receive_xattr(file, f );
130+#endif
bbdff76a 131
3731f97b 132 if (S_ISREG(file->mode) || S_ISLNK(file->mode))
bbdff76a 133 stats.total_size += file->length;
09cc6650
WD
134@@ -1404,6 +1419,9 @@ struct file_list *recv_file_list(int f)
135 #ifdef SUPPORT_ACLS
136 sort_file_acl_index_lists();
bbdff76a
WD
137 #endif
138+#ifdef SUPPORT_XATTRS
09cc6650 139+ sort_file_xattr_index_lists();
bbdff76a 140+#endif
09cc6650
WD
141
142 if (f >= 0) {
143 recv_uid_list(f, flist);
9a7eef96
WD
144--- old/lib/sysxattr.c
145+++ new/lib/sysxattr.c
bbdff76a
WD
146@@ -0,0 +1,41 @@
147+/* Extended attribute support for rsync. */
148+/* This file Copyright (C) 2004 Red Hat, Inc. */
149+/* Written by Jay Fenlason */
150+
151+/* This program is free software; you can redistribute it and/or modify
152+ it under the terms of the GNU General Public License as published by
153+ the Free Software Foundation; either version 2 of the License, or
154+ (at your option) any later version.
155+
156+ This program is distributed in the hope that it will be useful,
157+ but WITHOUT ANY WARRANTY; without even the implied warranty of
158+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
159+ GNU General Public License for more details.
160+
161+ You should have received a copy of the GNU General Public License
162+ along with this program; if not, write to the Free Software
163+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
164+*/
165+
166+#include "rsync.h"
167+
09cc6650 168+#if defined HAVE_LINUX_XATTRS
bbdff76a
WD
169+
170+ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
171+{
172+ return lgetxattr(path, name, value, size);
173+}
174+
175+int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags)
176+{
177+ return lsetxattr(path, name, value, size, flags);
178+}
179+
180+ssize_t sys_llistxattr(const char *path, char *list, size_t size)
181+{
182+ return llistxattr(path, list, size);
183+}
184+
185+#else
186+
187+#endif /* No xattrs */
9a7eef96
WD
188--- old/lib/sysxattr.h
189+++ new/lib/sysxattr.h
bbdff76a 190@@ -0,0 +1,9 @@
09cc6650 191+#if defined HAVE_LINUX_XATTRS
bbdff76a
WD
192+
193+ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size);
194+int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags);
195+ssize_t sys_llistxattr(const char *path, char *list, size_t size);
196+
197+#else
198+
199+#endif /* No xattrs */
9a7eef96
WD
200--- old/options.c
201+++ new/options.c
3731f97b 202@@ -46,6 +46,7 @@ int copy_links = 0;
bbdff76a
WD
203 int preserve_links = 0;
204 int preserve_hard_links = 0;
205 int preserve_acls = 0;
206+int preserve_xattrs = 0;
207 int preserve_perms = 0;
4a65fe72 208 int preserve_executability = 0;
bbdff76a 209 int preserve_devices = 0;
afcb578c 210@@ -196,6 +197,7 @@ static void print_rsync_version(enum log
bbdff76a
WD
211 char const *have_inplace = "no ";
212 char const *hardlinks = "no ";
213 char const *acls = "no ";
214+ char const *xattrs = "no ";
215 char const *links = "no ";
216 char const *ipv6 = "no ";
217 STRUCT_STAT *dumstat;
afcb578c 218@@ -215,7 +217,9 @@ static void print_rsync_version(enum log
bbdff76a
WD
219 #ifdef SUPPORT_ACLS
220 acls = "";
221 #endif
222-
223+#ifdef SUPPORT_XATTRS
224+ xattrs = "";
225+#endif
226 #ifdef SUPPORT_LINKS
227 links = "";
228 #endif
afcb578c 229@@ -229,9 +233,9 @@ static void print_rsync_version(enum log
3b05e91f 230 rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n");
bbdff76a
WD
231 rprintf(f, "<http://rsync.samba.org/>\n");
232 rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
bc5988ec
WD
233- "%shard links, %sACLs, %ssymlinks, batchfiles,\n",
234+ "%shard links, %sACLs, %sxattrs, %ssymlinks, batchfiles,\n",
bbdff76a
WD
235 (int) (sizeof (OFF_T) * 8),
236- got_socketpair, hardlinks, acls, links);
237+ got_socketpair, hardlinks, acls, xattrs, links);
238
239 /* Note that this field may not have type ino_t. It depends
240 * on the complicated interaction between largefile feature
3731f97b 241@@ -304,6 +308,9 @@ void usage(enum logcode F)
3610c43c 242 #ifdef SUPPORT_ACLS
bbdff76a 243 rprintf(F," -A, --acls preserve ACLs (implies --perms)\n");
3610c43c
WD
244 #endif
245+#ifdef SUPPORT_XATTRS
bbdff76a 246+ rprintf(F," -X, --xattrs preserve extended attributes (implies --perms)\n");
3610c43c 247+#endif
4a65fe72
WD
248 rprintf(F," --chmod=CHMOD change destination permissions\n");
249 rprintf(F," -o, --owner preserve owner (super-user only)\n");
bbdff76a 250 rprintf(F," -g, --group preserve group\n");
3731f97b 251@@ -422,6 +429,9 @@ static struct poptOption long_options[]
489b0a72
WD
252 {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
253 {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
254 {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
255+ {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 },
256+ {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
257+ {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
258 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
259 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
260 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
3731f97b 261@@ -1096,6 +1106,17 @@ int parse_arguments(int *argc, const cha
489b0a72 262 return 0;
3610c43c 263 #endif
bbdff76a
WD
264
265+ case 'X':
266+#ifdef SUPPORT_XATTRS
267+ preserve_xattrs = 1;
268+ preserve_perms = 1;
489b0a72 269+ break;
bbdff76a
WD
270+#else
271+ snprintf(err_buf,sizeof(err_buf),
272+ "extended attributes are not supported on this %s\n",
273+ am_server ? "server" : "client");
274+ return 0;
275+#endif /* SUPPORT_XATTRS */
bbdff76a
WD
276
277 default:
278 /* A large opt value means that set_refuse_options()
3731f97b 279@@ -1544,6 +1565,10 @@ void server_options(char **args,int *arg
bbdff76a
WD
280 if (preserve_acls)
281 argstr[x++] = 'A';
3610c43c
WD
282 #endif
283+#ifdef SUPPORT_XATTRS
bbdff76a
WD
284+ if (preserve_xattrs)
285+ argstr[x++] = 'X';
3610c43c 286+#endif
bbdff76a
WD
287 if (preserve_uid)
288 argstr[x++] = 'o';
289 if (preserve_gid)
9a7eef96
WD
290--- old/rsync.c
291+++ new/rsync.c
09cc6650
WD
292@@ -224,6 +224,10 @@ int set_file_attrs(char *fname, struct f
293 if (set_acl(fname, file) == 0)
294 updated = 1;
e5754c5f 295 #endif
09cc6650
WD
296+#ifdef SUPPORT_XATTRS
297+ if (set_xattr(fname, file) == 0)
298+ updated = 1;
299+#endif
bbdff76a 300
4a65fe72 301 if (verbose > 1 && flags & ATTRS_REPORT) {
09cc6650 302 enum logcode code = daemon_log_format_has_i || dry_run
9a7eef96
WD
303--- old/rsync.h
304+++ new/rsync.h
09cc6650
WD
305@@ -672,6 +672,14 @@ struct chmod_mode_struct;
306 #endif
bbdff76a
WD
307 #include "smb_acls.h"
308
309+#ifdef HAVE_LINUX_XATTRS
310+#define SUPPORT_XATTRS 1
311+#endif
312+
09cc6650 313+#if defined SUPPORT_XATTRS && defined HAVE_ATTR_XATTR_H
bbdff76a
WD
314+#include <attr/xattr.h>
315+#endif
bbdff76a
WD
316+
317 #include "proto.h"
318
319 /* We have replacement versions of these if they're missing. */
9a7eef96
WD
320--- old/rsync.yo
321+++ new/rsync.yo
3731f97b 322@@ -322,6 +322,7 @@ to the detailed description below for a
bbdff76a 323 -p, --perms preserve permissions
4a65fe72
WD
324 -E, --executability preserve executability
325 -A, --acls preserve ACLs (implies -p) [non-standard]
326+ -X, --xattrs preserve extended attrs (implies -p) [n.s.]
327 --chmod=CHMOD change destination permissions
328 -o, --owner preserve owner (super-user only)
bbdff76a 329 -g, --group preserve group
3731f97b 330@@ -802,6 +803,11 @@ dit(bf(-A, --acls)) This option causes r
4a65fe72
WD
331 ACLs to be the same as the source ACLs. This nonstandard option only
332 works if the remote rsync also supports it. bf(--acls) implies bf(--perms).
bbdff76a
WD
333
334+dit(bf(-X, --xattrs)) This option causes rsync to update the remote
335+extended attributes to be the same as the local ones. This will work
336+only if the remote machine's rsync supports this option also. This is
337+a non-standard option.
338+
4a65fe72
WD
339 dit(bf(--chmod)) This option tells rsync to apply one or more
340 comma-separated "chmod" strings to the permission of the files in the
341 transfer. The resulting value is treated as though it was the permissions
9a7eef96
WD
342--- old/xattr.c
343+++ new/xattr.c
e5754c5f 344@@ -0,0 +1,540 @@
bbdff76a
WD
345+/* Extended Attribute support for rsync */
346+/* Copyright (C) 2004 Red Hat, Inc */
347+/* Written by Jay Fenlason, vaguely based on the ACLs patch */
348+
349+/* This program is free software; you can redistribute it and/or modify
350+ it under the terms of the GNU General Public License as published by
351+ the Free Software Foundation; either version 2 of the License, or
352+ (at your option) any later version.
353+
354+ This program is distributed in the hope that it will be useful,
355+ but WITHOUT ANY WARRANTY; without even the implied warranty of
356+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
357+ GNU General Public License for more details.
358+
359+ You should have received a copy of the GNU General Public License
360+ along with this program; if not, write to the Free Software
361+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
362+*/
363+
364+#include "rsync.h"
365+#include "lib/sysxattr.h"
366+
367+#ifdef SUPPORT_XATTRS
368+
369+extern int preserve_xattrs;
370+extern int dry_run;
371+
372+#define RSYNC_XAL_INITIAL 5
373+#define RSYNC_XAL_LIST_INITIAL 100
374+
375+typedef struct {
376+ size_t name_len;
377+ char *name;
378+ size_t datum_len;
379+ char *datum;
380+} rsync_xa;
381+
382+typedef struct {
383+ size_t count;
384+ size_t alloc;
385+ rsync_xa *rxas;
386+} rsync_xal;
387+
388+typedef struct {
389+ size_t count;
390+ size_t alloc;
391+ rsync_xal *rxals;
392+} rsync_xal_list;
393+
394+static size_t namebuf_len = 0;
395+static char *namebuf = NULL;
396+
397+static size_t datumbuf_len = 0;
398+static char *datumbuf = NULL;
399+
400+static rsync_xal curr_rsync_xal = { 0, 0, NULL };
401+static rsync_xal_list rsync_xal_l = { 0, 0, NULL };
402+
403+
404+/* ------------------------------------------------------------------------- */
405+
406+/* the below stuff is only used by the receiver */
407+
408+/* structure to hold index to rsync_xal_l member corresponding to
409+ * flist->files[i] */
410+
411+typedef struct {
412+ const struct file_struct *file;
413+ int xalidx;
414+} file_xal_index;
415+
416+typedef struct {
417+ size_t count;
418+ size_t alloc;
419+ file_xal_index *filexalidxs;
420+} file_xal_index_list;
421+
422+static file_xal_index_list fxil = {0, 0, NULL };
423+
424+/* stuff for redirecting calls to set_acl() from set_perms()
425+ * for keep_backup() */
426+static const struct file_struct *backup_orig_file = NULL;
427+static const char null_string[] = "";
428+static const char *backup_orig_fname = null_string;
429+static const char *backup_dest_fname = null_string;
430+static rsync_xal backup_xal;
431+
432+/* ------------------------------------------------------------------------- */
433+
434+static void rsync_xal_free(rsync_xal *x)
435+{
436+ size_t i;
437+
438+ for (i = 0; i < x->count; i++) {
439+ free(x->rxas[i].name);
440+ /* free(x->rxas[i].value); */
441+ }
442+ x->count = 0;
443+}
444+
445+static int rsync_xal_compare_names(const void *x1, const void *x2)
446+{
447+ const rsync_xa *xa1;
448+ const rsync_xa *xa2;
449+
450+ xa1 = x1;
451+ xa2 = x2;
452+ return strcmp(xa1->name, xa2->name);
453+}
454+
e5754c5f 455+static int rsync_xal_get(const char *fname, rsync_xal *x)
bbdff76a
WD
456+{
457+ ssize_t name_size;
458+ ssize_t datum_size;
459+ ssize_t left;
460+ char *name;
461+ size_t len;
462+ char *ptr;
463+
464+ if (!namebuf) {
465+ namebuf_len = 100;
466+ namebuf = new_array(char, namebuf_len);
467+ datumbuf_len = 100;
468+ datumbuf = new_array(char, datumbuf_len);
469+ if (!namebuf || !datumbuf)
470+ out_of_memory("rsync_xal_get");
471+ }
472+
473+ name_size = sys_llistxattr(fname, namebuf, namebuf_len);
474+ if (name_size > (ssize_t)namebuf_len) {
475+ name_size = -1;
476+ errno = ERANGE;
477+ }
478+ if (name_size < 0) {
479+ if (errno == ENOTSUP)
e5754c5f 480+ return -1;
bbdff76a
WD
481+ if (errno == ERANGE) {
482+ name_size = sys_llistxattr(fname, NULL, 0);
483+ if (name_size < 0) {
484+ rprintf(FERROR, "%s: rsync_xal_get: llistxattr: %s\n",
e5754c5f
WD
485+ fname, strerror(errno));
486+ return -1;
bbdff76a
WD
487+ }
488+ namebuf = realloc_array(namebuf, char, name_size + 1);
489+ if (!namebuf)
490+ out_of_memory("rsync_xal_get");
491+ namebuf_len = name_size;
492+ name_size = sys_llistxattr(fname, namebuf, namebuf_len);
493+ if (name_size < 0) {
494+ rprintf(FERROR,
495+ "%s: rsync_xal_get: re-llistxattr failed: %s\n",
496+ fname, strerror(errno));
e5754c5f 497+ return -1;
bbdff76a
WD
498+ }
499+ } else {
500+ rprintf(FERROR,
501+ "%s: rsync_xal_get: llistxattr failed: %s\n",
502+ fname, strerror(errno));
e5754c5f 503+ return -1;
bbdff76a
WD
504+ }
505+ }
506+ rsync_xal_free(x);
507+ if (name_size == 0)
e5754c5f 508+ return 0;
bbdff76a
WD
509+ for (left = name_size, name = namebuf; left > 0 ; left -= len, name += len) {
510+ len = strlen(name) + 1;
511+
512+ if (x->count >= x->alloc) {
513+ size_t new_alloc;
514+ rsync_xa *new_rxas;
515+
516+ new_alloc = x->alloc < RSYNC_XAL_INITIAL ? RSYNC_XAL_INITIAL : x->alloc * 2;
517+ new_rxas = realloc_array(x->rxas, rsync_xa, new_alloc);
518+ if (!new_rxas)
519+ out_of_memory("rsync_xal_get");
520+ x->alloc = new_alloc;
521+ x->rxas = new_rxas;
522+ }
523+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
524+ if (datum_size > (ssize_t)datumbuf_len) {
525+ datum_size = -1;
526+ errno = ERANGE;
527+ }
528+ if (datum_size < 0) {
529+ if (errno == ENOTSUP)
e5754c5f 530+ return -1;
bbdff76a
WD
531+ if (errno == ERANGE) {
532+ datum_size = sys_lgetxattr(fname, name, NULL, 0);
533+ if (datum_size < 0) {
534+ rprintf(FERROR,
535+ "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
536+ fname, name, strerror(errno));
e5754c5f 537+ return -1;
bbdff76a
WD
538+ }
539+ datumbuf = realloc_array(datumbuf, char, datum_size + 1);
540+ if (!datumbuf)
541+ out_of_memory("rsync_xal_get");
542+ datumbuf_len = datum_size;
543+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
544+ if (datum_size < 0) {
545+ rprintf(FERROR,
546+ "%s: rsync_xal_get: re-lgetxattr of %s failed: %s\n",
547+ name, fname, strerror(errno));
e5754c5f 548+ return -1;
bbdff76a
WD
549+ }
550+ } else {
551+ rprintf(FERROR,
552+ "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
553+ fname, name, strerror(errno));
e5754c5f 554+ return -1;
bbdff76a
WD
555+ }
556+ }
557+ ptr = new_array(char, len + datum_size);
558+ if (!ptr)
559+ out_of_memory("rsync_xal_get");
560+ strcpy(ptr, name);
561+ if (datum_size)
562+ memcpy(ptr + len, datumbuf, datum_size);
563+ x->rxas[curr_rsync_xal.count].name_len = len;
564+ x->rxas[curr_rsync_xal.count].name = ptr;
565+ x->rxas[curr_rsync_xal.count].datum_len = datum_size;
566+ x->rxas[curr_rsync_xal.count].datum = ptr + len;
567+ x->count++;
568+ }
569+ if (x->count > 1) {
570+ qsort(x->rxas, x->count, sizeof (rsync_xa), rsync_xal_compare_names);
571+ }
e5754c5f 572+ return 0;
bbdff76a
WD
573+}
574+
575+
576+/* generate the xattr(s) for this flist entry;
577+ * xattr(s) are either sent or cleaned-up by send_xattr() below */
578+
e5754c5f 579+int make_xattr(const struct file_struct *file, const char *fname)
bbdff76a 580+{
a8801c39 581+ if (!preserve_xattrs || !file)
e5754c5f 582+ return 1;
bbdff76a
WD
583+
584+ rsync_xal_get(fname, &curr_rsync_xal);
e5754c5f 585+ return 0; /* TODO: This needs to return 1 if no xattrs changed! */
bbdff76a
WD
586+}
587+
588+static ssize_t rsync_xal_find_matching(void)
589+{
590+ size_t i;
591+ size_t j;
592+
593+ for (i = 0; i < rsync_xal_l.count; i++) {
594+ /* Wrong number of elements? */
595+ if (rsync_xal_l.rxals[i].count != curr_rsync_xal.count)
596+ continue;
597+ /* any elements different? */
598+ for (j = 0; j < curr_rsync_xal.count; j++) {
599+ if (rsync_xal_l.rxals[i].rxas[j].name_len != curr_rsync_xal.rxas[j].name_len
600+ || rsync_xal_l.rxals[i].rxas[j].datum_len != curr_rsync_xal.rxas[j].datum_len
601+ || strcmp(rsync_xal_l.rxals[i].rxas[j].name, curr_rsync_xal.rxas[j].name)
602+ || memcmp(rsync_xal_l.rxals[i].rxas[j].datum, curr_rsync_xal.rxas[j].datum, curr_rsync_xal.rxas[j].datum_len))
603+ break;
604+ }
605+ /* no differences found. This is The One! */
606+ if (j == curr_rsync_xal.count)
607+ break;
608+ }
609+ if (i < rsync_xal_l.count)
610+ return i;
611+ return (ssize_t)-1;
612+}
613+
614+/* Store curr_rsync_xal on the end of rsync_xal_l */
615+static void rsync_xal_store(void)
616+{
617+ if (rsync_xal_l.count <= rsync_xal_l.alloc) {
618+ size_t new_alloc;
619+ void *new_xal;
620+
621+ new_alloc = rsync_xal_l.count < RSYNC_XAL_LIST_INITIAL ? RSYNC_XAL_LIST_INITIAL : rsync_xal_l.count * 2;
622+ new_xal = realloc_array(rsync_xal_l.rxals, rsync_xal, new_alloc);
623+ if (!new_xal)
624+ out_of_memory("rsync_xal_store");
625+ rsync_xal_l.alloc = new_alloc;
626+ rsync_xal_l.rxals = new_xal;
627+ }
628+ rsync_xal_l.rxals[rsync_xal_l.count] = curr_rsync_xal;
629+ rsync_xal_l.count++;
630+ curr_rsync_xal.count = 0;
631+ curr_rsync_xal.alloc = 0;
632+}
633+
634+/* send the make_xattr()-generated xattr list for this flist entry,
635+ * or clean up after an flist entry that's not being sent (f == -1) */
636+
637+void send_xattr(const struct file_struct *file, int f)
638+{
639+ ssize_t index;
640+
a8801c39 641+ if (!preserve_xattrs || !file)
bbdff76a
WD
642+ return;
643+
644+ if (f == -1) {
645+ rsync_xal_free(&curr_rsync_xal);
646+ return;
647+ }
648+ index = rsync_xal_find_matching();
649+ if (index != -1) {
650+ write_byte(f, 'x');
651+ write_int(f, index);
652+ rsync_xal_free(&curr_rsync_xal);
653+ } else {
654+ rsync_xa *rxa;
655+ size_t count;
656+
657+ count = curr_rsync_xal.count;
658+ write_byte(f, 'X');
659+ write_int(f, count);
660+ for (rxa = curr_rsync_xal.rxas; count--; rxa++) {
661+ write_int(f, rxa->name_len);
662+ write_int(f, rxa->datum_len);
663+ write_buf(f, rxa->name, rxa->name_len);
664+ write_buf(f, rxa->datum, rxa->datum_len);
665+ }
666+ rsync_xal_store();
667+ }
668+}
669+
670+
671+/* ------------------------------------------------------------------------- */
672+/* receive and build the rsync_xattr_lists */
673+
674+void receive_xattr(struct file_struct *file, int f)
675+{
676+ char *fname;
677+ int tag;
678+
679+ if (!preserve_xattrs)
680+ return;
bd68c3c2 681+ fname = f_name(file, NULL);
bbdff76a
WD
682+ tag = read_byte(f);
683+ if (tag != 'X' && tag != 'x') {
684+ rprintf(FERROR,
685+ "%s: receive_xattr: unknown extended attribute type tag: %c\n",
686+ fname, tag);
687+ exit_cleanup(RERR_STREAMIO);
688+ }
689+
690+ if (fxil.alloc <= fxil.count) {
691+ void *new_ptr;
692+ size_t new_alloc;
693+
694+ if (fxil.count < RSYNC_XAL_LIST_INITIAL)
695+ new_alloc = fxil.alloc + RSYNC_XAL_LIST_INITIAL;
696+ else
697+ new_alloc = fxil.alloc * 2;
698+ new_ptr = realloc_array(fxil.filexalidxs, file_xal_index, new_alloc);
699+ if (!new_ptr)
700+ out_of_memory("receive_xattr");
701+ if (verbose >= 3) {
702+ rprintf(FINFO, "receive_xattr to %lu bytes, %s move\n",
703+ (unsigned long)(new_alloc * sizeof (file_xal_index)),
704+ fxil.filexalidxs == new_ptr ? "did not" : "did");
705+ }
706+
707+ fxil.filexalidxs = new_ptr;
708+ fxil.alloc = new_alloc;
709+ }
710+
711+ fxil.filexalidxs[fxil.count].file = file;
712+ if (tag == 'X') {
713+ size_t count;
714+ size_t i;
715+
716+ fxil.filexalidxs[fxil.count].xalidx = rsync_xal_l.count;
717+
718+ count = read_int(f);
719+ curr_rsync_xal.count = count;
720+ curr_rsync_xal.alloc = count;
721+ curr_rsync_xal.rxas = new_array(rsync_xa, count);
722+ if (!curr_rsync_xal.rxas)
723+ out_of_memory("receive_xattr");
724+ for (i = 0; i < count; i++) {
725+ size_t name_len;
726+ size_t datum_len;
727+ char *ptr;
728+
729+ name_len = read_int(f);
730+ datum_len = read_int(f);
731+ ptr = new_array(char, name_len + datum_len);
732+ if (!ptr)
733+ out_of_memory("receive_xattr");
734+ read_buf(f, ptr, name_len);
735+ read_buf(f, ptr + name_len, datum_len);
736+ curr_rsync_xal.rxas[i].name_len = name_len;
737+ curr_rsync_xal.rxas[i].datum_len = datum_len;
738+ curr_rsync_xal.rxas[i].name = ptr;
739+ curr_rsync_xal.rxas[i].datum = ptr + name_len;
740+ }
741+ rsync_xal_store();
742+ } else {
743+ size_t index;
744+
745+ index = read_int(f);
746+ if (index >= rsync_xal_l.count) {
747+ rprintf(FERROR, "%s: receive_xattr: xa index %lu out of range\n",
e5754c5f 748+ fname, (unsigned long)index);
bbdff76a
WD
749+ exit_cleanup(RERR_STREAMIO);
750+ }
751+ fxil.filexalidxs[fxil.count].xalidx = index;
752+ }
753+ fxil.count++;
754+}
755+
e5754c5f 756+static int rsync_xal_set(const char *fname, rsync_xal *x)
bbdff76a
WD
757+{
758+ size_t i;
e5754c5f 759+ int ret = 0;
bbdff76a 760+
bbdff76a 761+ for (i = 0; i < x->count; i++) {
e5754c5f 762+ int status = sys_lsetxattr(fname, x->rxas[i].name, x->rxas[i].datum, x->rxas[i].datum_len, 0);
bbdff76a
WD
763+ if (status < 0) {
764+ rprintf(FERROR, "%s: rsync_xal_set: lsetxattr %s failed: %s\n",
765+ fname, x->rxas[i].name, strerror(errno));
e5754c5f 766+ ret = -1;
bbdff76a
WD
767+ }
768+ }
769+ return ret;
770+}
771+
772+/* for duplicating xattrs on backups when using backup_dir */
773+
774+int dup_xattr(const char *orig, const char *bak)
775+{
776+ int ret;
777+
bbdff76a 778+ if (!preserve_xattrs)
e5754c5f 779+ return 1;
bbdff76a 780+
e5754c5f 781+ if (rsync_xal_get(orig, &backup_xal) < 0)
bbdff76a 782+ ret = rsync_xal_set(bak, &backup_xal);
e5754c5f
WD
783+ else
784+ ret = 0;
bbdff76a
WD
785+ rsync_xal_free(&backup_xal);
786+ return ret;
787+}
788+
789+void push_keep_backup_xattr(const struct file_struct *file, const char *orig, const char *dest)
790+{
791+ if (!preserve_xattrs)
792+ return;
793+
794+ backup_orig_file = file;
795+ backup_orig_fname = orig;
796+ backup_dest_fname = dest;
797+ rsync_xal_get(orig, &backup_xal);
798+}
799+
800+static int set_keep_backup_xal(void)
801+{
802+ if (!preserve_xattrs)
e5754c5f 803+ return 1;
bbdff76a
WD
804+ return rsync_xal_set(backup_dest_fname, &backup_xal);
805+}
806+
807+void cleanup_keep_backup_xattr(void)
808+{
809+ if (!preserve_xattrs)
810+ return;
811+
812+ backup_orig_file = NULL;
813+ backup_orig_fname = null_string;
814+ backup_dest_fname = null_string;
815+ rsync_xal_free(&backup_xal);
816+}
817+
818+static int file_xal_index_compare(const void *x1, const void *x2)
819+{
820+ const file_xal_index *xa1;
821+ const file_xal_index *xa2;
822+
823+ xa1 = x1;
824+ xa2 = x2;
825+ return xa1->file == xa2->file ? 0 : xa1->file < xa2->file ? -1 : 1;
826+}
827+
828+void sort_file_xattr_index_lists(void)
829+{
830+ if (!preserve_xattrs)
831+ return;
832+ qsort(fxil.filexalidxs, fxil.count, sizeof (file_xal_index), file_xal_index_compare);
833+}
834+
835+static int find_file_xal_index(const struct file_struct *file)
836+{
837+ int low = 0, high = fxil.count;
838+ const struct file_struct *file_mid;
839+
840+ if (!high--) {
841+ rprintf(FERROR, "find_file_xal_index: no entries\n");
842+ exit_cleanup(RERR_STREAMIO);
843+ return -1;
844+ }
845+ do {
846+ int mid = (high + low) / 2;
847+ file_mid = fxil.filexalidxs[mid].file;
848+ if (file_mid == file)
849+ return fxil.filexalidxs[mid].xalidx;
850+ if (file_mid > file)
851+ high = mid - 1;
852+ else
853+ low = mid + 1;
854+ } while (low < high);
855+ if (low == high) {
856+ file_mid = fxil.filexalidxs[low].file;
857+ if (file_mid == file)
858+ return fxil.filexalidxs[low].xalidx;
859+ }
860+ rprintf(FERROR,
861+ "find_file_xal_index: can't find entry for file in list\n");
862+ exit_cleanup(RERR_STREAMIO);
863+ return -1;
864+}
865+
bbdff76a
WD
866+/* set extended attributes on rsync-ed or keep_backup-ed file */
867+
868+int set_xattr(const char *fname, const struct file_struct *file)
869+{
bbdff76a
WD
870+ int xalidx;
871+ rsync_xal *x;
872+
bbdff76a 873+ if (dry_run || !preserve_xattrs)
e5754c5f 874+ return 1;
bbdff76a
WD
875+ if (file == backup_orig_file) {
876+ if (!strcmp(fname, backup_dest_fname))
877+ return set_keep_backup_xal();
878+ }
879+ xalidx = find_file_xal_index(file);
880+ x = &(rsync_xal_l.rxals[xalidx]);
e5754c5f 881+ return rsync_xal_set(fname, x);
bbdff76a
WD
882+}
883+
884+#endif /* SUPPORT_XATTRS */