[augeas-devel] [PATCH] Fix problem with transferring file attributes during save

David Lutterkort lutter at redhat.com
Thu Oct 30 23:34:04 UTC 2008


* src/transform.c(transform_save): transfer attributes from the original to
  the new file as soon as the new file is created; create a .augsave file
  as a hardlink, not by renaming
* src/transform.c(file_replace): pull out the code to transfer attributes
  into new function transfer_file_attrs; rename of new file to original is
  now done in transform_save
---
 src/transform.c |   88 +++++++++++++++++++++++++++---------------------------
 1 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/src/transform.c b/src/transform.c
index 44d99be..e216a6b 100644
--- a/src/transform.c
+++ b/src/transform.c
@@ -411,48 +411,39 @@ int transform_applies(struct transform *xform, const char *path) {
     return filter_matches(xform->filter, path + strlen(AUGEAS_FILES_TREE));
 }
 
-static int file_replace(const char *from, const char *to, int to_exists,
-                        const char **err_status) {
+static int transfer_file_attrs(const char *from, const char *to,
+                               const char **err_status) {
     struct stat st;
     int ret = 0;
     int selinux_enabled = (is_selinux_enabled() > 0);
     security_context_t con = NULL;
 
-    if (to_exists) {
-        ret = lstat(to, &st);
-        if (lstat(to, &st) != 0) {
-            *err_status = "replace_stat";
+    ret = lstat(from, &st);
+    if (ret < 0) {
+        *err_status = "replace_stat";
+        return -1;
+    }
+    if (selinux_enabled) {
+        if (lgetfilecon(from, &con) < 0) {
+            *err_status = "replace_getfilecon";
             return -1;
         }
-        if (selinux_enabled) {
-            if (lgetfilecon(to, &con) < 0) {
-                *err_status = "replace_getfscreatecon";
-                return -1;
-            }
-        }
     }
 
-    if (rename(from, to) != 0) {
-        *err_status = "rename_augnew";
+    if (lchown(to, st.st_uid, st.st_gid) < 0) {
+        *err_status = "replace_chown";
         return -1;
     }
-
-    if (to_exists) {
-        if (lchown(to, st.st_uid, st.st_gid) != 0) {
-            *err_status = "replace_chown";
-            return -1;
-        }
-        if (chmod(to, st.st_mode) != 0) {
-            *err_status = "replace_chmod";
+    if (chmod(to, st.st_mode) < 0) {
+        *err_status = "replace_chmod";
+        return -1;
+    }
+    if (selinux_enabled && con != NULL) {
+        if (lsetfilecon(to, con) < 0) {
+            *err_status = "replace_setfilecon";
             return -1;
         }
-        if (selinux_enabled && con != NULL) {
-            if (lsetfilecon(to, con) < 0) {
-                *err_status = "replace_setfilecon";
-                return -1;
-            }
-            freecon(con);
-        }
+        freecon(con);
     }
     return 0;
 }
@@ -499,6 +490,22 @@ int transform_save(struct augeas *aug, struct transform *xform,
         goto done;
     }
 
+    augorig_canon = canonicalize_file_name(augorig);
+    augorig_exists = 1;
+    if (augorig_canon == NULL) {
+        if (errno == ENOENT) {
+            augorig_canon = augorig;
+            augorig_exists = 0;
+        } else {
+            err_status = "canon_augorig";
+            goto done;
+        }
+    }
+    if (augorig_exists) {
+        if (transfer_file_attrs(augorig_canon, augnew, &err_status) != 0)
+            goto done;
+    }
+
     if (tree != NULL)
         lns_put(fp, xform->lens, tree->children, text, &err);
     // FIXME: Delete file if tree == NULL
@@ -530,18 +537,6 @@ int transform_save(struct augeas *aug, struct transform *xform,
     }
 
     if (!(aug->flags & AUG_SAVE_NEWFILE)) {
-        augorig_canon = canonicalize_file_name(augorig);
-        augorig_exists = 1;
-        if (augorig_canon == NULL) {
-            if (errno == ENOENT) {
-                augorig_canon = augorig;
-                augorig_exists = 0;
-            } else {
-                err_status = "canon_augorig";
-                goto done;
-            }
-        }
-
         if (aug->flags & AUG_SAVE_BACKUP) {
             int r;
             r = asprintf(&augsave, "%s%s" EXT_AUGSAVE, aug->root, filename);
@@ -550,14 +545,19 @@ int transform_save(struct augeas *aug, struct transform *xform,
                 goto done;
             }
 
-            if (rename(augorig_canon, augsave) != 0) {
+            /* We do an unlink + link on AUGSAVE rather than a rename so that
+               we never have any point in time where augorig_canon does
+               not exist. */
+            unlink(augsave);   /* Return value ignored intentionally */
+            if (link(augorig_canon, augsave) != 0) {
                 err_status = "rename_augsave";
                 goto done;
             }
         }
-        if (file_replace(augnew, augorig_canon,
-                         augorig_exists, &err_status) != 0)
+        if (rename(augnew, augorig_canon) != 0) {
+            err_status = "rename_augnew";
             goto done;
+        }
     }
     result = 1;
 
-- 
1.5.6.5




More information about the augeas-devel mailing list