Fix issues with unchanged_attrs() for symlinks.
authorWayne Davison <wayned@samba.org>
Sat, 18 Dec 2010 16:48:07 +0000 (08:48 -0800)
committerWayne Davison <wayned@samba.org>
Sat, 18 Dec 2010 16:48:07 +0000 (08:48 -0800)
generator.c
rsync.c
rsync.h

index be36e63e93b1ced16737d4ea5f9775f52cc9810e..61a23059c4c7b6906b2a9d6cb2b8f18c3aeb5812 100644 (file)
@@ -388,42 +388,100 @@ static void do_delete_pass(void)
                rprintf(FINFO, "                    \r");
 }
 
-int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
+static inline int time_differs(struct file_struct *file, stat_x *sxp)
 {
-       if (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(file->mode)) {
-               ;
-       } else if (preserve_times && cmp_time(sxp->st.st_mtime, file->modtime) != 0)
-               return 0;
+       return cmp_time(sxp->st.st_mtime, file->modtime);
+}
 
-       if (preserve_perms) {
-               if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
-                       return 0;
-       } else if (preserve_executability
-        && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
-               return 0;
+static inline int perms_differ(struct file_struct *file, stat_x *sxp)
+{
+       if (preserve_perms)
+               return !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS);
 
+       if (preserve_executability)
+               return (sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0);
+
+       return 0;
+}
+
+static inline int ownership_differs(struct file_struct *file, stat_x *sxp)
+{
        if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))
-               return 0;
+               return 1;
 
        if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))
-               return 0;
+               return 1;
+
+       return 0;
+}
 
 #ifdef SUPPORT_ACLS
-       if (preserve_acls && !S_ISLNK(file->mode)) {
+static inline int acls_differ(const char *fname, struct file_struct *file, stat_x *sxp)
+{
+       if (preserve_acls) {
                if (!ACL_READY(*sxp))
                        get_acl(fname, sxp);
                if (set_acl(NULL, file, sxp, file->mode))
-                       return 0;
+                       return 1;
        }
+
+       return 0;
+}
 #endif
+
 #ifdef SUPPORT_XATTRS
+static inline int xattrs_differ(const char *fname, struct file_struct *file, stat_x *sxp)
+{
        if (preserve_xattrs) {
                if (!XATTR_READY(*sxp))
                        get_xattr(fname, sxp);
                if (xattr_diff(file, sxp, 0))
-                       return 0;
+                       return 1;
        }
+
+       return 0;
+}
+#endif
+
+int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
+{
+       if (S_ISLNK(file->mode)) {
+#ifdef CAN_SET_SYMLINK_TIMES
+               if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
+                       return 0;
+#endif
+#ifdef CAN_CHMOD_SYMLINK
+               if (perms_differ(file, sxp))
+                       return 0;
+#endif
+#ifndef CAN_CHOWN_SYMLINK
+               if (ownership_differs(file, sxp))
+                       return 0;
+#endif
+#if defined SUPPORT_ACLS && 0 /* no current symlink-ACL support */
+               if (acls_differ(fname, file, sxp))
+                       return 0;
 #endif
+#if defined SUPPORT_XATTRS && !defined NO_SYMLINK_XATTRS
+               if (xattrs_differ(fname, file, sxp))
+                       return 0;
+#endif
+       } else {
+               if (preserve_times && time_differs(file, sxp))
+                       return 0;
+               if (perms_differ(file, sxp))
+                       return 0;
+               if (ownership_differs(file, sxp))
+                       return 0;
+#ifdef SUPPORT_ACLS
+               if (acls_differ(fname, file, sxp))
+                       return 0;
+#endif
+#ifdef SUPPORT_XATTRS
+               if (xattrs_differ(fname, file, sxp))
+                       return 0;
+#endif
+       }
 
        return 1;
 }
diff --git a/rsync.c b/rsync.c
index a0da86d3962e6218a0ff8c0a07567dfe8e3e1816..17ce76a45f419c7eadbb4b16d90f05a1ad0565b8 100644 (file)
--- a/rsync.c
+++ b/rsync.c
@@ -510,7 +510,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
        change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
        change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
                  && sxp->st.st_gid != (gid_t)F_GROUP(file);
-#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
+#ifndef CAN_CHOWN_SYMLINK
        if (S_ISLNK(sxp->st.st_mode)) {
                ;
        } else
diff --git a/rsync.h b/rsync.h
index 3404da78254ea74d8c1f680cc13f70603719893c..1b73031b80fc9925b0f145b9a968e0445f5c0f20 100644 (file)
--- a/rsync.h
+++ b/rsync.h
@@ -370,6 +370,14 @@ enum delret {
 #define CAN_SET_SYMLINK_TIMES 1
 #endif
 
+#if defined HAVE_LCHOWN || defined CHOWN_MODIFIES_SYMLINK
+#define CAN_CHOWN_SYMLINK 1
+#endif
+
+#if defined HAVE_LCHMOD || defined HAVE_SETATTRLIST
+#define CAN_CHMOD_SYMLINK 1
+#endif
+
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif