1This patch adds a new option:  --fake-super, which tells rsync to copy in a
2fake super-user mode that stores various file attributes in an extended-
3attribute value instead of as real file-system attributes.  See the changes
4to the manpages for details.
5
6To use this patch, run these commands for a successful build:
7
8    patch -p1 <patches/acls.diff
9    patch -p1 <patches/xattrs.diff
10    patch -p1 <patches/fake-super.diff
11    ./prepare-source
12    ./configure --enable-xattr-support
13    make
14
15If you want ACL support too, use this configure command instead of the one
16above:
17
18    ./configure --enable-acl-support --enable-xattr-support
19
20--- old/backup.c
21+++ new/backup.c
22@@ -129,7 +129,7 @@ static int make_bak_dir(char *fullpath)
23 		if (p >= rel) {
24 			/* Try to transfer the directory settings of the
25 			 * actual dir that the files are coming from. */
26-			if (do_stat(rel, &sx.st) < 0) {
27+			if (x_stat(rel, &sx.st, NULL) < 0) {
28 				rsyserr(FERROR, errno,
29 					"make_bak_dir stat %s failed",
30 					full_fname(rel));
31@@ -200,7 +200,7 @@ static int keep_backup(char *fname)
32 	int ret_code;
33 
34 	/* return if no file to keep */
35-	if (do_lstat(fname, &sx.st) < 0)
36+	if (x_lstat(fname, &sx.st, NULL) < 0)
37 		return 1;
38 #ifdef SUPPORT_ACLS
39 	sx.acc_acl = sx.def_acl = NULL;
40--- old/clientserver.c
41+++ new/clientserver.c
42@@ -625,6 +625,11 @@ static int rsync_module(int f_in, int f_
43 	ret = parse_arguments(&argc, (const char ***) &argv, 0);
44 	quiet = 0; /* Don't let someone try to be tricky. */
45 
46+	if (lp_fake_super(i))
47+		am_root = -1;
48+	else if (am_root < 0) /* Treat --fake-super from client as --super. */
49+		am_root = 2;
50+
51 	if (filesfrom_fd == 0)
52 		filesfrom_fd = f_in;
53 
54--- old/flist.c
55+++ new/flist.c
56@@ -181,7 +181,7 @@ static int readlink_stat(const char *pat
57 	}
58 	return 0;
59 #else
60-	return do_stat(path, stp);
61+	return x_stat(path, stp, NULL);
62 #endif
63 }
64 
65@@ -189,17 +189,17 @@ int link_stat(const char *path, STRUCT_S
66 {
67 #ifdef SUPPORT_LINKS
68 	if (copy_links)
69-		return do_stat(path, stp);
70-	if (do_lstat(path, stp) < 0)
71+		return x_stat(path, stp, NULL);
72+	if (x_lstat(path, stp, NULL) < 0)
73 		return -1;
74 	if (follow_dirlinks && S_ISLNK(stp->st_mode)) {
75 		STRUCT_STAT st;
76-		if (do_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
77+		if (x_stat(path, &st, NULL) == 0 && S_ISDIR(st.st_mode))
78 			*stp = st;
79 	}
80 	return 0;
81 #else
82-	return do_stat(path, stp);
83+	return x_stat(path, stp, NULL);
84 #endif
85 }
86 
87@@ -234,26 +234,6 @@ static int is_excluded(char *fname, int 
88 	return 0;
89 }
90 
91-static int to_wire_mode(mode_t mode)
92-{
93-#ifdef SUPPORT_LINKS
94-#if _S_IFLNK != 0120000
95-	if (S_ISLNK(mode))
96-		return (mode & ~(_S_IFMT)) | 0120000;
97-#endif
98-#endif
99-	return mode;
100-}
101-
102-static mode_t from_wire_mode(int mode)
103-{
104-#if _S_IFLNK != 0120000
105-	if ((mode & (_S_IFMT)) == 0120000)
106-		return (mode & ~(_S_IFMT)) | _S_IFLNK;
107-#endif
108-	return mode;
109-}
110-
111 static void send_directory(int f, struct file_list *flist,
112 			   char *fbuf, int len);
113 
114@@ -793,7 +773,7 @@ struct file_struct *make_file(char *fnam
115 		if (save_errno == ENOENT) {
116 #ifdef SUPPORT_LINKS
117 			/* Avoid "vanished" error if symlink points nowhere. */
118-			if (copy_links && do_lstat(thisname, &st) == 0
119+			if (copy_links && x_lstat(thisname, &st, NULL) == 0
120 			    && S_ISLNK(st.st_mode)) {
121 				io_error |= IOERR_GENERAL;
122 				rprintf(FERROR, "symlink has no referent: %s\n",
123@@ -963,7 +943,7 @@ struct file_struct *make_file(char *fnam
124 		int save_mode = file->mode;
125 		file->mode = S_IFDIR; /* Find a directory with our name. */
126 		if (flist_find(the_file_list, file) >= 0
127-		    && do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) {
128+		    && x_stat(thisname, &st2, NULL) == 0 && S_ISDIR(st2.st_mode)) {
129 			file->modtime = st2.st_mtime;
130 			file->length = st2.st_size;
131 			file->mode = st2.st_mode;
132--- old/loadparm.c
133+++ new/loadparm.c
134@@ -150,6 +150,7 @@ typedef struct
135 	int syslog_facility;
136 	int timeout;
137 
138+	BOOL fake_super;
139 	BOOL ignore_errors;
140 	BOOL ignore_nonreadable;
141 	BOOL list;
142@@ -197,6 +198,7 @@ static service sDefault =
143  /* syslog_facility; */		LOG_DAEMON,
144  /* timeout; */			0,
145 
146+ /* fake_super; */		False,
147  /* ignore_errors; */		False,
148  /* ignore_nonreadable; */	False,
149  /* list; */			True,
150@@ -298,6 +300,7 @@ static struct parm_struct parm_table[] =
151  {"dont compress",     P_STRING, P_LOCAL, &sDefault.dont_compress,     NULL,0},
152  {"exclude from",      P_STRING, P_LOCAL, &sDefault.exclude_from,      NULL,0},
153  {"exclude",           P_STRING, P_LOCAL, &sDefault.exclude,           NULL,0},
154+ {"fake super",        P_BOOL,   P_LOCAL, &sDefault.fake_super,        NULL,0},
155  {"filter",            P_STRING, P_LOCAL, &sDefault.filter,            NULL,0},
156  {"gid",               P_STRING, P_LOCAL, &sDefault.gid,               NULL,0},
157  {"hosts allow",       P_STRING, P_LOCAL, &sDefault.hosts_allow,       NULL,0},
158@@ -412,6 +415,7 @@ FN_LOCAL_INTEGER(lp_max_connections, max
159 FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
160 FN_LOCAL_INTEGER(lp_timeout, timeout)
161 
162+FN_LOCAL_BOOL(lp_fake_super, fake_super)
163 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
164 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
165 FN_LOCAL_BOOL(lp_list, list)
166@@ -816,7 +820,7 @@ BOOL lp_load(char *pszFname, int globals
167 
168 	if (pszFname)
169 	    pstrcpy(n2,pszFname);
170-	else if (am_server && !am_root)
171+	else if (am_server && am_root <= 0)
172 	    pstrcpy(n2,RSYNCD_USERCONF);
173 	else
174 	    pstrcpy(n2,RSYNCD_SYSCONF);
175--- old/options.c
176+++ new/options.c
177@@ -73,7 +73,7 @@ int protocol_version = PROTOCOL_VERSION;
178 int sparse_files = 0;
179 int do_compression = 0;
180 int def_compress_level = Z_DEFAULT_COMPRESSION;
181-int am_root = 0;
182+int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */
183 int am_server = 0;
184 int am_sender = 0;
185 int am_generator = 0;
186@@ -329,6 +329,9 @@ void usage(enum logcode F)
187   rprintf(F," -t, --times                 preserve times\n");
188   rprintf(F," -O, --omit-dir-times        omit directories when preserving times\n");
189   rprintf(F,"     --super                 receiver attempts super-user activities\n");
190+#ifdef SUPPORT_XATTRS
191+  rprintf(F,"     --fake-super            store/recover privileged attrs using xattrs\n");
192+#endif
193   rprintf(F," -S, --sparse                handle sparse files efficiently\n");
194   rprintf(F," -n, --dry-run               show what would have been transferred\n");
195   rprintf(F," -W, --whole-file            copy files whole (without rsync algorithm)\n");
196@@ -453,6 +456,7 @@ static struct poptOption long_options[] 
197   {"modify-window",    0,  POPT_ARG_INT,    &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
198   {"super",            0,  POPT_ARG_VAL,    &am_root, 2, 0, 0 },
199   {"no-super",         0,  POPT_ARG_VAL,    &am_root, 0, 0, 0 },
200+  {"fake-super",       0,  POPT_ARG_VAL,    &am_root, -1, 0, 0 },
201   {"owner",           'o', POPT_ARG_VAL,    &preserve_uid, 1, 0, 0 },
202   {"no-owner",         0,  POPT_ARG_VAL,    &preserve_uid, 0, 0, 0 },
203   {"no-o",             0,  POPT_ARG_VAL,    &preserve_uid, 0, 0, 0 },
204@@ -1178,6 +1182,14 @@ int parse_arguments(int *argc, const cha
205 	}
206 #endif
207 
208+#ifndef SUPPORT_XATTRS
209+	if (am_root < 0) {
210+		snprintf(err_buf, sizeof err_buf,
211+			 "--fake-super requires an rsync with extended attributes enabled\n");
212+		return 0;
213+	}
214+#endif
215+
216 	if (write_batch && read_batch) {
217 		snprintf(err_buf, sizeof err_buf,
218 			"--write-batch and --read-batch can not be used together\n");
219--- old/rsync.c
220+++ new/rsync.c
221@@ -196,7 +196,9 @@ int set_file_attrs(char *fname, struct f
222 					(long)sxp->st.st_gid, (long)file->gid);
223 			}
224 		}
225-		if (do_lchown(fname,
226+		if (am_root < 0) {
227+			;
228+		} else if (do_lchown(fname,
229 		    change_uid ? file->uid : sxp->st.st_uid,
230 		    change_gid ? file->gid : sxp->st.st_gid) != 0) {
231 			/* shouldn't have attempted to change uid or gid
232@@ -205,7 +207,7 @@ int set_file_attrs(char *fname, struct f
233 			    change_uid ? "chown" : "chgrp",
234 			    full_fname(fname));
235 			goto cleanup;
236-		}
237+		} else
238 		/* a lchown had been done - we have to re-stat if the
239 		 * destination had the setuid or setgid bits set due
240 		 * to the side effect of the chown call */
241@@ -222,6 +224,8 @@ int set_file_attrs(char *fname, struct f
242 #ifdef SUPPORT_XATTRS
243 	if (preserve_xattrs && set_xattr(fname, file, sxp) == 0)
244 		updated = 1;
245+	if (am_root < 0)
246+		set_stat_xattr(fname, file);
247 #endif
248 #ifdef SUPPORT_ACLS
249 	/* It's OK to call set_acl() now, even for a dir, as the generator
250@@ -236,7 +240,7 @@ int set_file_attrs(char *fname, struct f
251 
252 #ifdef HAVE_CHMOD
253 	if ((sxp->st.st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
254-		int ret = do_chmod(fname, new_mode);
255+		int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
256 		if (ret < 0) {
257 			rsyserr(FERROR, errno,
258 				"failed to set permissions on %s",
259--- old/rsync.h
260+++ new/rsync.h
261@@ -707,6 +707,12 @@ typedef struct {
262 
263 #include "proto.h"
264 
265+#ifndef SUPPORT_XATTRS
266+#define x_stat(fn,fst,xst) do_stat(fn,fst)
267+#define x_lstat(fn,fst,xst) do_lstat(fn,fst)
268+#define x_fstat(fd,fst,xst) do_fstat(fd,fst)
269+#endif
270+
271 /* We have replacement versions of these if they're missing. */
272 #ifndef HAVE_ASPRINTF
273 int asprintf(char **ptr, const char *format, ...);
274@@ -924,3 +930,23 @@ int inet_pton(int af, const char *src, v
275 #ifdef MAINTAINER_MODE
276 const char *get_panic_action(void);
277 #endif
278+
279+static inline int to_wire_mode(mode_t mode)
280+{
281+#ifdef SUPPORT_LINKS
282+#if _S_IFLNK != 0120000
283+	if (S_ISLNK(mode))
284+		return (mode & ~(_S_IFMT)) | 0120000;
285+#endif
286+#endif
287+	return mode;
288+}
289+
290+static inline mode_t from_wire_mode(int mode)
291+{
292+#if _S_IFLNK != 0120000
293+	if ((mode & (_S_IFMT)) == 0120000)
294+		return (mode & ~(_S_IFMT)) | _S_IFLNK;
295+#endif
296+	return mode;
297+}
298--- old/rsync.yo
299+++ new/rsync.yo
300@@ -333,6 +333,7 @@ to the detailed description below for a 
301  -t, --times                 preserve times
302  -O, --omit-dir-times        omit directories when preserving times
303      --super                 receiver attempts super-user activities
304+     --fake-super            store/recover privileged attrs using xattrs
305  -S, --sparse                handle sparse files efficiently
306  -n, --dry-run               show what would have been transferred
307  -W, --whole-file            copy files whole (without rsync algorithm)
308@@ -846,7 +847,7 @@ permission value can be applied to the f
309 dit(bf(-o, --owner)) This option causes rsync to set the owner of the
310 destination file to be the same as the source file, but only if the
311 receiving rsync is being run as the super-user (see also the bf(--super)
312-option to force rsync to attempt super-user activities).
313+and bf(--fake-super) options).
314 Without this option, the owner is set to the invoking user on the
315 receiving side.
316 
317@@ -869,7 +870,7 @@ default, but may fall back to using the 
318 dit(bf(--devices)) This option causes rsync to transfer character and
319 block device files to the remote system to recreate these devices.
320 This option has no effect if the receiving rsync is not run as the
321-super-user and bf(--super) is not specified.
322+super-user (see also the bf(--super) and bf(--fake-super) options).
323 
324 dit(bf(--specials)) This option causes rsync to transfer special files
325 such as named sockets and fifos.
326@@ -899,6 +900,33 @@ also for ensuring that you will get erro
327 being running as the super-user.  To turn off super-user activities, the
328 super-user can use bf(--no-super).
329 
330+dit(bf(--fake-super)) When this option is enabled, rsync simulates
331+super-user activities by saving/restoring the privileged attributes via a
332+special extended attribute that is attached to each file (as needed).  This
333+includes the file's owner and group (if it is not the default), the file's
334+device info (device & special files are created as empty text files), and
335+any permission bits that we won't allow to be set on the real file (e.g.
336+the real file gets u-s,g-s,o-t for safety) or that would limit the owner's
337+access (since the real super-user can always access/change a file or
338+directory, the files we create can always be accessed/changed by the
339+creating user).
340+
341+The bf(--fake-super) option only affects the side where the option is used.
342+To affect the remote side of a remote-shell connection, specify an rsync
343+path:
344+
345+quote(tt(  rsync -av --rsync-path="rsync --fake-super" /src/ host:/dest/))
346+
347+Since there is only one "side" in a local copy, this option affects both
348+the sending and recieving of files.  You'll need to specify a copy using
349+"localhost" if you need to avoid this.  Note, however, that it is always
350+safe to copy from some non-fake-super files into some fake-super files
351+using a local bf(--fake-super) command because the non-fake source files
352+will just have their normal attributes.
353+
354+See also the "fake super" setting in the daemon's rsyncd.conf file.
355+This option is overridden by both bf(--super) and bf(--no-super).
356+
357 dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take
358 up less space on the destination.  Conflicts with bf(--inplace) because it's
359 not possible to overwrite data in a sparse fashion.
360--- old/rsyncd.conf.yo
361+++ new/rsyncd.conf.yo
362@@ -226,6 +226,11 @@ file transfers to and from that module s
363 was run as root. This complements the "uid" option. The default is gid -2,
364 which is normally the group "nobody".
365 
366+dit(bf(fake super)) Setting "fake super = yes" for a module causes the
367+daemon side to behave as if the bf(--fake-user) command-line option had
368+been specified.  This allows the full attributes of a file to be stored
369+without having to have the daemon actually running as root.
370+
371 dit(bf(filter)) The "filter" option allows you to specify a space-separated
372 list of filter rules that the daemon will not allow to be read or written.
373 This is only superficially equivalent to the client specifying these
374--- old/syscall.c
375+++ new/syscall.c
376@@ -28,6 +28,7 @@
377 #endif
378 
379 extern int dry_run;
380+extern int am_root;
381 extern int read_only;
382 extern int list_only;
383 extern int preserve_perms;
384@@ -79,6 +80,15 @@ int do_mknod(char *pathname, mode_t mode
385 {
386 	if (dry_run) return 0;
387 	RETURN_ERROR_IF_RO_OR_LO;
388+
389+	/* For --fake-super, we create a normal file with mode 0600. */
390+	if (am_root < 0) {
391+		int fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
392+		if (fd < 0 || close(fd) < 0)
393+			return -1;
394+		return 0;
395+	}
396+
397 #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
398 	if (S_ISFIFO(mode))
399 		return mkfifo(pathname, mode);
400--- old/t_unsafe.c
401+++ new/t_unsafe.c
402@@ -24,7 +24,11 @@
403 
404 #include "rsync.h"
405 
406-int dry_run, read_only, list_only, verbose;
407+int dry_run = 0;
408+int am_root = 0;
409+int read_only = 0;
410+int list_only = 0;
411+int verbose = 0;
412 int preserve_perms = 0;
413 
414 int
415--- old/tls.c
416+++ new/tls.c
417@@ -39,6 +39,7 @@
418 
419 /* These are to make syscall.o shut up. */
420 int dry_run = 0;
421+int am_root = 0;
422 int read_only = 1;
423 int list_only = 0;
424 int preserve_perms = 0;
425--- old/trimslash.c
426+++ new/trimslash.c
427@@ -23,6 +23,7 @@
428 
429 /* These are to make syscall.o shut up. */
430 int dry_run = 0;
431+int am_root = 0;
432 int read_only = 1;
433 int list_only = 0;
434 int preserve_perms = 0;
435--- old/xattr.c
436+++ new/xattr.c
437@@ -43,11 +43,16 @@ extern unsigned int file_struct_len;
438 #define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1)
439 
440 #ifdef HAVE_LINUX_XATTRS
441-#define RPRE_LEN 0
442+#define MIGHT_NEED_RPRE (am_root < 0)
443+#define RSYNC_PREFIX USER_PREFIX "rsync."
444 #else
445+#define MIGHT_NEED_RPRE am_root
446 #define RSYNC_PREFIX "rsync."
447-#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
448 #endif
449+#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
450+
451+#define XSTAT_ATTR RSYNC_PREFIX "%stat"
452+#define XSTAT_LEN ((int)sizeof XSTAT_ATTR - 1)
453 
454 typedef struct {
455 	char *datum, *name;
456@@ -148,6 +153,10 @@ static int rsync_xal_get(const char *fna
457 			continue;
458 #endif
459 
460+		if (am_root < 0 && name_len == XSTAT_LEN + 1
461+		 && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
462+			continue;
463+
464 		datum_len = sys_lgetxattr(fname, name, NULL, 0);
465 		if (datum_len < 0) {
466 			if (errno == ENOTSUP)
467@@ -177,6 +186,13 @@ static int rsync_xal_get(const char *fna
468 				return -1;
469 			}
470 		}
471+#ifdef HAVE_LINUX_XATTRS
472+		if (am_root < 0 && name_len > RPRE_LEN
473+		 && HAS_PREFIX(name, RSYNC_PREFIX)) {
474+			name += RPRE_LEN;
475+			name_len -= RPRE_LEN;
476+		}
477+#endif
478 		rxas = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
479 		rxas->name = ptr + datum_len;
480 		rxas->datum = ptr;
481@@ -298,13 +314,9 @@ void receive_xattr(struct file_struct *f
482 			rsync_xa *rxa;
483 			size_t name_len = read_int(f);
484 			size_t datum_len = read_int(f);
485-#ifdef HAVE_LINUX_XATTRS
486-			size_t extra_len = 0;
487-#else
488-			size_t extra_len = am_root ? RPRE_LEN : 0;
489+			size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
490 			if (datum_len + extra_len < datum_len)
491 				out_of_memory("receive_xattr"); /* overflow */
492-#endif
493 			if (name_len + datum_len + extra_len < name_len)
494 				out_of_memory("receive_xattr"); /* overflow */
495 			ptr = new_array(char, name_len + datum_len + extra_len);
496@@ -315,9 +327,14 @@ void receive_xattr(struct file_struct *f
497 			read_buf(f, ptr, datum_len);
498 #ifdef HAVE_LINUX_XATTRS
499 			/* Non-root can only save the user namespace. */
500-			if (!am_root && !HAS_PREFIX(name, USER_PREFIX)) {
501-				free(ptr);
502-				continue;
503+			if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
504+				if (!am_root) {
505+					free(ptr);
506+					continue;
507+				}
508+				name -= RPRE_LEN;
509+				name_len += RPRE_LEN;
510+				memcpy(name, RSYNC_PREFIX, RPRE_LEN);
511 			}
512 #else
513 			/* This OS only has a user namespace, so we either
514@@ -335,6 +352,12 @@ void receive_xattr(struct file_struct *f
515 				continue;
516 			}
517 #endif
518+			if (am_root < 0 && name_len == XSTAT_LEN + 1
519+			 && name[RPRE_LEN] == '%'
520+			 && strcmp(name, XSTAT_ATTR) == 0) {
521+				free(ptr);
522+				continue;
523+			}
524 			rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
525 			rxa->name = name;
526 			rxa->datum = ptr;
527@@ -414,4 +437,149 @@ int set_xattr(const char *fname, const s
528 	return rsync_xal_set(fname, lst + ndx); /* TODO:  This needs to return 1 if no xattrs changed! */
529 }
530 
531+int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
532+{
533+	int mode, rdev_major, rdev_minor, uid, gid, len;
534+	char buf[256];
535+
536+	if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
537+		return -1;
538+
539+	if (xst)
540+		*xst = *fst;
541+	else
542+		xst = fst;
543+	if (fname) {
544+		fd = -1;
545+		len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
546+	} else {
547+		fname = "fd";
548+		len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
549+	}
550+	if (len >= (int)sizeof buf) {
551+		len = -1;
552+		errno = ERANGE;
553+	}
554+	if (len < 0) {
555+		if (errno == ENOTSUP || errno == ENOATTR)
556+			return -1;
557+		if (errno == EPERM && S_ISLNK(fst->st_mode)) {
558+			xst->st_uid = 0;
559+			xst->st_gid = 0;
560+			return 0;
561+		}
562+		rsyserr(FERROR, errno, "failed to read xattr %s for %s",
563+			XSTAT_ATTR, full_fname(fname));
564+		return -1;
565+	}
566+	buf[len] = '\0';
567+
568+	if (sscanf(buf, "%o %d,%d %d:%d",
569+		   &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
570+		rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
571+			XSTAT_ATTR, full_fname(fname), buf);
572+		exit_cleanup(RERR_FILEIO);
573+	}
574+
575+	xst->st_mode = from_wire_mode(mode);
576+	xst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
577+	xst->st_uid = uid;
578+	xst->st_gid = gid;
579+
580+	return 0;
581+}
582+
583+int set_stat_xattr(const char *fname, struct file_struct *file)
584+{
585+	STRUCT_STAT fst, xst;
586+	dev_t rdev;
587+	mode_t mode, fmode;
588+
589+	if (dry_run)
590+		return 0;
591+
592+	if (read_only || list_only) {
593+		rsyserr(FERROR, EROFS, "failed to write xattr %s for %s",
594+			XSTAT_ATTR, full_fname(fname));
595+		return -1;
596+	}
597+
598+	if (x_lstat(fname, &fst, &xst) < 0) {
599+		rsyserr(FERROR, errno, "failed to re-stat %s",
600+			full_fname(fname));
601+		return -1;
602+	}
603+
604+	fst.st_mode &= (_S_IFMT | CHMOD_BITS);
605+	fmode = file->mode & (_S_IFMT | CHMOD_BITS);
606+
607+	if (IS_DEVICE(fmode) || IS_SPECIAL(fmode))
608+		rdev = file->u.rdev;
609+	else
610+		rdev = 0;
611+
612+	/* Dump the special permissions and enable full owner access. */
613+	mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
614+	     | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
615+	if (fst.st_mode != mode)
616+		do_chmod(fname, mode);
617+	if (!IS_DEVICE(fst.st_mode) && !IS_SPECIAL(fst.st_mode))
618+		fst.st_rdev = 0; /* just in case */
619+
620+	if (mode == fmode && fst.st_rdev == rdev
621+	 && fst.st_uid == file->uid && fst.st_gid == file->gid) {
622+		/* xst.st_mode will be 0 if there's no current stat xattr */
623+		if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
624+			rsyserr(FERROR, errno,
625+				"delete of stat xattr failed for %s",
626+				full_fname(fname));
627+			return -1;
628+		}
629+		return 0;
630+	}
631+
632+	if (xst.st_mode != fmode || xst.st_rdev != rdev
633+	 || xst.st_uid != file->uid || xst.st_gid != file->gid) {
634+		char buf[256];
635+		int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
636+			to_wire_mode(fmode),
637+			(int)major(rdev), (int)minor(rdev),
638+			(int)file->uid, (int)file->gid);
639+		if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
640+			if (errno == EPERM && S_ISLNK(fst.st_mode))
641+				return 0;
642+			rsyserr(FERROR, errno,
643+				"failed to write xattr %s for %s",
644+				XSTAT_ATTR, full_fname(fname));
645+			return -1;
646+		}
647+	}
648+
649+	return 0;
650+}
651+
652+int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
653+{
654+	int ret = do_stat(fname, fst);
655+	if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
656+		xst->st_mode = 0;
657+	return ret;
658+}
659+
660+int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
661+{
662+	int ret = do_lstat(fname, fst);
663+	if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
664+		xst->st_mode = 0;
665+	return ret;
666+}
667+
668+int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
669+{
670+	int ret = do_fstat(fd, fst);
671+	if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst)
672+		xst->st_mode = 0;
673+	return ret;
674+}
675+
676 #endif /* SUPPORT_XATTRS */
677--- old/proto.h
678+++ new/proto.h
679@@ -182,6 +182,7 @@ char *lp_uid(int );
680 int lp_max_connections(int );
681 int lp_max_verbosity(int );
682 int lp_timeout(int );
683+BOOL lp_fake_super(int );
684 BOOL lp_ignore_errors(int );
685 BOOL lp_ignore_nonreadable(int );
686 BOOL lp_list(int );
687@@ -332,4 +333,15 @@ int bitbag_check_bit(struct bitbag *bb, 
688 int bitbag_next_bit(struct bitbag *bb, int after);
689 void *expand_item_list(item_list *lp, size_t item_size,
690 		       const char *desc, int incr);
691+void free_xattr(statx *sxp);
692+int get_xattr(const char *fname, statx *sxp);
693+void send_xattr(statx *sxp, int f);
694+void receive_xattr(struct file_struct *file, int f);
695+void cache_xattr(struct file_struct *file, statx *sxp);
696+int set_xattr(const char *fname, const struct file_struct *file, UNUSED(statx *sxp));
697+int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst);
698+int set_stat_xattr(const char *fname, struct file_struct *file);
699+int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst);
700+int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst);
701+int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst);
702 int sys_gettimeofday(struct timeval *tv);
703--- old/configure
704+++ new/configure
705@@ -1259,6 +1259,7 @@ Optional Features:
706   --disable-ipv6          don't even try to use IPv6
707   --disable-locale        turn off locale features
708   --enable-acl-support    Include ACL support (default=no)
709+  --enable-xattr-support  Include extended attribute support (default=no)
710 
711 Optional Packages:
712   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
713@@ -15628,6 +15629,559 @@ echo "${ECHO_T}no" >&6; }
714 fi
715 
716 
717+
718+for ac_header in attr/xattr.h
719+do
720+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
721+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
722+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
723+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
724+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
725+  echo $ECHO_N "(cached) $ECHO_C" >&6
726+fi
727+ac_res=`eval echo '${'$as_ac_Header'}'`
728+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
729+echo "${ECHO_T}$ac_res" >&6; }
730+else
731+  # Is the header compilable?
732+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
733+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
734+cat >conftest.$ac_ext <<_ACEOF
735+/* confdefs.h.  */
736+_ACEOF
737+cat confdefs.h >>conftest.$ac_ext
738+cat >>conftest.$ac_ext <<_ACEOF
739+/* end confdefs.h.  */
740+$ac_includes_default
741+#include <$ac_header>
742+_ACEOF
743+rm -f conftest.$ac_objext
744+if { (ac_try="$ac_compile"
745+case "(($ac_try" in
746+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
747+  *) ac_try_echo=$ac_try;;
748+esac
749+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
750+  (eval "$ac_compile") 2>conftest.er1
751+  ac_status=$?
752+  grep -v '^ *+' conftest.er1 >conftest.err
753+  rm -f conftest.er1
754+  cat conftest.err >&5
755+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
756+  (exit $ac_status); } &&
757+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
758+  { (case "(($ac_try" in
759+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
760+  *) ac_try_echo=$ac_try;;
761+esac
762+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
763+  (eval "$ac_try") 2>&5
764+  ac_status=$?
765+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
766+  (exit $ac_status); }; } &&
767+	 { ac_try='test -s conftest.$ac_objext'
768+  { (case "(($ac_try" in
769+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
770+  *) ac_try_echo=$ac_try;;
771+esac
772+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
773+  (eval "$ac_try") 2>&5
774+  ac_status=$?
775+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
776+  (exit $ac_status); }; }; then
777+  ac_header_compiler=yes
778+else
779+  echo "$as_me: failed program was:" >&5
780+sed 's/^/| /' conftest.$ac_ext >&5
781+
782+	ac_header_compiler=no
783+fi
784+
785+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
786+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
787+echo "${ECHO_T}$ac_header_compiler" >&6; }
788+
789+# Is the header present?
790+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
791+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
792+cat >conftest.$ac_ext <<_ACEOF
793+/* confdefs.h.  */
794+_ACEOF
795+cat confdefs.h >>conftest.$ac_ext
796+cat >>conftest.$ac_ext <<_ACEOF
797+/* end confdefs.h.  */
798+#include <$ac_header>
799+_ACEOF
800+if { (ac_try="$ac_cpp conftest.$ac_ext"
801+case "(($ac_try" in
802+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
803+  *) ac_try_echo=$ac_try;;
804+esac
805+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
806+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
807+  ac_status=$?
808+  grep -v '^ *+' conftest.er1 >conftest.err
809+  rm -f conftest.er1
810+  cat conftest.err >&5
811+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
812+  (exit $ac_status); } >/dev/null; then
813+  if test -s conftest.err; then
814+    ac_cpp_err=$ac_c_preproc_warn_flag
815+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
816+  else
817+    ac_cpp_err=
818+  fi
819+else
820+  ac_cpp_err=yes
821+fi
822+if test -z "$ac_cpp_err"; then
823+  ac_header_preproc=yes
824+else
825+  echo "$as_me: failed program was:" >&5
826+sed 's/^/| /' conftest.$ac_ext >&5
827+
828+  ac_header_preproc=no
829+fi
830+
831+rm -f conftest.err conftest.$ac_ext
832+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
833+echo "${ECHO_T}$ac_header_preproc" >&6; }
834+
835+# So?  What about this header?
836+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
837+  yes:no: )
838+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
839+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
840+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
841+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
842+    ac_header_preproc=yes
843+    ;;
844+  no:yes:* )
845+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
846+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
847+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
848+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
849+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
850+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
851+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
852+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
853+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
854+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
855+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
856+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
857+
858+    ;;
859+esac
860+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
861+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
862+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
863+  echo $ECHO_N "(cached) $ECHO_C" >&6
864+else
865+  eval "$as_ac_Header=\$ac_header_preproc"
866+fi
867+ac_res=`eval echo '${'$as_ac_Header'}'`
868+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
869+echo "${ECHO_T}$ac_res" >&6; }
870+
871+fi
872+if test `eval echo '${'$as_ac_Header'}'` = yes; then
873+  cat >>confdefs.h <<_ACEOF
874+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
875+_ACEOF
876+
877+fi
878+
879+done
880+
881+
882+for ac_header in sys/xattr.h
883+do
884+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
885+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
886+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
887+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
888+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
889+  echo $ECHO_N "(cached) $ECHO_C" >&6
890+fi
891+ac_res=`eval echo '${'$as_ac_Header'}'`
892+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
893+echo "${ECHO_T}$ac_res" >&6; }
894+else
895+  # Is the header compilable?
896+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
897+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
898+cat >conftest.$ac_ext <<_ACEOF
899+/* confdefs.h.  */
900+_ACEOF
901+cat confdefs.h >>conftest.$ac_ext
902+cat >>conftest.$ac_ext <<_ACEOF
903+/* end confdefs.h.  */
904+$ac_includes_default
905+#include <$ac_header>
906+_ACEOF
907+rm -f conftest.$ac_objext
908+if { (ac_try="$ac_compile"
909+case "(($ac_try" in
910+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
911+  *) ac_try_echo=$ac_try;;
912+esac
913+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
914+  (eval "$ac_compile") 2>conftest.er1
915+  ac_status=$?
916+  grep -v '^ *+' conftest.er1 >conftest.err
917+  rm -f conftest.er1
918+  cat conftest.err >&5
919+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
920+  (exit $ac_status); } &&
921+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
922+  { (case "(($ac_try" in
923+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
924+  *) ac_try_echo=$ac_try;;
925+esac
926+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
927+  (eval "$ac_try") 2>&5
928+  ac_status=$?
929+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
930+  (exit $ac_status); }; } &&
931+	 { ac_try='test -s conftest.$ac_objext'
932+  { (case "(($ac_try" in
933+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
934+  *) ac_try_echo=$ac_try;;
935+esac
936+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
937+  (eval "$ac_try") 2>&5
938+  ac_status=$?
939+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
940+  (exit $ac_status); }; }; then
941+  ac_header_compiler=yes
942+else
943+  echo "$as_me: failed program was:" >&5
944+sed 's/^/| /' conftest.$ac_ext >&5
945+
946+	ac_header_compiler=no
947+fi
948+
949+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
950+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
951+echo "${ECHO_T}$ac_header_compiler" >&6; }
952+
953+# Is the header present?
954+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
955+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
956+cat >conftest.$ac_ext <<_ACEOF
957+/* confdefs.h.  */
958+_ACEOF
959+cat confdefs.h >>conftest.$ac_ext
960+cat >>conftest.$ac_ext <<_ACEOF
961+/* end confdefs.h.  */
962+#include <$ac_header>
963+_ACEOF
964+if { (ac_try="$ac_cpp conftest.$ac_ext"
965+case "(($ac_try" in
966+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
967+  *) ac_try_echo=$ac_try;;
968+esac
969+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
970+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
971+  ac_status=$?
972+  grep -v '^ *+' conftest.er1 >conftest.err
973+  rm -f conftest.er1
974+  cat conftest.err >&5
975+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
976+  (exit $ac_status); } >/dev/null; then
977+  if test -s conftest.err; then
978+    ac_cpp_err=$ac_c_preproc_warn_flag
979+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
980+  else
981+    ac_cpp_err=
982+  fi
983+else
984+  ac_cpp_err=yes
985+fi
986+if test -z "$ac_cpp_err"; then
987+  ac_header_preproc=yes
988+else
989+  echo "$as_me: failed program was:" >&5
990+sed 's/^/| /' conftest.$ac_ext >&5
991+
992+  ac_header_preproc=no
993+fi
994+
995+rm -f conftest.err conftest.$ac_ext
996+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
997+echo "${ECHO_T}$ac_header_preproc" >&6; }
998+
999+# So?  What about this header?
1000+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
1001+  yes:no: )
1002+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
1003+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
1004+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
1005+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
1006+    ac_header_preproc=yes
1007+    ;;
1008+  no:yes:* )
1009+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
1010+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
1011+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
1012+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
1013+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
1014+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
1015+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
1016+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
1017+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
1018+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
1019+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
1020+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
1021+
1022+    ;;
1023+esac
1024+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
1025+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
1026+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
1027+  echo $ECHO_N "(cached) $ECHO_C" >&6
1028+else
1029+  eval "$as_ac_Header=\$ac_header_preproc"
1030+fi
1031+ac_res=`eval echo '${'$as_ac_Header'}'`
1032+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
1033+echo "${ECHO_T}$ac_res" >&6; }
1034+
1035+fi
1036+if test `eval echo '${'$as_ac_Header'}'` = yes; then
1037+  cat >>confdefs.h <<_ACEOF
1038+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
1039+_ACEOF
1040+
1041+fi
1042+
1043+done
1044+
1045+
1046+for ac_header in sys/extattr.h
1047+do
1048+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
1049+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
1050+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
1051+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
1052+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
1053+  echo $ECHO_N "(cached) $ECHO_C" >&6
1054+fi
1055+ac_res=`eval echo '${'$as_ac_Header'}'`
1056+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
1057+echo "${ECHO_T}$ac_res" >&6; }
1058+else
1059+  # Is the header compilable?
1060+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
1061+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
1062+cat >conftest.$ac_ext <<_ACEOF
1063+/* confdefs.h.  */
1064+_ACEOF
1065+cat confdefs.h >>conftest.$ac_ext
1066+cat >>conftest.$ac_ext <<_ACEOF
1067+/* end confdefs.h.  */
1068+$ac_includes_default
1069+#include <$ac_header>
1070+_ACEOF
1071+rm -f conftest.$ac_objext
1072+if { (ac_try="$ac_compile"
1073+case "(($ac_try" in
1074+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
1075+  *) ac_try_echo=$ac_try;;
1076+esac
1077+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
1078+  (eval "$ac_compile") 2>conftest.er1
1079+  ac_status=$?
1080+  grep -v '^ *+' conftest.er1 >conftest.err
1081+  rm -f conftest.er1
1082+  cat conftest.err >&5
1083+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
1084+  (exit $ac_status); } &&
1085+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
1086+  { (case "(($ac_try" in
1087+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
1088+  *) ac_try_echo=$ac_try;;
1089+esac
1090+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
1091+  (eval "$ac_try") 2>&5
1092+  ac_status=$?
1093+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
1094+  (exit $ac_status); }; } &&
1095+	 { ac_try='test -s conftest.$ac_objext'
1096+  { (case "(($ac_try" in
1097+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
1098+  *) ac_try_echo=$ac_try;;
1099+esac
1100+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
1101+  (eval "$ac_try") 2>&5
1102+  ac_status=$?
1103+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
1104+  (exit $ac_status); }; }; then
1105+  ac_header_compiler=yes
1106+else
1107+  echo "$as_me: failed program was:" >&5
1108+sed 's/^/| /' conftest.$ac_ext >&5
1109+
1110+	ac_header_compiler=no
1111+fi
1112+
1113+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
1114+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
1115+echo "${ECHO_T}$ac_header_compiler" >&6; }
1116+
1117+# Is the header present?
1118+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
1119+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
1120+cat >conftest.$ac_ext <<_ACEOF
1121+/* confdefs.h.  */
1122+_ACEOF
1123+cat confdefs.h >>conftest.$ac_ext
1124+cat >>conftest.$ac_ext <<_ACEOF
1125+/* end confdefs.h.  */
1126+#include <$ac_header>
1127+_ACEOF
1128+if { (ac_try="$ac_cpp conftest.$ac_ext"
1129+case "(($ac_try" in
1130+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
1131+  *) ac_try_echo=$ac_try;;
1132+esac
1133+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
1134+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
1135+  ac_status=$?
1136+  grep -v '^ *+' conftest.er1 >conftest.err
1137+  rm -f conftest.er1
1138+  cat conftest.err >&5
1139+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
1140+  (exit $ac_status); } >/dev/null; then
1141+  if test -s conftest.err; then
1142+    ac_cpp_err=$ac_c_preproc_warn_flag
1143+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
1144+  else
1145+    ac_cpp_err=
1146+  fi
1147+else
1148+  ac_cpp_err=yes
1149+fi
1150+if test -z "$ac_cpp_err"; then
1151+  ac_header_preproc=yes
1152+else
1153+  echo "$as_me: failed program was:" >&5
1154+sed 's/^/| /' conftest.$ac_ext >&5
1155+
1156+  ac_header_preproc=no
1157+fi
1158+
1159+rm -f conftest.err conftest.$ac_ext
1160+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
1161+echo "${ECHO_T}$ac_header_preproc" >&6; }
1162+
1163+# So?  What about this header?
1164+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
1165+  yes:no: )
1166+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
1167+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
1168+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
1169+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
1170+    ac_header_preproc=yes
1171+    ;;
1172+  no:yes:* )
1173+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
1174+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
1175+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
1176+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
1177+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
1178+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
1179+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
1180+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
1181+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
1182+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
1183+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
1184+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
1185+
1186+    ;;
1187+esac
1188+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
1189+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
1190+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
1191+  echo $ECHO_N "(cached) $ECHO_C" >&6
1192+else
1193+  eval "$as_ac_Header=\$ac_header_preproc"
1194+fi
1195+ac_res=`eval echo '${'$as_ac_Header'}'`
1196+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
1197+echo "${ECHO_T}$ac_res" >&6; }
1198+
1199+fi
1200+if test `eval echo '${'$as_ac_Header'}'` = yes; then
1201+  cat >>confdefs.h <<_ACEOF
1202+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
1203+_ACEOF
1204+
1205+fi
1206+
1207+done
1208+
1209+{ echo "$as_me:$LINENO: checking whether to support extended attributes" >&5
1210+echo $ECHO_N "checking whether to support extended attributes... $ECHO_C" >&6; }
1211+# Check whether --enable-xattr-support was given.
1212+if test "${enable_xattr_support+set}" = set; then
1213+  enableval=$enable_xattr_support;  case "$enableval" in
1214+  yes)
1215+      case "$host_os" in
1216+      *linux*)
1217+            { echo "$as_me:$LINENO: result: Using Linux xattrs" >&5
1218+echo "${ECHO_T}Using Linux xattrs" >&6; }
1219+
1220+cat >>confdefs.h <<\_ACEOF
1221+#define HAVE_LINUX_XATTRS 1
1222+_ACEOF
1223+
1224+            ;;
1225+      darwin*)
1226+            { echo "$as_me:$LINENO: result: Using OS X xattrs" >&5
1227+echo "${ECHO_T}Using OS X xattrs" >&6; }
1228+
1229+cat >>confdefs.h <<\_ACEOF
1230+#define HAVE_OSX_XATTRS 1
1231+_ACEOF
1232+
1233+            ;;
1234+      freebsd*)
1235+            { echo "$as_me:$LINENO: result: Using FreeBSD extattrs" >&5
1236+echo "${ECHO_T}Using FreeBSD extattrs" >&6; }
1237+
1238+cat >>confdefs.h <<\_ACEOF
1239+#define HAVE_FREEBSD_XATTRS 1
1240+_ACEOF
1241+
1242+            ;;
1243+      *)
1244+            { echo "$as_me:$LINENO: result: Xattrs requested but not Linux or OS X.  Good luck..." >&5
1245+echo "${ECHO_T}Xattrs requested but not Linux or OS X.  Good luck..." >&6; }
1246+            ;;
1247+      esac
1248+      ;;
1249+  *)
1250+      { echo "$as_me:$LINENO: result: no" >&5
1251+echo "${ECHO_T}no" >&6; }
1252+
1253+cat >>confdefs.h <<\_ACEOF
1254+#define HAVE_NO_XATTRS 1
1255+_ACEOF
1256+
1257+  esac
1258+else
1259+  { echo "$as_me:$LINENO: result: no" >&5
1260+echo "${ECHO_T}no" >&6; }
1261+
1262+cat >>confdefs.h <<\_ACEOF
1263+#define HAVE_NO_XATTRS 1
1264+_ACEOF
1265+
1266+
1267+fi
1268+
1269+
1270 ac_config_files="$ac_config_files Makefile lib/dummy zlib/dummy popt/dummy shconfig"
1271 
1272 cat >confcache <<\_ACEOF
1273--- old/config.h.in
1274+++ new/config.h.in
1275@@ -55,6 +55,9 @@
1276 /* Define to 1 if you have the `asprintf' function. */
1277 #undef HAVE_ASPRINTF
1278 
1279+/* Define to 1 if you have the <attr/xattr.h> header file. */
1280+#undef HAVE_ATTR_XATTR_H
1281+
1282 /* Define to 1 if readdir() is broken */
1283 #undef HAVE_BROKEN_READDIR
1284 
1285@@ -92,6 +95,9 @@
1286 /* Define to 1 if you have the <float.h> header file. */
1287 #undef HAVE_FLOAT_H
1288 
1289+/* True if you have FreeBSD xattrs */
1290+#undef HAVE_FREEBSD_XATTRS
1291+
1292 /* Define to 1 if you have the `fstat' function. */
1293 #undef HAVE_FSTAT
1294 
1295@@ -194,6 +200,9 @@
1296 /* Define to 1 if you have the `link' function. */
1297 #undef HAVE_LINK
1298 
1299+/* True if you have Linux xattrs */
1300+#undef HAVE_LINUX_XATTRS
1301+
1302 /* Define to 1 if you have the `locale_charset' function. */
1303 #undef HAVE_LOCALE_CHARSET
1304 
1305@@ -253,9 +262,15 @@
1306 /* true if you don't have ACLs */
1307 #undef HAVE_NO_ACLS
1308 
1309+/* True if you don't have extended attributes */
1310+#undef HAVE_NO_XATTRS
1311+
1312 /* Define to 1 if you have the `open64' function. */
1313 #undef HAVE_OPEN64
1314 
1315+/* True if you have Mac OS X xattrs */
1316+#undef HAVE_OSX_XATTRS
1317+
1318 /* true if you have posix ACLs */
1319 #undef HAVE_POSIX_ACLS
1320 
1321@@ -365,6 +380,9 @@
1322    */
1323 #undef HAVE_SYS_DIR_H
1324 
1325+/* Define to 1 if you have the <sys/extattr.h> header file. */
1326+#undef HAVE_SYS_EXTATTR_H
1327+
1328 /* Define to 1 if you have the <sys/fcntl.h> header file. */
1329 #undef HAVE_SYS_FCNTL_H
1330 
1331@@ -408,6 +426,9 @@
1332 /* Define to 1 if you have the <sys/wait.h> header file. */
1333 #undef HAVE_SYS_WAIT_H
1334 
1335+/* Define to 1 if you have the <sys/xattr.h> header file. */
1336+#undef HAVE_SYS_XATTR_H
1337+
1338 /* Define to 1 if you have the `tcgetpgrp' function. */
1339 #undef HAVE_TCGETPGRP
1340 
1341--- old/rsync.1
1342+++ new/rsync.1
1343@@ -367,7 +367,7 @@ to the detailed description below for a 
1344  \-q, \-\-quiet                 suppress non-error messages
1345      \-\-no\-motd               suppress daemon-mode MOTD (see caveat)
1346  \-c, \-\-checksum              skip based on checksum, not mod-time & size
1347- \-a, \-\-archive               archive mode; same as \-rlptgoD (no \-H, \-A)
1348+ \-a, \-\-archive               archive mode; equals \-rlptgoD (no \-H,\-A,\-X)
1349      \-\-no\-OPTION             turn off an implied OPTION (e\&.g\&. \-\-no\-D)
1350  \-r, \-\-recursive             recurse into directories
1351  \-R, \-\-relative              use relative path names
1352@@ -390,6 +390,7 @@ to the detailed description below for a 
1353  \-E, \-\-executability         preserve executability
1354      \-\-chmod=CHMOD           affect file and/or directory permissions
1355  \-A, \-\-acls                  preserve ACLs (implies \-p) [non-standard]
1356+ \-X, \-\-xattrs                preserve extended attrs (implies \-p) [n\&.s\&.]
1357  \-o, \-\-owner                 preserve owner (super-user only)
1358  \-g, \-\-group                 preserve group
1359      \-\-devices               preserve device files (super-user only)
1360@@ -398,6 +399,7 @@ to the detailed description below for a 
1361  \-t, \-\-times                 preserve times
1362  \-O, \-\-omit\-dir\-times        omit directories when preserving times
1363      \-\-super                 receiver attempts super-user activities
1364+     \-\-fake\-super            store/recover privileged attrs using xattrs
1365  \-S, \-\-sparse                handle sparse files efficiently
1366  \-n, \-\-dry\-run               show what would have been transferred
1367  \-W, \-\-whole\-file            copy files whole (without rsync algorithm)
1368@@ -947,6 +949,12 @@ version makes it incompatible with sendi
1369 rsync unless you double the \fB\-\-acls\fP option (e\&.g\&. \fB\-AA\fP)\&.  This
1370 doubling is not needed when pulling files from an older rsync\&.
1371 .IP 
1372+.IP "\fB\-X, \-\-xattrs\fP"
1373+This option causes rsync to update the remote
1374+extended attributes to be the same as the local ones\&.  This will work
1375+only if the remote machine\&'s rsync supports this option also\&. This is
1376+a non-standard option\&.
1377+.IP 
1378 .IP "\fB\-\-chmod\fP"
1379 This option tells rsync to apply one or more
1380 comma-separated "chmod" strings to the permission of the files in the
1381@@ -974,7 +982,7 @@ permission value can be applied to the f
1382 This option causes rsync to set the owner of the
1383 destination file to be the same as the source file, but only if the
1384 receiving rsync is being run as the super-user (see also the \fB\-\-super\fP
1385-option to force rsync to attempt super-user activities)\&.
1386+and \fB\-\-fake\-super\fP options)\&.
1387 Without this option, the owner is set to the invoking user on the
1388 receiving side\&.
1389 .IP 
1390@@ -999,7 +1007,7 @@ default, but may fall back to using the 
1391 This option causes rsync to transfer character and
1392 block device files to the remote system to recreate these devices\&.
1393 This option has no effect if the receiving rsync is not run as the
1394-super-user and \fB\-\-super\fP is not specified\&.
1395+super-user (see also the \fB\-\-super\fP and \fB\-\-fake\-super\fP options)\&.
1396 .IP 
1397 .IP "\fB\-\-specials\fP"
1398 This option causes rsync to transfer special files
1399@@ -1034,6 +1042,37 @@ also for ensuring that you will get erro
1400 being running as the super-user\&.  To turn off super-user activities, the
1401 super-user can use \fB\-\-no\-super\fP\&.
1402 .IP 
1403+.IP "\fB\-\-fake\-super\fP"
1404+When this option is enabled, rsync simulates
1405+super-user activities by saving/restoring the privileged attributes via a
1406+special extended attribute that is attached to each file (as needed)\&.  This
1407+includes the file\&'s owner and group (if it is not the default), the file\&'s
1408+device info (device & special files are created as empty text files), and
1409+any permission bits that we won\&'t allow to be set on the real file (e\&.g\&.
1410+the real file gets u-s,g-s,o-t for safety) or that would limit the owner\&'s
1411+access (since the real super-user can always access/change a file or
1412+directory, the files we create can always be accessed/changed by the
1413+creating user)\&.
1414+.IP 
1415+The \fB\-\-fake\-super\fP option only affects the side where the option is used\&.
1416+To affect the remote side of a remote-shell connection, specify an rsync
1417+path:
1418+.IP 
1419+.RS 
1420+\f(CW  rsync \-av \-\-rsync\-path="rsync \-\-fake\-super" /src/ host:/dest/\fP
1421+.RE
1422+
1423+.IP 
1424+Since there is only one "side" in a local copy, this option affects both
1425+the sending and recieving of files\&.  You\&'ll need to specify a copy using
1426+"localhost" if you need to avoid this\&.  Note, however, that it is always
1427+safe to copy from some non-fake-super files into some fake-super files
1428+using a local \fB\-\-fake\-super\fP command because the non-fake source files
1429+will just have their normal attributes\&.
1430+.IP 
1431+See also the "fake super" setting in the daemon\&'s rsyncd\&.conf file\&.
1432+This option is overridden by both \fB\-\-super\fP and \fB\-\-no\-super\fP\&.
1433+.IP 
1434 .IP "\fB\-S, \-\-sparse\fP"
1435 Try to handle sparse files efficiently so they take
1436 up less space on the destination\&.  Conflicts with \fB\-\-inplace\fP because it\&'s
1437--- old/rsyncd.conf.5
1438+++ new/rsyncd.conf.5
1439@@ -263,6 +263,12 @@ file transfers to and from that module s
1440 was run as root\&. This complements the "uid" option\&. The default is gid \-2,
1441 which is normally the group "nobody"\&.
1442 .IP 
1443+.IP "\fBfake super\fP"
1444+Setting "fake super = yes" for a module causes the
1445+daemon side to behave as if the \fB\-\-fake\-user\fP command-line option had
1446+been specified\&.  This allows the full attributes of a file to be stored
1447+without having to have the daemon actually running as root\&.
1448+.IP 
1449 .IP "\fBfilter\fP"
1450 The "filter" option allows you to specify a space-separated
1451 list of filter rules that the daemon will not allow to be read or written\&.
1452