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