Changed the --width-* option to an --enable-* option (as it should
[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
4bf6f8c7
WD
11--- orig/Makefile.in 2005-07-07 23:11:55
12+++ Makefile.in 2005-07-07 23:15:20
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 \
24- fileio.o batch.o clientname.o acls.o
25+ fileio.o batch.o clientname.o acls.o xattr.o
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
31@@ -136,6 +136,7 @@ static int make_bak_dir(char *fullpath)
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 = '/';
39@@ -189,6 +190,7 @@ static int keep_backup(char *fname)
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 */
4bf6f8c7
WD
46 if (IS_DEVICE(file->mode) && am_root && preserve_devices) {
47@@ -265,6 +267,7 @@ static int keep_backup(char *fname)
bbdff76a
WD
48 }
49 set_perms(buf, file, NULL, 0);
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
489b0a72 57@@ -822,6 +822,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)]),
bbdff76a
WD
65+[ case "$withval" in
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
489b0a72 88--- orig/flist.c 2005-07-29 02:49:06
bbdff76a 89+++ flist.c 2005-05-12 22:55:41
f787c90c 90@@ -970,6 +970,8 @@ static struct file_struct *send_file_nam
bbdff76a 91 return NULL;
489b0a72 92 if (MAKE_ACL(file, fname) < 0)
bbdff76a
WD
93 return NULL;
94+ if (!MAKE_XATTR(file, fname))
95+ return NULL;
96
97 maybe_emit_filelist_progress(flist->count + flist_count_offset);
98
f787c90c 99@@ -979,9 +981,11 @@ static struct file_struct *send_file_nam
bbdff76a
WD
100 flist->files[flist->count++] = file;
101 send_file_entry(file, f, base_flags);
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 }
f787c90c 111@@ -1328,6 +1332,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;
f787c90c 119@@ -1352,6 +1357,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) {
126 /* Now send the uid/gid list. This was introduced in
127--- orig/generator.c 2005-05-12 23:34:00
128+++ generator.c 2005-05-12 23:21:08
489b0a72 129@@ -729,6 +729,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))
139 delete_in_dir(the_file_list, fname, file);
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 */
489b0a72
WD
196--- orig/options.c 2005-08-27 21:15:29
197+++ options.c 2005-08-27 21:29:40
1a2bc9cd 198@@ -44,6 +44,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;
204 int preserve_devices = 0;
205 int preserve_uid = 0;
489b0a72 206@@ -183,6 +184,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;
489b0a72 214@@ -202,7 +204,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
489b0a72 225@@ -217,9 +221,9 @@ static void print_rsync_version(enum log
bbdff76a
WD
226 "Copyright (C) 1996-2005 by Andrew Tridgell and others\n");
227 rprintf(f, "<http://rsync.samba.org/>\n");
228 rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
229- "%shard links, %sACLs, %ssymlinks, batchfiles, \n",
230+ "%shard links, %sACLs, %sxattrs, %ssymlinks, batchfiles, \n",
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
f787c90c 237@@ -290,6 +294,7 @@ void usage(enum logcode F)
bbdff76a
WD
238 rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
239 rprintf(F," -p, --perms preserve permissions\n");
240 rprintf(F," -A, --acls preserve ACLs (implies --perms)\n");
241+ rprintf(F," -X, --xattrs preserve extended attributes (implies --perms)\n");
242 rprintf(F," -o, --owner preserve owner (root only)\n");
243 rprintf(F," -g, --group preserve group\n");
244 rprintf(F," -D, --devices preserve devices (root only)\n");
489b0a72
WD
245@@ -395,6 +400,9 @@ static struct poptOption long_options[]
246 {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
247 {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
248 {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
249+ {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 },
250+ {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
251+ {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
252 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
253 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
254 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
f787c90c 255@@ -954,6 +962,17 @@ int parse_arguments(int *argc, const cha
489b0a72 256 return 0;
bbdff76a 257 #endif /* SUPPORT_ACLS */
bbdff76a
WD
258
259+ case 'X':
260+#ifdef SUPPORT_XATTRS
261+ preserve_xattrs = 1;
262+ preserve_perms = 1;
489b0a72 263+ break;
bbdff76a
WD
264+#else
265+ snprintf(err_buf,sizeof(err_buf),
266+ "extended attributes are not supported on this %s\n",
267+ am_server ? "server" : "client");
268+ return 0;
269+#endif /* SUPPORT_XATTRS */
bbdff76a
WD
270
271 default:
272 /* A large opt value means that set_refuse_options()
f787c90c 273@@ -1378,6 +1397,8 @@ void server_options(char **args,int *arg
bbdff76a
WD
274 argstr[x++] = 'H';
275 if (preserve_acls)
276 argstr[x++] = 'A';
277+ if (preserve_xattrs)
278+ argstr[x++] = 'X';
279 if (preserve_uid)
280 argstr[x++] = 'o';
281 if (preserve_gid)
282--- orig/rsync.c 2004-07-03 20:11:58
283+++ rsync.c 2005-03-03 01:31:22
489b0a72 284@@ -146,6 +146,14 @@ int set_perms(char *fname,struct file_st
bbdff76a
WD
285 if (SET_ACL(fname, file) == 0)
286 updated = 1;
287 }
288+ /* If this is a directory, SET_XATTR() will be called on the cleanup
289+ * receive_generator() pass--if we called it here, we might clobber
290+ * writability on the directory (SELinux security contexts are stored
291+ * in xattrs). everything else is OK to do now. */
292+ if (!S_ISDIR(st->st_mode)) {
293+ if (SET_XATTR(fname, file) == 0)
294+ updated = 1;
295+ }
296
297 if (verbose > 1 && flags & PERMS_REPORT) {
298 enum logcode code = daemon_log_format_has_i || dry_run
489b0a72 299--- orig/rsync.h 2005-07-29 02:25:55
bbdff76a 300+++ rsync.h 2005-05-12 23:19:46
f787c90c 301@@ -688,6 +688,38 @@ struct stats {
bbdff76a
WD
302 #endif /* SUPPORT_ACLS */
303 #include "smb_acls.h"
304
305+#ifdef HAVE_LINUX_XATTRS
306+#define SUPPORT_XATTRS 1
307+#endif
308+
309+#ifdef SUPPORT_XATTRS
310+#ifdef HAVE_ATTR_XATTR_H
311+#include <attr/xattr.h>
312+#endif
313+#define MAKE_XATTR(file, fname) make_xattr(file, fname)
314+#define SEND_XATTR(file, f) send_xattr(file, f)
315+#define RECEIVE_XATTR(file, f) receive_xattr(file, f)
316+#define SORT_FILE_XATTR_INDEX_LISTS() sort_file_xattr_index_lists()
317+#define SET_XATTR(fname, file) set_xattr(fname, file)
318+#define NEXT_XATTR_UID() next_xattr_uid()
319+#define XATTR_UID_MAP(uid) xattr_uid_map(uid)
320+#define PUSH_KEEP_BACKUP_XATTR(file, orig, dest) \
321+ push_keep_backup_xattr(file, orig, dest)
322+#define CLEANUP_KEEP_BACKUP_XATTR() cleanup_keep_backup_xattr()
323+#define DUP_XATTR(orig, dest) dup_xattr(orig, dest)
324+#else /* SUPPORT_XATTRS */
325+#define MAKE_XATTR(file, fname) 1 /* checked return value */
326+#define SEND_XATTR(file, f)
327+#define RECEIVE_XATTR(file, f)
328+#define SORT_FILE_XATTR_INDEX_LISTS()
329+#define SET_XATTR(fname, file) 0 /* checked return value */
330+#define NEXT_XATTR_UID()
331+#define XATTR_UID_MAP(uid)
332+#define PUSH_KEEP_BACKUP_XATTR(file, orig, dest)
333+#define CLEANUP_KEEP_BACKUP_XATTR()
334+#define DUP_XATTR(src, orig) 0 /* checked return value */
335+#endif /* SUPPORT_XATTRS */
336+
337 #include "proto.h"
338
339 /* We have replacement versions of these if they're missing. */
340--- orig/rsync.yo 2004-07-03 20:11:58
341+++ rsync.yo 2005-03-03 01:33:53
f787c90c 342@@ -317,6 +317,7 @@ to the detailed description below for a
bbdff76a
WD
343 -K, --keep-dirlinks treat symlinked dir on receiver as dir
344 -p, --perms preserve permissions
345 -A, --acls preserve ACLs (implies -p) [local option]
346+ -X, --xattrs preserve extended attributes (implies -p) [local option]
347 -o, --owner preserve owner (root only)
348 -g, --group preserve group
349 -D, --devices preserve devices (root only)
489b0a72 350@@ -671,6 +672,11 @@ ACLs to be the same as the local ACLs.
bbdff76a
WD
351 remote machine's rsync supports this option also. This is a non-standard
352 option.
353
354+dit(bf(-X, --xattrs)) This option causes rsync to update the remote
355+extended attributes to be the same as the local ones. This will work
356+only if the remote machine's rsync supports this option also. This is
357+a non-standard option.
358+
359 dit(bf(-o, --owner)) This option causes rsync to set the owner of the
360 destination file to be the same as the source file. On most systems,
361 only the super-user can set file ownership. By default, the preservation
a8801c39
WD
362--- orig/xattr.c 2005-05-13 06:10:34
363+++ xattr.c 2005-05-13 06:10:34
bbdff76a
WD
364@@ -0,0 +1,546 @@
365+/* Extended Attribute support for rsync */
366+/* Copyright (C) 2004 Red Hat, Inc */
367+/* Written by Jay Fenlason, vaguely based on the ACLs patch */
368+
369+/* This program is free software; you can redistribute it and/or modify
370+ it under the terms of the GNU General Public License as published by
371+ the Free Software Foundation; either version 2 of the License, or
372+ (at your option) any later version.
373+
374+ This program is distributed in the hope that it will be useful,
375+ but WITHOUT ANY WARRANTY; without even the implied warranty of
376+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
377+ GNU General Public License for more details.
378+
379+ You should have received a copy of the GNU General Public License
380+ along with this program; if not, write to the Free Software
381+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
382+*/
383+
384+#include "rsync.h"
385+#include "lib/sysxattr.h"
386+
387+#ifdef SUPPORT_XATTRS
388+
389+extern int preserve_xattrs;
390+extern int dry_run;
391+
392+#define RSYNC_XAL_INITIAL 5
393+#define RSYNC_XAL_LIST_INITIAL 100
394+
395+typedef struct {
396+ size_t name_len;
397+ char *name;
398+ size_t datum_len;
399+ char *datum;
400+} rsync_xa;
401+
402+typedef struct {
403+ size_t count;
404+ size_t alloc;
405+ rsync_xa *rxas;
406+} rsync_xal;
407+
408+typedef struct {
409+ size_t count;
410+ size_t alloc;
411+ rsync_xal *rxals;
412+} rsync_xal_list;
413+
414+static size_t namebuf_len = 0;
415+static char *namebuf = NULL;
416+
417+static size_t datumbuf_len = 0;
418+static char *datumbuf = NULL;
419+
420+static rsync_xal curr_rsync_xal = { 0, 0, NULL };
421+static rsync_xal_list rsync_xal_l = { 0, 0, NULL };
422+
423+
424+/* ------------------------------------------------------------------------- */
425+
426+/* the below stuff is only used by the receiver */
427+
428+/* structure to hold index to rsync_xal_l member corresponding to
429+ * flist->files[i] */
430+
431+typedef struct {
432+ const struct file_struct *file;
433+ int xalidx;
434+} file_xal_index;
435+
436+typedef struct {
437+ size_t count;
438+ size_t alloc;
439+ file_xal_index *filexalidxs;
440+} file_xal_index_list;
441+
442+static file_xal_index_list fxil = {0, 0, NULL };
443+
444+/* stuff for redirecting calls to set_acl() from set_perms()
445+ * for keep_backup() */
446+static const struct file_struct *backup_orig_file = NULL;
447+static const char null_string[] = "";
448+static const char *backup_orig_fname = null_string;
449+static const char *backup_dest_fname = null_string;
450+static rsync_xal backup_xal;
451+
452+/* ------------------------------------------------------------------------- */
453+
454+static void rsync_xal_free(rsync_xal *x)
455+{
456+ size_t i;
457+
458+ for (i = 0; i < x->count; i++) {
459+ free(x->rxas[i].name);
460+ /* free(x->rxas[i].value); */
461+ }
462+ x->count = 0;
463+}
464+
465+static int rsync_xal_compare_names(const void *x1, const void *x2)
466+{
467+ const rsync_xa *xa1;
468+ const rsync_xa *xa2;
469+
470+ xa1 = x1;
471+ xa2 = x2;
472+ return strcmp(xa1->name, xa2->name);
473+}
474+
475+static BOOL rsync_xal_get(const char *fname, rsync_xal *x)
476+{
477+ ssize_t name_size;
478+ ssize_t datum_size;
479+ ssize_t left;
480+ char *name;
481+ size_t len;
482+ char *ptr;
483+
484+ if (!namebuf) {
485+ namebuf_len = 100;
486+ namebuf = new_array(char, namebuf_len);
487+ datumbuf_len = 100;
488+ datumbuf = new_array(char, datumbuf_len);
489+ if (!namebuf || !datumbuf)
490+ out_of_memory("rsync_xal_get");
491+ }
492+
493+ name_size = sys_llistxattr(fname, namebuf, namebuf_len);
494+ if (name_size > (ssize_t)namebuf_len) {
495+ name_size = -1;
496+ errno = ERANGE;
497+ }
498+ if (name_size < 0) {
499+ if (errno == ENOTSUP)
500+ return False;
501+ if (errno == ERANGE) {
502+ name_size = sys_llistxattr(fname, NULL, 0);
503+ if (name_size < 0) {
504+ rprintf(FERROR, "%s: rsync_xal_get: llistxattr: %s\n",
505+ fname, strerror(errno));
506+ return False;
507+ }
508+ namebuf = realloc_array(namebuf, char, name_size + 1);
509+ if (!namebuf)
510+ out_of_memory("rsync_xal_get");
511+ namebuf_len = name_size;
512+ name_size = sys_llistxattr(fname, namebuf, namebuf_len);
513+ if (name_size < 0) {
514+ rprintf(FERROR,
515+ "%s: rsync_xal_get: re-llistxattr failed: %s\n",
516+ fname, strerror(errno));
517+ return False;
518+ }
519+ } else {
520+ rprintf(FERROR,
521+ "%s: rsync_xal_get: llistxattr failed: %s\n",
522+ fname, strerror(errno));
523+ return False;
524+ }
525+ }
526+ rsync_xal_free(x);
527+ if (name_size == 0)
528+ return True;
529+ for (left = name_size, name = namebuf; left > 0 ; left -= len, name += len) {
530+ len = strlen(name) + 1;
531+
532+ if (x->count >= x->alloc) {
533+ size_t new_alloc;
534+ rsync_xa *new_rxas;
535+
536+ new_alloc = x->alloc < RSYNC_XAL_INITIAL ? RSYNC_XAL_INITIAL : x->alloc * 2;
537+ new_rxas = realloc_array(x->rxas, rsync_xa, new_alloc);
538+ if (!new_rxas)
539+ out_of_memory("rsync_xal_get");
540+ x->alloc = new_alloc;
541+ x->rxas = new_rxas;
542+ }
543+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
544+ if (datum_size > (ssize_t)datumbuf_len) {
545+ datum_size = -1;
546+ errno = ERANGE;
547+ }
548+ if (datum_size < 0) {
549+ if (errno == ENOTSUP)
550+ return False;
551+ if (errno == ERANGE) {
552+ datum_size = sys_lgetxattr(fname, name, NULL, 0);
553+ if (datum_size < 0) {
554+ rprintf(FERROR,
555+ "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
556+ fname, name, strerror(errno));
557+ return False;
558+ }
559+ datumbuf = realloc_array(datumbuf, char, datum_size + 1);
560+ if (!datumbuf)
561+ out_of_memory("rsync_xal_get");
562+ datumbuf_len = datum_size;
563+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
564+ if (datum_size < 0) {
565+ rprintf(FERROR,
566+ "%s: rsync_xal_get: re-lgetxattr of %s failed: %s\n",
567+ name, fname, strerror(errno));
568+ return False;
569+ }
570+ } else {
571+ rprintf(FERROR,
572+ "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
573+ fname, name, strerror(errno));
574+ return False;
575+ }
576+ }
577+ ptr = new_array(char, len + datum_size);
578+ if (!ptr)
579+ out_of_memory("rsync_xal_get");
580+ strcpy(ptr, name);
581+ if (datum_size)
582+ memcpy(ptr + len, datumbuf, datum_size);
583+ x->rxas[curr_rsync_xal.count].name_len = len;
584+ x->rxas[curr_rsync_xal.count].name = ptr;
585+ x->rxas[curr_rsync_xal.count].datum_len = datum_size;
586+ x->rxas[curr_rsync_xal.count].datum = ptr + len;
587+ x->count++;
588+ }
589+ if (x->count > 1) {
590+ qsort(x->rxas, x->count, sizeof (rsync_xa), rsync_xal_compare_names);
591+ }
592+ return True;
593+}
594+
595+
596+/* generate the xattr(s) for this flist entry;
597+ * xattr(s) are either sent or cleaned-up by send_xattr() below */
598+
599+BOOL make_xattr(const struct file_struct *file, const char *fname)
600+{
a8801c39 601+ if (!preserve_xattrs || !file)
bbdff76a
WD
602+ return True;
603+
604+ rsync_xal_get(fname, &curr_rsync_xal);
605+ return True;
606+}
607+
608+static ssize_t rsync_xal_find_matching(void)
609+{
610+ size_t i;
611+ size_t j;
612+
613+ for (i = 0; i < rsync_xal_l.count; i++) {
614+ /* Wrong number of elements? */
615+ if (rsync_xal_l.rxals[i].count != curr_rsync_xal.count)
616+ continue;
617+ /* any elements different? */
618+ for (j = 0; j < curr_rsync_xal.count; j++) {
619+ if (rsync_xal_l.rxals[i].rxas[j].name_len != curr_rsync_xal.rxas[j].name_len
620+ || rsync_xal_l.rxals[i].rxas[j].datum_len != curr_rsync_xal.rxas[j].datum_len
621+ || strcmp(rsync_xal_l.rxals[i].rxas[j].name, curr_rsync_xal.rxas[j].name)
622+ || memcmp(rsync_xal_l.rxals[i].rxas[j].datum, curr_rsync_xal.rxas[j].datum, curr_rsync_xal.rxas[j].datum_len))
623+ break;
624+ }
625+ /* no differences found. This is The One! */
626+ if (j == curr_rsync_xal.count)
627+ break;
628+ }
629+ if (i < rsync_xal_l.count)
630+ return i;
631+ return (ssize_t)-1;
632+}
633+
634+/* Store curr_rsync_xal on the end of rsync_xal_l */
635+static void rsync_xal_store(void)
636+{
637+ if (rsync_xal_l.count <= rsync_xal_l.alloc) {
638+ size_t new_alloc;
639+ void *new_xal;
640+
641+ new_alloc = rsync_xal_l.count < RSYNC_XAL_LIST_INITIAL ? RSYNC_XAL_LIST_INITIAL : rsync_xal_l.count * 2;
642+ new_xal = realloc_array(rsync_xal_l.rxals, rsync_xal, new_alloc);
643+ if (!new_xal)
644+ out_of_memory("rsync_xal_store");
645+ rsync_xal_l.alloc = new_alloc;
646+ rsync_xal_l.rxals = new_xal;
647+ }
648+ rsync_xal_l.rxals[rsync_xal_l.count] = curr_rsync_xal;
649+ rsync_xal_l.count++;
650+ curr_rsync_xal.count = 0;
651+ curr_rsync_xal.alloc = 0;
652+}
653+
654+/* send the make_xattr()-generated xattr list for this flist entry,
655+ * or clean up after an flist entry that's not being sent (f == -1) */
656+
657+void send_xattr(const struct file_struct *file, int f)
658+{
659+ ssize_t index;
660+
a8801c39 661+ if (!preserve_xattrs || !file)
bbdff76a
WD
662+ return;
663+
664+ if (f == -1) {
665+ rsync_xal_free(&curr_rsync_xal);
666+ return;
667+ }
668+ index = rsync_xal_find_matching();
669+ if (index != -1) {
670+ write_byte(f, 'x');
671+ write_int(f, index);
672+ rsync_xal_free(&curr_rsync_xal);
673+ } else {
674+ rsync_xa *rxa;
675+ size_t count;
676+
677+ count = curr_rsync_xal.count;
678+ write_byte(f, 'X');
679+ write_int(f, count);
680+ for (rxa = curr_rsync_xal.rxas; count--; rxa++) {
681+ write_int(f, rxa->name_len);
682+ write_int(f, rxa->datum_len);
683+ write_buf(f, rxa->name, rxa->name_len);
684+ write_buf(f, rxa->datum, rxa->datum_len);
685+ }
686+ rsync_xal_store();
687+ }
688+}
689+
690+
691+/* ------------------------------------------------------------------------- */
692+/* receive and build the rsync_xattr_lists */
693+
694+void receive_xattr(struct file_struct *file, int f)
695+{
696+ char *fname;
697+ int tag;
698+
699+ if (!preserve_xattrs)
700+ return;
701+ fname = f_name(file);
702+ tag = read_byte(f);
703+ if (tag != 'X' && tag != 'x') {
704+ rprintf(FERROR,
705+ "%s: receive_xattr: unknown extended attribute type tag: %c\n",
706+ fname, tag);
707+ exit_cleanup(RERR_STREAMIO);
708+ }
709+
710+ if (fxil.alloc <= fxil.count) {
711+ void *new_ptr;
712+ size_t new_alloc;
713+
714+ if (fxil.count < RSYNC_XAL_LIST_INITIAL)
715+ new_alloc = fxil.alloc + RSYNC_XAL_LIST_INITIAL;
716+ else
717+ new_alloc = fxil.alloc * 2;
718+ new_ptr = realloc_array(fxil.filexalidxs, file_xal_index, new_alloc);
719+ if (!new_ptr)
720+ out_of_memory("receive_xattr");
721+ if (verbose >= 3) {
722+ rprintf(FINFO, "receive_xattr to %lu bytes, %s move\n",
723+ (unsigned long)(new_alloc * sizeof (file_xal_index)),
724+ fxil.filexalidxs == new_ptr ? "did not" : "did");
725+ }
726+
727+ fxil.filexalidxs = new_ptr;
728+ fxil.alloc = new_alloc;
729+ }
730+
731+ fxil.filexalidxs[fxil.count].file = file;
732+ if (tag == 'X') {
733+ size_t count;
734+ size_t i;
735+
736+ fxil.filexalidxs[fxil.count].xalidx = rsync_xal_l.count;
737+
738+ count = read_int(f);
739+ curr_rsync_xal.count = count;
740+ curr_rsync_xal.alloc = count;
741+ curr_rsync_xal.rxas = new_array(rsync_xa, count);
742+ if (!curr_rsync_xal.rxas)
743+ out_of_memory("receive_xattr");
744+ for (i = 0; i < count; i++) {
745+ size_t name_len;
746+ size_t datum_len;
747+ char *ptr;
748+
749+ name_len = read_int(f);
750+ datum_len = read_int(f);
751+ ptr = new_array(char, name_len + datum_len);
752+ if (!ptr)
753+ out_of_memory("receive_xattr");
754+ read_buf(f, ptr, name_len);
755+ read_buf(f, ptr + name_len, datum_len);
756+ curr_rsync_xal.rxas[i].name_len = name_len;
757+ curr_rsync_xal.rxas[i].datum_len = datum_len;
758+ curr_rsync_xal.rxas[i].name = ptr;
759+ curr_rsync_xal.rxas[i].datum = ptr + name_len;
760+ }
761+ rsync_xal_store();
762+ } else {
763+ size_t index;
764+
765+ index = read_int(f);
766+ if (index >= rsync_xal_l.count) {
767+ rprintf(FERROR, "%s: receive_xattr: xa index %lu out of range\n",
768+fname, (unsigned long)index);
769+ exit_cleanup(RERR_STREAMIO);
770+ }
771+ fxil.filexalidxs[fxil.count].xalidx = index;
772+ }
773+ fxil.count++;
774+}
775+
776+static BOOL rsync_xal_set(const char *fname, rsync_xal *x)
777+{
778+ size_t i;
779+ int status;
780+ BOOL ret;
781+
782+ ret = True;
783+ for (i = 0; i < x->count; i++) {
784+ status = sys_lsetxattr(fname, x->rxas[i].name, x->rxas[i].datum, x->rxas[i].datum_len, 0);
785+ if (status < 0) {
786+ rprintf(FERROR, "%s: rsync_xal_set: lsetxattr %s failed: %s\n",
787+ fname, x->rxas[i].name, strerror(errno));
788+ ret = False;
789+ }
790+ }
791+ return ret;
792+}
793+
794+/* for duplicating xattrs on backups when using backup_dir */
795+
796+int dup_xattr(const char *orig, const char *bak)
797+{
798+ int ret;
799+
800+ ret = 0;
801+ if (!preserve_xattrs)
802+ return ret;
803+
804+ ret = rsync_xal_get(orig, &backup_xal);
805+ if (ret == True)
806+ ret = rsync_xal_set(bak, &backup_xal);
807+ rsync_xal_free(&backup_xal);
808+ return ret;
809+}
810+
811+void push_keep_backup_xattr(const struct file_struct *file, const char *orig, const char *dest)
812+{
813+ if (!preserve_xattrs)
814+ return;
815+
816+ backup_orig_file = file;
817+ backup_orig_fname = orig;
818+ backup_dest_fname = dest;
819+ rsync_xal_get(orig, &backup_xal);
820+}
821+
822+static int set_keep_backup_xal(void)
823+{
824+ if (!preserve_xattrs)
825+ return 0;
826+ return rsync_xal_set(backup_dest_fname, &backup_xal);
827+}
828+
829+void cleanup_keep_backup_xattr(void)
830+{
831+ if (!preserve_xattrs)
832+ return;
833+
834+ backup_orig_file = NULL;
835+ backup_orig_fname = null_string;
836+ backup_dest_fname = null_string;
837+ rsync_xal_free(&backup_xal);
838+}
839+
840+static int file_xal_index_compare(const void *x1, const void *x2)
841+{
842+ const file_xal_index *xa1;
843+ const file_xal_index *xa2;
844+
845+ xa1 = x1;
846+ xa2 = x2;
847+ return xa1->file == xa2->file ? 0 : xa1->file < xa2->file ? -1 : 1;
848+}
849+
850+void sort_file_xattr_index_lists(void)
851+{
852+ if (!preserve_xattrs)
853+ return;
854+ qsort(fxil.filexalidxs, fxil.count, sizeof (file_xal_index), file_xal_index_compare);
855+}
856+
857+static int find_file_xal_index(const struct file_struct *file)
858+{
859+ int low = 0, high = fxil.count;
860+ const struct file_struct *file_mid;
861+
862+ if (!high--) {
863+ rprintf(FERROR, "find_file_xal_index: no entries\n");
864+ exit_cleanup(RERR_STREAMIO);
865+ return -1;
866+ }
867+ do {
868+ int mid = (high + low) / 2;
869+ file_mid = fxil.filexalidxs[mid].file;
870+ if (file_mid == file)
871+ return fxil.filexalidxs[mid].xalidx;
872+ if (file_mid > file)
873+ high = mid - 1;
874+ else
875+ low = mid + 1;
876+ } while (low < high);
877+ if (low == high) {
878+ file_mid = fxil.filexalidxs[low].file;
879+ if (file_mid == file)
880+ return fxil.filexalidxs[low].xalidx;
881+ }
882+ rprintf(FERROR,
883+ "find_file_xal_index: can't find entry for file in list\n");
884+ exit_cleanup(RERR_STREAMIO);
885+ return -1;
886+}
887+
888+
889+/* set extended attributes on rsync-ed or keep_backup-ed file */
890+
891+int set_xattr(const char *fname, const struct file_struct *file)
892+{
893+ int updated;
894+ int xalidx;
895+ rsync_xal *x;
896+
897+ updated = 0;
898+ if (dry_run || !preserve_xattrs)
899+ return 0;
900+ if (file == backup_orig_file) {
901+ if (!strcmp(fname, backup_dest_fname))
902+ return set_keep_backup_xal();
903+ }
904+ xalidx = find_file_xal_index(file);
905+ x = &(rsync_xal_l.rxals[xalidx]);
906+ updated = rsync_xal_set(fname, x);
907+ return updated;
908+}
909+
910+#endif /* SUPPORT_XATTRS */