{"no-o", 0, POPT_ARG_VAL, &preserve_uid, 0, 0, 0 },
--- old/rsync.c
+++ new/rsync.c
-@@ -197,6 +197,12 @@ int set_file_attrs(char *fname, struct f
+@@ -197,7 +197,9 @@ int set_file_attrs(char *fname, struct f
(long)sxp->st.st_gid, (long)file->gid);
}
}
-+ if (am_root < 0) {
-+ if (change_uid)
-+ sxp->st.st_uid = file->uid;
-+ if (change_gid)
-+ sxp->st.st_gid = file->gid;
-+ } else
- if (do_lchown(fname,
+- 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) {
-@@ -206,7 +212,7 @@ int set_file_attrs(char *fname, struct f
+ /* shouldn't have attempted to change uid or gid
+@@ -206,7 +208,7 @@ int set_file_attrs(char *fname, struct f
change_uid ? "chown" : "chgrp",
full_fname(fname));
goto cleanup;
/* 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 */
-@@ -237,7 +243,16 @@ int set_file_attrs(char *fname, struct f
+@@ -237,7 +239,15 @@ int set_file_attrs(char *fname, struct f
#ifdef HAVE_CHMOD
if ((sxp->st.st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
+ ret = do_chmod(fname, mode);
+ else
+ ret = 0;
-+ sxp->st.st_mode = new_mode;
+ } else
+ ret = do_chmod(fname, new_mode);
if (ret < 0) {
rsyserr(FERROR, errno,
"failed to set permissions on %s",
-@@ -249,6 +264,22 @@ int set_file_attrs(char *fname, struct f
+@@ -249,6 +259,23 @@ int set_file_attrs(char *fname, struct f
}
#endif
+ if (am_root < 0) {
-+ int write_it = updated;
-+ if (IS_DEVICE(file->mode) || IS_SPECIAL(file->mode)) {
-+ if (file->u.rdev != sxp->st.st_rdev) {
-+ sxp->st.st_rdev = file->u.rdev;
-+ write_it = 1;
-+ }
-+ } else
-+ sxp->st.st_rdev = 0;
-+ if (write_it && set_stat_xattr(fname, &sxp->st) < 0) {
++ switch (set_stat_xattr(fname, file)) {
++ case 0:
++ break;
++ case -1:
+ rsyserr(FERROR, errno,
+ "write of stat xattr failed for %s",
+ full_fname(fname));
++ break;
++ case -2:
++ rsyserr(FERROR, errno,
++ "delete of stat xattr failed for %s",
++ full_fname(fname));
++ break;
+ }
+ }
+
#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
if (S_ISFIFO(mode))
return mkfifo(pathname, mode);
-@@ -215,23 +226,71 @@ int do_mkstemp(char *template, mode_t pe
+@@ -215,23 +226,98 @@ int do_mkstemp(char *template, mode_t pe
#endif
}
+ len = sys_lgetxattr(fname, FAKE_XATTR, buf, sizeof buf - 1);
+ if (len < 0 || len >= (int)sizeof buf) {
+ if (errno == ENOTSUP || errno == ENOATTR)
-+ return 0;
++ return -1;
+ return -1;
+ }
+ buf[len] = '\0';
+
+ if (sscanf(buf, "%o %d,%d %d:%d",
-+ &mode, &rdev_major, &rdev_minor, &uid, &gid) != 4) {
++ &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
-+int set_stat_xattr(const char *fname, STRUCT_STAT *st)
++int set_stat_xattr(const char *fname, struct file_struct *file)
+{
-+ char buf[256];
-+ int len;
++ STRUCT_STAT fst, xst;
++ int have_xattr;
++ dev_t rdev;
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
-+ len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
-+ (int)st->st_mode,
-+ (int)major(st->st_rdev), (int)minor(st->st_rdev),
-+ (int)st->st_uid, (int)st->st_gid);
-+ return sys_lsetxattr(fname, FAKE_XATTR, buf, len, 0);
++
++ am_root = 2; /* get real stat() w/o xattr overlay */
++ do_stat(fname, &fst);
++ am_root = -1;
++ have_xattr = get_stat_xattr(fname, &xst) == 0;
++
++ if (IS_DEVICE(file->mode) || IS_SPECIAL(file->mode))
++ rdev = file->u.rdev;
++ else
++ rdev = 0;
++ if (!IS_DEVICE(fst.st_mode) && !IS_SPECIAL(fst.st_mode))
++ fst.st_rdev = 0; /* just in case */
++
++ if (fst.st_mode == file->mode && fst.st_rdev == rdev
++ && fst.st_uid == file->uid && fst.st_gid == file->gid) {
++ if (have_xattr && sys_lremovexattr(fname, FAKE_XATTR) < 0)
++ return -2;
++ return 0;
++ }
++
++ if (!have_xattr
++ || xst.st_mode != file->mode || xst.st_rdev != rdev
++ || xst.st_uid != file->uid || xst.st_gid != file->gid) {
++ char buf[256];
++ int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
++ (int)file->mode,
++ (int)major(rdev), (int)minor(rdev),
++ (int)file->uid, (int)file->gid);
++ return sys_lsetxattr(fname, FAKE_XATTR, buf, len, 0);
++ }
++ return 0;
+}
+
int do_stat(const char *fname, STRUCT_STAT *st)