Blob Blame History Raw
From 361adbf9e520d695ae13efe6084cbcdebe4779e2 Mon Sep 17 00:00:00 2001
From: Dominic Cleal <dcleal@redhat.com>
Date: Tue, 19 Nov 2013 09:39:23 +0000
Subject: [PATCH] * src/transform.c (filter_matches): wrap fnmatch to ensure
 that an incl   pattern containing "//" matches file paths

Fixes RHBZ#1031084
---
 src/transform.c   | 38 ++++++++++++++++++++++++++++++++++----
 tests/test-save.c | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/src/transform.c b/src/transform.c
index 1ee8da8..ccbe422 100644
--- a/src/transform.c
+++ b/src/transform.c
@@ -142,6 +142,33 @@ static char *mtime_as_string(struct augeas *aug, const char *fname) {
     return NULL;
 }
 
+/* fnmatch(3) which will match // in a pattern to a path, like glob(3) does */
+static int fnmatch_normalize(const char *pattern, const char *string, int flags) {
+    int i, j, r;
+    char *pattern_norm = NULL;
+
+    r = ALLOC_N(pattern_norm, strlen(pattern) + 1);
+    if (r < 0)
+        goto error;
+
+    for (i = 0, j = 0; i < strlen(pattern); i++) {
+        if (pattern[i] != '/' || pattern[i+1] != '/') {
+            pattern_norm[j] = pattern[i];
+            j++;
+        }
+    }
+    pattern_norm[j] = 0;
+
+    r = fnmatch(pattern_norm, string, flags);
+    FREE(pattern_norm);
+    return r;
+
+ error:
+    if (pattern_norm != NULL)
+        FREE(pattern_norm);
+    return -1;
+}
+
 static bool file_current(struct augeas *aug, const char *fname,
                          struct tree *finfo) {
     struct tree *mtime = tree_child(finfo, s_mtime);
@@ -217,9 +244,12 @@ static int filter_generate(struct tree *xfm, const char *root,
 
             if (strchr(e->value, SEP) == NULL)
                 path = pathbase(path);
-            if ((r = fnmatch(e->value, path, fnm_flags)) == 0) {
+
+            r = fnmatch_normalize(e->value, path, fnm_flags);
+            if (r < 0)
+                goto error;
+            else if (r == 0)
                 include = false;
-            }
         }
 
         if (include)
@@ -254,7 +284,7 @@ static int filter_generate(struct tree *xfm, const char *root,
 static int filter_matches(struct tree *xfm, const char *path) {
     int found = 0;
     list_for_each(f, xfm->children) {
-        if (is_incl(f) && fnmatch(f->value, path, fnm_flags) == 0) {
+        if (is_incl(f) && fnmatch_normalize(f->value, path, fnm_flags) == 0) {
             found = 1;
             break;
         }
@@ -262,7 +292,7 @@ static int filter_matches(struct tree *xfm, const char *path) {
     if (! found)
         return 0;
     list_for_each(f, xfm->children) {
-        if (is_excl(f) && (fnmatch(f->value, path, fnm_flags) == 0))
+        if (is_excl(f) && (fnmatch_normalize(f->value, path, fnm_flags) == 0))
             return 0;
     }
     return 1;
diff --git a/tests/test-save.c b/tests/test-save.c
index 04b86f7..617ef31 100644
--- a/tests/test-save.c
+++ b/tests/test-save.c
@@ -183,6 +183,44 @@ static void testRelPath(CuTest *tc) {
     CuAssertIntEquals(tc, 1, r);
 }
 
+/* Check that loading and saving a file with // in the incl pattern works.
+ * RHBZ#1031084
+ */
+static void testDoubleSlashPath(CuTest *tc) {
+    int r;
+
+    r = aug_rm(aug, "/augeas/load/*");
+    CuAssertPositive(tc, r);
+
+    r = aug_set(aug, "/augeas/load/Hosts/lens", "Hosts.lns");
+    CuAssertRetSuccess(tc, r);
+    r = aug_set(aug, "/augeas/load/Hosts/incl", "/etc//hosts");
+    CuAssertRetSuccess(tc, r);
+    r = aug_load(aug);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_match(aug, "/files/etc/hosts/1/alias[ . = 'new']", NULL);
+    CuAssertIntEquals(tc, 0, r);
+
+    r = aug_set(aug, "/files/etc/hosts/1/alias[last() + 1]", "new");
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_save(aug);
+    CuAssertRetSuccess(tc, r);
+    r = aug_match(aug, "/augeas//error", NULL);
+    CuAssertIntEquals(tc, 0, r);
+
+    /* Force reloading the file */
+    r = aug_rm(aug, "/augeas/files//mtime");
+    CuAssertPositive(tc, r);
+
+    r = aug_load(aug);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_match(aug, "/files/etc/hosts/1/alias[. = 'new']", NULL);
+    CuAssertIntEquals(tc, 1, r);
+}
+
 int main(void) {
     char *output = NULL;
     CuSuite* suite = CuSuiteNew();
@@ -206,6 +244,7 @@ int main(void) {
     SUITE_ADD_TEST(suite, testMultipleXfm);
     SUITE_ADD_TEST(suite, testMtime);
     SUITE_ADD_TEST(suite, testRelPath);
+    SUITE_ADD_TEST(suite, testDoubleSlashPath);
 
     CuSuiteRun(suite);
     CuSuiteSummary(suite, &output);
-- 
1.8.3.1