Got rid of some accumulated patch fuzz.
[rsync/rsync-patches.git] / fake-super.diff
index e4f47c5..a70b890 100644 (file)
@@ -1,26 +1,17 @@
-Depends-On-Patch: acls.diff
-Depends-On-Patch: xattrs.diff
-
 This patch adds a new option:  --fake-super, which tells rsync to copy in a
 fake super-user mode that stores various file attributes in an extended-
 attribute value instead of as real file-system attributes.  See the changes
 to the manpages for details.
 
-After applying this patch, run these commands for a successful build:
-
-    ./prepare-source
-    ./configure --enable-xattr-support
-    make
-
-or, if you want ACL support too:
+To use this patch, run these commands for a successful build:
 
-    ./prepare-source
-    ./configure --enable-acl-support --enable-xattr-support
+    patch -p1 <patches/fake-super.diff
+    ./configure                         (optional if already run)
     make
 
 --- old/backup.c
 +++ new/backup.c
-@@ -129,7 +129,7 @@ static int make_bak_dir(char *fullpath)
+@@ -127,7 +127,7 @@ static int make_bak_dir(char *fullpath)
                if (p >= rel) {
                        /* Try to transfer the directory settings of the
                         * actual dir that the files are coming from. */
@@ -29,7 +20,7 @@ or, if you want ACL support too:
                                rsyserr(FERROR, errno,
                                        "make_bak_dir stat %s failed",
                                        full_fname(rel));
-@@ -200,7 +200,7 @@ static int keep_backup(char *fname)
+@@ -200,7 +200,7 @@ static int keep_backup(const char *fname
        int ret_code;
  
        /* return if no file to keep */
@@ -40,9 +31,9 @@ or, if you want ACL support too:
        sx.acc_acl = sx.def_acl = NULL;
 --- old/clientserver.c
 +++ new/clientserver.c
-@@ -625,6 +625,11 @@ static int rsync_module(int f_in, int f_
-       ret = parse_arguments(&argc, (const char ***) &argv, 0);
-       quiet = 0; /* Don't let someone try to be tricky. */
+@@ -630,6 +630,11 @@ static int rsync_module(int f_in, int f_
+       if (lp_ignore_errors(module_id))
+               ignore_errors = 1;
  
 +      if (lp_fake_super(i))
 +              am_root = -1;
@@ -54,7 +45,13 @@ or, if you want ACL support too:
  
 --- old/flist.c
 +++ new/flist.c
-@@ -181,7 +181,7 @@ static int readlink_stat(const char *pat
+@@ -196,12 +196,12 @@ static int readlink_stat(const char *pat
+                               rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
+                                       path, linkbuf);
+                       }
+-                      return do_stat(path, stp);
++                      return x_stat(path, stp, NULL);
+               }
        }
        return 0;
  #else
@@ -63,7 +60,7 @@ or, if you want ACL support too:
  #endif
  }
  
-@@ -189,17 +189,17 @@ int link_stat(const char *path, STRUCT_S
+@@ -209,17 +209,17 @@ int link_stat(const char *path, STRUCT_S
  {
  #ifdef SUPPORT_LINKS
        if (copy_links)
@@ -85,7 +82,7 @@ or, if you want ACL support too:
  #endif
  }
  
-@@ -234,26 +234,6 @@ static int is_excluded(char *fname, int 
+@@ -254,26 +254,6 @@ static int is_excluded(char *fname, int 
        return 0;
  }
  
@@ -109,10 +106,10 @@ or, if you want ACL support too:
 -      return mode;
 -}
 -
- static void send_directory(int f, struct file_list *flist,
-                          char *fbuf, int len);
+ static void send_directory(int f, struct file_list *flist, int ndx,
+                          char *fbuf, int len, int flags);
  
-@@ -793,7 +773,7 @@ struct file_struct *make_file(char *fnam
+@@ -954,7 +934,7 @@ struct file_struct *make_file(const char
                if (save_errno == ENOENT) {
  #ifdef SUPPORT_LINKS
                        /* Avoid "vanished" error if symlink points nowhere. */
@@ -121,18 +118,18 @@ or, if you want ACL support too:
                            && S_ISLNK(st.st_mode)) {
                                io_error |= IOERR_GENERAL;
                                rprintf(FERROR, "symlink has no referent: %s\n",
-@@ -963,7 +943,7 @@ struct file_struct *make_file(char *fnam
+@@ -1126,7 +1106,7 @@ struct file_struct *make_file(const char
                int save_mode = file->mode;
                file->mode = S_IFDIR; /* Find a directory with our name. */
-               if (flist_find(the_file_list, file) >= 0
+               if (flist_find(dir_flist, file) >= 0
 -                  && do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) {
 +                  && x_stat(thisname, &st2, NULL) == 0 && S_ISDIR(st2.st_mode)) {
                        file->modtime = st2.st_mtime;
-                       file->length = st2.st_size;
+                       file->len32 = 0;
                        file->mode = st2.st_mode;
 --- old/loadparm.c
 +++ new/loadparm.c
-@@ -150,6 +150,7 @@ typedef struct
+@@ -149,6 +149,7 @@ typedef struct
        int syslog_facility;
        int timeout;
  
@@ -140,7 +137,7 @@ or, if you want ACL support too:
        BOOL ignore_errors;
        BOOL ignore_nonreadable;
        BOOL list;
-@@ -197,6 +198,7 @@ static service sDefault =
+@@ -196,6 +197,7 @@ static service sDefault =
   /* syslog_facility; */               LOG_DAEMON,
   /* timeout; */                       0,
  
@@ -148,7 +145,7 @@ or, if you want ACL support too:
   /* ignore_errors; */         False,
   /* ignore_nonreadable; */    False,
   /* list; */                  True,
-@@ -298,6 +300,7 @@ static struct parm_struct parm_table[] =
+@@ -297,6 +299,7 @@ static struct parm_struct parm_table[] =
   {"dont compress",     P_STRING, P_LOCAL, &sDefault.dont_compress,     NULL,0},
   {"exclude from",      P_STRING, P_LOCAL, &sDefault.exclude_from,      NULL,0},
   {"exclude",           P_STRING, P_LOCAL, &sDefault.exclude,           NULL,0},
@@ -156,7 +153,7 @@ or, if you want ACL support too:
   {"filter",            P_STRING, P_LOCAL, &sDefault.filter,            NULL,0},
   {"gid",               P_STRING, P_LOCAL, &sDefault.gid,               NULL,0},
   {"hosts allow",       P_STRING, P_LOCAL, &sDefault.hosts_allow,       NULL,0},
-@@ -412,6 +415,7 @@ FN_LOCAL_INTEGER(lp_max_connections, max
+@@ -411,6 +414,7 @@ FN_LOCAL_INTEGER(lp_max_connections, max
  FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
  FN_LOCAL_INTEGER(lp_timeout, timeout)
  
@@ -164,7 +161,7 @@ or, if you want ACL support too:
  FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
  FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
  FN_LOCAL_BOOL(lp_list, list)
-@@ -816,7 +820,7 @@ BOOL lp_load(char *pszFname, int globals
+@@ -814,7 +818,7 @@ BOOL lp_load(char *pszFname, int globals
  
        if (pszFname)
            pstrcpy(n2,pszFname);
@@ -175,7 +172,7 @@ or, if you want ACL support too:
            pstrcpy(n2,RSYNCD_SYSCONF);
 --- old/options.c
 +++ new/options.c
-@@ -73,7 +73,7 @@ int protocol_version = PROTOCOL_VERSION;
+@@ -72,7 +72,7 @@ int protocol_version = PROTOCOL_VERSION;
  int sparse_files = 0;
  int do_compression = 0;
  int def_compress_level = Z_DEFAULT_COMPRESSION;
@@ -184,7 +181,7 @@ or, if you want ACL support too:
  int am_server = 0;
  int am_sender = 0;
  int am_generator = 0;
-@@ -329,6 +329,9 @@ void usage(enum logcode F)
+@@ -326,6 +326,9 @@ void usage(enum logcode F)
    rprintf(F," -t, --times                 preserve times\n");
    rprintf(F," -O, --omit-dir-times        omit directories when preserving times\n");
    rprintf(F,"     --super                 receiver attempts super-user activities\n");
@@ -194,7 +191,7 @@ or, if you want ACL support too:
    rprintf(F," -S, --sparse                handle sparse files efficiently\n");
    rprintf(F," -n, --dry-run               show what would have been transferred\n");
    rprintf(F," -W, --whole-file            copy files whole (without rsync algorithm)\n");
-@@ -453,6 +456,7 @@ static struct poptOption long_options[] 
+@@ -455,6 +458,7 @@ static struct poptOption long_options[] 
    {"modify-window",    0,  POPT_ARG_INT,    &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
    {"super",            0,  POPT_ARG_VAL,    &am_root, 2, 0, 0 },
    {"no-super",         0,  POPT_ARG_VAL,    &am_root, 0, 0, 0 },
@@ -202,7 +199,7 @@ or, if you want ACL support too:
    {"owner",           'o', POPT_ARG_VAL,    &preserve_uid, 1, 0, 0 },
    {"no-owner",         0,  POPT_ARG_VAL,    &preserve_uid, 0, 0, 0 },
    {"no-o",             0,  POPT_ARG_VAL,    &preserve_uid, 0, 0, 0 },
-@@ -1178,6 +1182,14 @@ int parse_arguments(int *argc, const cha
+@@ -1187,6 +1191,14 @@ int parse_arguments(int *argc, const cha
        }
  #endif
  
@@ -219,18 +216,27 @@ or, if you want ACL support too:
                        "--write-batch and --read-batch can not be used together\n");
 --- old/rsync.c
 +++ new/rsync.c
-@@ -196,7 +196,9 @@ int set_file_attrs(char *fname, struct f
-                                       (long)sxp->st.st_gid, (long)file->gid);
+@@ -261,6 +261,8 @@ int set_file_attrs(const char *fname, st
+ #ifdef SUPPORT_XATTRS
+       if (preserve_xattrs && fnamecmp)
+               set_xattr(fname, file, fnamecmp, sxp);
++      if (am_root < 0)
++              set_stat_xattr(fname, file);
+ #endif
+       if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times))
+@@ -300,7 +302,9 @@ int set_file_attrs(const char *fname, st
+                                       (long)sxp->st.st_gid, (long)F_GID(file));
                        }
                }
 -              if (do_lchown(fname,
 +              if (am_root < 0) {
 +                      ;
 +              } else if (do_lchown(fname,
-                   change_uid ? file->uid : sxp->st.st_uid,
-                   change_gid ? file->gid : sxp->st.st_gid) != 0) {
+                   change_uid ? F_UID(file) : sxp->st.st_uid,
+                   change_gid ? F_GID(file) : sxp->st.st_gid) != 0) {
                        /* shouldn't have attempted to change uid or gid
-@@ -205,7 +207,7 @@ int set_file_attrs(char *fname, struct f
+@@ -309,7 +313,7 @@ int set_file_attrs(const char *fname, st
                            change_uid ? "chown" : "chgrp",
                            full_fname(fname));
                        goto cleanup;
@@ -239,19 +245,10 @@ or, if you want ACL support too:
                /* a lchown had been done - we have to re-stat if the
                 * destination had the setuid or setgid bits set due
                 * to the side effect of the chown call */
-@@ -222,6 +224,8 @@ int set_file_attrs(char *fname, struct f
- #ifdef SUPPORT_XATTRS
-       if (preserve_xattrs && set_xattr(fname, file, sxp) == 0)
-               updated = 1;
-+      if (am_root < 0)
-+              set_stat_xattr(fname, file);
- #endif
- #ifdef SUPPORT_ACLS
-       /* It's OK to call set_acl() now, even for a dir, as the generator
-@@ -236,7 +240,7 @@ int set_file_attrs(char *fname, struct f
+@@ -336,7 +340,7 @@ int set_file_attrs(const char *fname, st
  
  #ifdef HAVE_CHMOD
-       if ((sxp->st.st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
+       if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
 -              int ret = do_chmod(fname, new_mode);
 +              int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
                if (ret < 0) {
@@ -259,7 +256,7 @@ or, if you want ACL support too:
                                "failed to set permissions on %s",
 --- old/rsync.h
 +++ new/rsync.h
-@@ -707,6 +707,12 @@ typedef struct {
+@@ -805,6 +805,12 @@ typedef struct {
  
  #include "proto.h"
  
@@ -272,11 +269,10 @@ or, if you want ACL support too:
  /* We have replacement versions of these if they're missing. */
  #ifndef HAVE_ASPRINTF
  int asprintf(char **ptr, const char *format, ...);
-@@ -924,3 +930,23 @@ int inet_pton(int af, const char *src, v
- #ifdef MAINTAINER_MODE
+@@ -1023,6 +1029,26 @@ int inet_pton(int af, const char *src, v
  const char *get_panic_action(void);
  #endif
-+
 +static inline int to_wire_mode(mode_t mode)
 +{
 +#ifdef SUPPORT_LINKS
@@ -296,6 +292,10 @@ or, if you want ACL support too:
 +#endif
 +      return mode;
 +}
++
+ static inline int
+ isDigit(const char *ptr)
+ {
 --- old/rsync.yo
 +++ new/rsync.yo
 @@ -333,6 +333,7 @@ to the detailed description below for a 
@@ -306,7 +306,7 @@ or, if you want ACL support too:
   -S, --sparse                handle sparse files efficiently
   -n, --dry-run               show what would have been transferred
   -W, --whole-file            copy files whole (without rsync algorithm)
-@@ -846,7 +847,7 @@ permission value can be applied to the f
+@@ -859,7 +860,7 @@ permission value can be applied to the f
  dit(bf(-o, --owner)) This option causes rsync to set the owner of the
  destination file to be the same as the source file, but only if the
  receiving rsync is being run as the super-user (see also the bf(--super)
@@ -315,7 +315,7 @@ or, if you want ACL support too:
  Without this option, the owner is set to the invoking user on the
  receiving side.
  
-@@ -869,7 +870,7 @@ default, but may fall back to using the 
+@@ -882,7 +883,7 @@ default, but may fall back to using the 
  dit(bf(--devices)) This option causes rsync to transfer character and
  block device files to the remote system to recreate these devices.
  This option has no effect if the receiving rsync is not run as the
@@ -324,7 +324,7 @@ or, if you want ACL support too:
  
  dit(bf(--specials)) This option causes rsync to transfer special files
  such as named sockets and fifos.
-@@ -899,6 +900,33 @@ also for ensuring that you will get erro
+@@ -912,6 +913,33 @@ also for ensuring that you will get erro
  being running as the super-user.  To turn off super-user activities, the
  super-user can use bf(--no-super).
  
@@ -374,7 +374,7 @@ or, if you want ACL support too:
  This is only superficially equivalent to the client specifying these
 --- old/syscall.c
 +++ new/syscall.c
-@@ -28,6 +28,7 @@
+@@ -27,6 +27,7 @@
  #endif
  
  extern int dry_run;
@@ -382,7 +382,7 @@ or, if you want ACL support too:
  extern int read_only;
  extern int list_only;
  extern int preserve_perms;
-@@ -79,6 +80,15 @@ int do_mknod(char *pathname, mode_t mode
+@@ -78,6 +79,15 @@ int do_mknod(const char *pathname, mode_
  {
        if (dry_run) return 0;
        RETURN_ERROR_IF_RO_OR_LO;
@@ -400,7 +400,7 @@ or, if you want ACL support too:
                return mkfifo(pathname, mode);
 --- old/t_unsafe.c
 +++ new/t_unsafe.c
-@@ -24,7 +24,11 @@
+@@ -23,7 +23,11 @@
  
  #include "rsync.h"
  
@@ -419,13 +419,13 @@ or, if you want ACL support too:
  
  /* These are to make syscall.o shut up. */
  int dry_run = 0;
-+int am_root = 0; /* TODO: add option to set this to -1. */
++int am_root = 0;
  int read_only = 1;
  int list_only = 0;
  int preserve_perms = 0;
 --- old/trimslash.c
 +++ new/trimslash.c
-@@ -23,6 +23,7 @@
+@@ -22,6 +22,7 @@
  
  /* These are to make syscall.o shut up. */
  int dry_run = 0;
@@ -433,62 +433,100 @@ or, if you want ACL support too:
  int read_only = 1;
  int list_only = 0;
  int preserve_perms = 0;
---- old/xattr.c
-+++ new/xattr.c
-@@ -28,11 +28,14 @@
- extern int dry_run;
- extern int read_only;
- extern int list_only;
-+extern int am_root;
- extern unsigned int file_struct_len;
- #define RSYNC_XAL_INITIAL 5
- #define RSYNC_XAL_LIST_INITIAL 100
+--- old/xattrs.c
++++ new/xattrs.c
+@@ -53,11 +53,16 @@ extern int checksum_seed;
+ #define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1)
  
-+#define FAKE_XATTR "user.rsync%stat"
+ #ifdef HAVE_LINUX_XATTRS
+-#define RPRE_LEN 0
++#define MIGHT_NEED_RPRE (am_root < 0)
++#define RSYNC_PREFIX USER_PREFIX "rsync."
+ #else
++#define MIGHT_NEED_RPRE am_root
+ #define RSYNC_PREFIX "rsync."
+-#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
+ #endif
++#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
 +
++#define XSTAT_ATTR RSYNC_PREFIX "%stat"
++#define XSTAT_LEN ((int)sizeof XSTAT_ATTR - 1)
  typedef struct {
-       char *name;
-       char *datum;
-@@ -132,9 +135,15 @@ static int rsync_xal_get(const char *fna
-       if (name_size == 0)
-               return 0;
-       for (left = name_size, name = namebuf; left > 0 ; left -= len, name += len) {
--              rsync_xa *rxas = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
-+              rsync_xa *rxas;
-               len = strlen(name) + 1;
-+              if (am_root < 0 && len == sizeof FAKE_XATTR
-+               && name[10] == '%' && strcmp(name, FAKE_XATTR) == 0)
+       char *datum, *name;
+@@ -218,6 +223,10 @@ static int rsync_xal_get(const char *fna
+                       continue;
+ #endif
++              if (am_root < 0 && name_len == XSTAT_LEN + 1
++               && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
 +                      continue;
 +
-+              rxas = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
-+
-               datum_size = sys_lgetxattr(fname, name, NULL, 0);
-               if (datum_size < 0) {
-                       if (errno == ENOTSUP)
-@@ -287,10 +296,19 @@ void receive_xattr(struct file_struct *f
-                               out_of_memory("receive_xattr");
-                       read_buf(f, ptr, name_len);
-                       read_buf(f, ptr + name_len, datum_len);
-+
-+                      if (am_root < 0 && name_len == sizeof FAKE_XATTR
-+                       && ptr[10] == '%' && strcmp(ptr, FAKE_XATTR) == 0) {
-+                              free(ptr);
-+                              temp_xattr.count--;
-+                              continue;
-+                      }
-+
-                       rxa->name_len = name_len;
-                       rxa->datum_len = datum_len;
-                       rxa->name = ptr;
-                       rxa->datum = ptr + name_len;
-+
- #ifdef HAVE_OSX_XATTRS
-                       if (strncmp(rxa->name, UNIQUE_PREFIX, UPRE_LEN) == 0) {
-                               rxa->name_len -= UPRE_LEN;
-@@ -372,4 +390,146 @@ int set_xattr(const char *fname, const s
-       return rsync_xal_set(fname, lst + ndx); /* TODO:  This needs to return 1 if no xattrs changed! */
+               datum_len = name_len; /* Pass extra size to get_xattr_data() */
+               if (!(ptr = get_xattr_data(fname, name, &datum_len, 0)))
+                       return -1;
+@@ -236,6 +245,14 @@ static int rsync_xal_get(const char *fna
+               } else
+                       name_offset = datum_len;
++#ifdef HAVE_LINUX_XATTRS
++              if (am_root < 0 && name_len > RPRE_LEN
++               && HAS_PREFIX(name, RSYNC_PREFIX)) {
++                      name += RPRE_LEN;
++                      name_len -= RPRE_LEN;
++              }
++#endif
++
+               rxas = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
+               rxas->name = ptr + name_offset;
+               memcpy(rxas->name, name, name_len);
+@@ -576,13 +593,9 @@ void receive_xattr(struct file_struct *f
+               size_t name_len = read_abbrevint(f);
+               size_t datum_len = read_abbrevint(f);
+               size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
+-#ifdef HAVE_LINUX_XATTRS
+-              size_t extra_len = 0;
+-#else
+-              size_t extra_len = am_root ? RPRE_LEN : 0;
++              size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
+               if (dget_len + extra_len < dget_len)
+                       out_of_memory("receive_xattr"); /* overflow */
+-#endif
+               if (dget_len + extra_len + name_len < dget_len)
+                       out_of_memory("receive_xattr"); /* overflow */
+               ptr = new_array(char, dget_len + extra_len + name_len);
+@@ -598,9 +611,14 @@ void receive_xattr(struct file_struct *f
+               }
+ #ifdef HAVE_LINUX_XATTRS
+               /* Non-root can only save the user namespace. */
+-              if (!am_root && !HAS_PREFIX(name, USER_PREFIX)) {
+-                      free(ptr);
+-                      continue;
++                      if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
++                              if (!am_root) {
++                                      free(ptr);
++                                      continue;
++                              }
++                              name -= RPRE_LEN;
++                              name_len += RPRE_LEN;
++                              memcpy(name, RSYNC_PREFIX, RPRE_LEN);
+               }
+ #else
+               /* This OS only has a user namespace, so we either
+@@ -618,6 +636,11 @@ void receive_xattr(struct file_struct *f
+                       continue;
+               }
+ #endif
++              if (am_root < 0 && name_len == XSTAT_LEN + 1
++               && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0) {
++                      free(ptr);
++                      continue;
++              }
+               rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1);
+               rxa->name = name;
+               rxa->datum = ptr;
+@@ -772,4 +795,150 @@ int set_xattr(const char *fname, const s
+       return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp);
  }
  
 +int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
@@ -505,10 +543,10 @@ or, if you want ACL support too:
 +              xst = fst;
 +      if (fname) {
 +              fd = -1;
-+              len = sys_lgetxattr(fname, FAKE_XATTR, buf, sizeof buf - 1);
++              len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
 +      } else {
 +              fname = "fd";
-+              len = sys_fgetxattr(fd, FAKE_XATTR, buf, sizeof buf - 1);
++              len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
 +      }
 +      if (len >= (int)sizeof buf) {
 +              len = -1;
@@ -523,7 +561,7 @@ or, if you want ACL support too:
 +                      return 0;
 +              }
 +              rsyserr(FERROR, errno, "failed to read xattr %s for %s",
-+                      FAKE_XATTR, full_fname(fname));
++                      XSTAT_ATTR, full_fname(fname));
 +              return -1;
 +      }
 +      buf[len] = '\0';
@@ -531,7 +569,7 @@ or, if you want ACL support too:
 +      if (sscanf(buf, "%o %d,%d %d:%d",
 +                 &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
 +              rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
-+                      FAKE_XATTR, full_fname(fname), buf);
++                      XSTAT_ATTR, full_fname(fname), buf);
 +              exit_cleanup(RERR_FILEIO);
 +      }
 +
@@ -547,14 +585,14 @@ or, if you want ACL support too:
 +{
 +      STRUCT_STAT fst, xst;
 +      dev_t rdev;
-+      mode_t mode;
++      mode_t mode, fmode;
 +
 +      if (dry_run)
 +              return 0;
 +
 +      if (read_only || list_only) {
 +              rsyserr(FERROR, EROFS, "failed to write xattr %s for %s",
-+                      FAKE_XATTR, full_fname(fname));
++                      XSTAT_ATTR, full_fname(fname));
 +              return -1;
 +      }
 +
@@ -564,23 +602,27 @@ or, if you want ACL support too:
 +              return -1;
 +      }
 +
-+      if (IS_DEVICE(file->mode) || IS_SPECIAL(file->mode))
-+              rdev = file->u.rdev;
-+      else
++      fst.st_mode &= (_S_IFMT | CHMOD_BITS);
++      fmode = file->mode & (_S_IFMT | CHMOD_BITS);
++
++      if (IS_DEVICE(fmode) || IS_SPECIAL(fmode)) {
++              uint32 *devp = F_RDEV_P(file);
++              rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
++      } else
 +              rdev = 0;
 +
 +      /* Dump the special permissions and enable full owner access. */
-+      mode = (fst.st_mode & ~CHMOD_BITS) | (file->mode & ACCESSPERMS)
++      mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
 +           | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
 +      if (fst.st_mode != mode)
 +              do_chmod(fname, mode);
 +      if (!IS_DEVICE(fst.st_mode) && !IS_SPECIAL(fst.st_mode))
 +              fst.st_rdev = 0; /* just in case */
 +
-+      if (mode == file->mode && fst.st_rdev == rdev
-+       && fst.st_uid == file->uid && fst.st_gid == file->gid) {
++      if (mode == fmode && fst.st_rdev == rdev
++       && fst.st_uid == F_UID(file) && fst.st_gid == F_GID(file)) {
 +              /* xst.st_mode will be 0 if there's no current stat xattr */
-+              if (xst.st_mode && sys_lremovexattr(fname, FAKE_XATTR) < 0) {
++              if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
 +                      rsyserr(FERROR, errno,
 +                              "delete of stat xattr failed for %s",
 +                              full_fname(fname));
@@ -589,19 +631,19 @@ or, if you want ACL support too:
 +              return 0;
 +      }
 +
-+      if (xst.st_mode != file->mode || xst.st_rdev != rdev
-+       || xst.st_uid != file->uid || xst.st_gid != file->gid) {
++      if (xst.st_mode != fmode || xst.st_rdev != rdev
++       || xst.st_uid != F_UID(file) || xst.st_gid != F_GID(file)) {
 +              char buf[256];
 +              int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
-+                      to_wire_mode(file->mode) & (_S_IFMT|CHMOD_BITS),
++                      to_wire_mode(fmode),
 +                      (int)major(rdev), (int)minor(rdev),
-+                      (int)file->uid, (int)file->gid);
-+              if (sys_lsetxattr(fname, FAKE_XATTR, buf, len, 0) < 0) {
++                      (int)F_UID(file), (int)F_GID(file));
++              if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
 +                      if (errno == EPERM && S_ISLNK(fst.st_mode))
 +                              return 0;
 +                      rsyserr(FERROR, errno,
 +                              "failed to write xattr %s for %s",
-+                              FAKE_XATTR, full_fname(fname));
++                              XSTAT_ATTR, full_fname(fname));
 +                      return -1;
 +              }
 +      }