Fixed an ACL/xattr corruption issue where the --backup option could cause
authorWayne Davison <wayned@samba.org>
Fri, 10 Apr 2009 23:22:44 +0000 (16:22 -0700)
committerWayne Davison <wayned@samba.org>
Fri, 10 Apr 2009 23:22:44 +0000 (16:22 -0700)
rsync to associate the wrong ACL/xattr information with received files.

acls.c
backup.c
xattrs.c

diff --git a/acls.c b/acls.c
index dc80dce..105b985 100644 (file)
--- a/acls.c
+++ b/acls.c
@@ -88,6 +88,9 @@ static const rsync_acl empty_rsync_acl = {
 static item_list access_acl_list = EMPTY_ITEM_LIST;
 static item_list default_acl_list = EMPTY_ITEM_LIST;
 
+static size_t prior_access_count = (size_t)-1;
+static size_t prior_default_count = (size_t)-1;
+
 /* === Calculations on ACL types === */
 
 static const char *str_acl_type(SMB_ACL_TYPE_T type)
@@ -788,17 +791,50 @@ static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl
 
 /* Turn the ACL data in stat_x into cached ACL data, setting the index
  * values in the file struct. */
-void cache_acl(struct file_struct *file, stat_x *sxp)
+void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
 {
+       if (prior_access_count == (size_t)-1)
+               prior_access_count = access_acl_list.count;
+
        F_ACL(file) = cache_rsync_acl(sxp->acc_acl,
                                      SMB_ACL_TYPE_ACCESS, &access_acl_list);
 
        if (S_ISDIR(sxp->st.st_mode)) {
+               if (prior_default_count == (size_t)-1)
+                       prior_default_count = default_acl_list.count;
                F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl,
                                      SMB_ACL_TYPE_DEFAULT, &default_acl_list);
        }
 }
 
+static void uncache_duo_acls(item_list *duo_list, size_t start)
+{
+       acl_duo *duo_item = duo_list->items;
+       acl_duo *duo_start = duo_item + start;
+
+       duo_item += duo_list->count;
+       duo_list->count = start;
+
+       while (duo_item-- > duo_start) {
+               rsync_acl_free(&duo_item->racl);
+               if (duo_item->sacl)
+                       sys_acl_free_acl(duo_item->sacl);
+       }
+}
+
+void uncache_tmp_acls(void)
+{
+       if (prior_access_count != (size_t)-1) {
+               uncache_duo_acls(&access_acl_list, prior_access_count);
+               prior_access_count = (size_t)-1;
+       }
+
+       if (prior_default_count != (size_t)-1) {
+               uncache_duo_acls(&default_acl_list, prior_default_count);
+               prior_default_count = (size_t)-1;
+       }
+}
+
 #ifndef HAVE_OSX_ACLS
 static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode)
 {
index 0da6b33..5805f16 100644 (file)
--- a/backup.c
+++ b/backup.c
@@ -106,19 +106,25 @@ int make_bak_dir(const char *fullpath)
 #ifdef SUPPORT_ACLS
                                if (preserve_acls && !S_ISLNK(file->mode)) {
                                        get_acl(rel, &sx);
-                                       cache_acl(file, &sx);
+                                       cache_tmp_acl(file, &sx);
                                        free_acl(&sx);
                                }
 #endif
 #ifdef SUPPORT_XATTRS
                                if (preserve_xattrs) {
                                        get_xattr(rel, &sx);
-                                       cache_xattr(file, &sx);
+                                       cache_tmp_xattr(file, &sx);
                                        free_xattr(&sx);
                                }
 #endif
                                set_file_attrs(fbuf, file, NULL, NULL, 0);
                                unmake_file(file);
+#ifdef SUPPORT_ACLS
+                               uncache_tmp_acls();
+#endif
+#ifdef SUPPORT_XATTRS
+                               uncache_tmp_xattrs();
+#endif
                        }
                }
                *p = '/';
@@ -219,14 +225,14 @@ int make_backup(const char *fname, BOOL prefer_rename)
 #ifdef SUPPORT_ACLS
        if (preserve_acls && !S_ISLNK(file->mode)) {
                get_acl(fname, &sx);
-               cache_acl(file, &sx);
+               cache_tmp_acl(file, &sx);
                free_acl(&sx);
        }
 #endif
 #ifdef SUPPORT_XATTRS
        if (preserve_xattrs) {
                get_xattr(fname, &sx);
-               cache_xattr(file, &sx);
+               cache_tmp_xattr(file, &sx);
                free_xattr(&sx);
        }
 #endif
@@ -313,6 +319,12 @@ int make_backup(const char *fname, BOOL prefer_rename)
                rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
                        fname);
                unmake_file(file);
+#ifdef SUPPORT_ACLS
+               uncache_tmp_acls();
+#endif
+#ifdef SUPPORT_XATTRS
+               uncache_tmp_xattrs();
+#endif
                return 2;
        }
 
@@ -322,6 +334,12 @@ int make_backup(const char *fname, BOOL prefer_rename)
                        rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
                                full_fname(fname), buf);
                        unmake_file(file);
+#ifdef SUPPORT_ACLS
+                       uncache_tmp_acls();
+#endif
+#ifdef SUPPORT_XATTRS
+                       uncache_tmp_xattrs();
+#endif
                        return 0;
                }
                ret = 2;
@@ -333,6 +351,12 @@ int make_backup(const char *fname, BOOL prefer_rename)
        preserve_xattrs = save_preserve_xattrs;
 
        unmake_file(file);
+#ifdef SUPPORT_ACLS
+       uncache_tmp_acls();
+#endif
+#ifdef SUPPORT_XATTRS
+       uncache_tmp_xattrs();
+#endif
 
   success:
        if (INFO_GTE(BACKUP, 1)) {
index 2d0e050..b903475 100644 (file)
--- a/xattrs.c
+++ b/xattrs.c
@@ -82,6 +82,8 @@ static char *namebuf = NULL;
 static item_list empty_xattr = EMPTY_ITEM_LIST;
 static item_list rsync_xal_l = EMPTY_ITEM_LIST;
 
+static size_t prior_xattr_count = (size_t)-1;
+
 /* ------------------------------------------------------------------------- */
 
 static void rsync_xal_free(item_list *xalp)
@@ -725,13 +727,15 @@ void receive_xattr(struct file_struct *file, int f)
 
 /* Turn the xattr data in stat_x into cached xattr data, setting the index
  * values in the file struct. */
-void cache_xattr(struct file_struct *file, stat_x *sxp)
+void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
 {
        int ndx;
 
        if (!sxp->xattr)
                return;
 
+       if (prior_xattr_count == (size_t)-1)
+               prior_xattr_count = rsync_xal_l.count;
        ndx = find_matching_xattr(sxp->xattr);
        if (ndx < 0)
                rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
@@ -739,6 +743,21 @@ void cache_xattr(struct file_struct *file, stat_x *sxp)
        F_XATTR(file) = ndx;
 }
 
+void uncache_tmp_xattrs(void)
+{
+       if (prior_xattr_count != (size_t)-1) {
+               item_list *xattr_item = rsync_xal_l.items;
+               item_list *xattr_start = xattr_item + prior_xattr_count;
+               xattr_item += rsync_xal_l.count;
+               rsync_xal_l.count = prior_xattr_count;
+               while (xattr_item-- > xattr_start) {
+                       rsync_xal_free(xattr_item);
+                       free(xattr_item);
+               }
+               prior_xattr_count = (size_t)-1;
+       }
+}
+
 static int rsync_xal_set(const char *fname, item_list *xalp,
                         const char *fnamecmp, stat_x *sxp)
 {