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