[augeas-devel] [PATCH] Canonicalize file names before writing

David Lutterkort dlutter at redhat.com
Mon Jul 21 21:50:39 UTC 2008


4 files changed, 55 insertions(+), 3 deletions(-)
bootstrap                 |    1 +
src/transform.c           |   12 ++++++++++--
tests/Makefile.am         |    3 ++-
tests/test-put-symlink.sh |   42 ++++++++++++++++++++++++++++++++++++++++++


# HG changeset patch
# User David Lutterkort <dlutter at redhat.com>
# Date 1216677032 25200
# Node ID f2e8ca33a64abc7b061b65667e0c1dfe8b4d02f5
# Parent  6f2f5289c94a304d686b13c7aa6778ddcedbbe7d
Canonicalize file names before writing

We used to clobber symlinks because writing a file consists of writing to
an intermediate .augnew file, and then moving that over the target file. To
keep target files that are symlinks intact, we now canonicalize the target
filename and then move the intermediate file to the canonicalized target
file.

diff -r 6f2f5289c94a -r f2e8ca33a64a bootstrap
--- a/bootstrap	Mon Jul 21 11:00:36 2008 -0700
+++ b/bootstrap	Mon Jul 21 14:50:32 2008 -0700
@@ -59,6 +59,7 @@
 
 modules='
 argz
+canonicalize-lgpl
 regex
 strndup
 '
diff -r 6f2f5289c94a -r f2e8ca33a64a src/transform.c
--- a/src/transform.c	Mon Jul 21 11:00:36 2008 -0700
+++ b/src/transform.c	Mon Jul 21 14:50:32 2008 -0700
@@ -384,6 +384,7 @@
                    const char *path, struct tree *tree) {
     FILE *fp = NULL;
     char *augnew = NULL, *augorig = NULL, *augsave = NULL;
+    char *augorig_canon = NULL;
     char *text = NULL;
     const char *filename = path + strlen(AUGEAS_FILES_TREE) + 1;
     const char *err_status = NULL;
@@ -433,6 +434,12 @@
     }
 
     if (!(aug->flags & AUG_SAVE_NEWFILE)) {
+        augorig_canon = canonicalize_file_name(augorig);
+        if (augorig_canon == NULL) {
+            err_status = "canon_augorig";
+            goto done;
+        }
+
         if (aug->flags & AUG_SAVE_BACKUP) {
             int r;
             r = asprintf(&augsave, "%s%s" EXT_AUGSAVE, aug->root, filename);
@@ -441,12 +448,12 @@
                 goto done;
             }
 
-            if (rename(augorig, augsave) != 0) {
+            if (rename(augorig_canon, augsave) != 0) {
                 err_status = "rename_augsave";
                 goto done;
             }
         }
-        if (rename(augnew, augorig) != 0) {
+        if (rename(augnew, augorig_canon) != 0) {
             err_status = "rename_augnew";
             goto done;
         }
@@ -458,6 +465,7 @@
     free(text);
     free(augnew);
     free(augorig);
+    free(augorig_canon);
     free(augsave);
     store_error(aug, filename, path, err_status, err);
     free_lns_error(err);
diff -r 6f2f5289c94a -r f2e8ca33a64a tests/Makefile.am
--- a/tests/Makefile.am	Mon Jul 21 11:00:36 2008 -0700
+++ b/tests/Makefile.am	Mon Jul 21 14:50:32 2008 -0700
@@ -9,7 +9,8 @@
 valgrind: fatest
 	libtool --mode=execute valgrind --quiet --leak-check=full ./fatest
 
-check_SCRIPTS=test-lenses.sh test-interpreter.sh test-get.sh
+check_SCRIPTS=test-lenses.sh test-interpreter.sh test-get.sh \
+              test-put-symlink.sh
 
 EXTRA_DIST=augtest $(AUGTESTS) root \
 	   $(check_SCRIPTS) modules
diff -r 6f2f5289c94a -r f2e8ca33a64a tests/test-put-symlink.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-put-symlink.sh	Mon Jul 21 14:50:32 2008 -0700
@@ -0,0 +1,42 @@
+#! /bin/sh
+
+# Test that we correctly preserve symlinks when saving a file
+
+ROOT=$abs_top_builddir/build/test-put-symlink
+HOSTS=$ROOT/etc/hosts
+REAL_HOSTS=$ROOT/other/hosts
+
+rm -rf $ROOT
+mkdir -p $(dirname $HOSTS)
+mkdir -p $(dirname $REAL_HOSTS)
+
+cat <<EOF > $REAL_HOSTS
+127.0.0.1 localhost
+EOF
+
+(cd $(dirname $HOSTS) && ln -s ../other/hosts $(basename $HOSTS))
+
+augtool -b -r $ROOT <<EOF
+set /files/etc/hosts/1/alias myhost
+save
+EOF
+
+HOSTS_AUGSAVE=${HOSTS}.augsave
+if [ ! -f $HOSTS_AGSAVE ] ; then
+    echo "Missing /etc/hosts.augsave"
+    exit 1
+fi
+if [ -h $HOSTS_AUGSAVE ] ; then
+    echo "The file /etc/hosts.augsave is a symlink"
+    exit 1
+fi
+if [ ! -h $HOSTS ] ; then
+    echo "/etc/hosts is not a symbolic link"
+    exit 1
+fi
+
+LINK=$(readlink $HOSTS)
+if [ "x$LINK" != "x../other/hosts" ] ; then
+    echo "/etc/hosts does not link to ../other/hosts"
+    exit 1
+fi




More information about the augeas-devel mailing list