[libvirt] [PATCHv3 17/36] util: storagefile: Add canonicalization to virStorageFileSimplifyPath

Peter Krempa pkrempa at redhat.com
Fri May 30 08:37:39 UTC 2014


The recently introduced virStorageFileSimplifyPath is good at resolving
relative portions of a path. To add full path canonicalization
capability we need to be able to resolve symlinks in the path too.

This patch adds a callback to that function so that arbitrary storage
systems can use this functionality.
---
 src/libvirt_private.syms  |  1 +
 src/util/virstoragefile.c | 82 +++++++++++++++++++++++++++++++++++++++++++++--
 src/util/virstoragefile.h |  9 ++++++
 tests/virstoragetest.c    | 80 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 170 insertions(+), 2 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 8e00d8c..7de04ed 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1872,6 +1872,7 @@ virStorageFileIsClusterFS;
 virStorageFileParseChainIndex;
 virStorageFileProbeFormat;
 virStorageFileResize;
+virStorageFileSimplifyPathInternal;
 virStorageIsFile;
 virStorageNetHostDefClear;
 virStorageNetHostDefCopy;
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index d8b4b54..301452e 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -1962,13 +1962,47 @@ virStorageFileExportPath(char **components,
 }


+static int
+virStorageFileExplodePath(const char *path,
+                          size_t at,
+                          char ***components,
+                          size_t *ncomponents)
+{
+    char **tmp = NULL;
+    char **next;
+    size_t ntmp = 0;
+    int ret = -1;
+
+    if (!(tmp = virStringSplitCount(path, "/", 0, &ntmp)))
+        goto cleanup;
+
+    /* prepend */
+    for (next = tmp; *next; next++) {
+        if (VIR_INSERT_ELEMENT(*components, at, *ncomponents, *next) < 0)
+            goto cleanup;
+
+        at++;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virStringFreeListCount(tmp, ntmp);
+    return ret;
+}
+
+
 char *
-virStorageFileSimplifyPath(const char *path,
-                           bool allow_relative)
+virStorageFileSimplifyPathInternal(const char *path,
+                                   bool allow_relative,
+                                   virStorageFileSimplifyPathReadlinkCallback cb,
+                                   void *cbdata)
 {
     bool beginSlash = false;
     char **components = NULL;
     size_t ncomponents = 0;
+    char *linkpath = NULL;
+    char *currentpath = NULL;
     size_t i;
     char *ret = NULL;

@@ -2012,6 +2046,40 @@ virStorageFileSimplifyPath(const char *path,
             continue;
         }

+        /* read link and stuff */
+        if (cb) {
+            int rc;
+            if (!(currentpath = virStorageFileExportPath(components, i + 1,
+                                                         beginSlash)))
+                goto cleanup;
+
+            if ((rc = cb(currentpath, &linkpath, cbdata)) < 0)
+                goto cleanup;
+
+            if (rc == 0) {
+                if (linkpath[0] == '/') {
+                    /* start from a clean slate */
+                    virStringFreeListCount(components, ncomponents);
+                    ncomponents = 0;
+                    components = NULL;
+                    beginSlash = true;
+                    i = 0;
+                } else {
+                    VIR_FREE(components[i]);
+                    VIR_DELETE_ELEMENT(components, i, ncomponents);
+                }
+
+                if (virStorageFileExplodePath(linkpath, i, &components,
+                                              &ncomponents) < 0)
+                    goto cleanup;
+
+                VIR_FREE(linkpath);
+                VIR_FREE(currentpath);
+
+                continue;
+            }
+        }
+
         i++;
     }

@@ -2019,11 +2087,21 @@ virStorageFileSimplifyPath(const char *path,

  cleanup:
     virStringFreeListCount(components, ncomponents);
+    VIR_FREE(linkpath);
+    VIR_FREE(currentpath);

     return ret;
 }


+char *
+virStorageFileSimplifyPath(const char *path,
+                           bool allow_relative)
+{
+    return virStorageFileSimplifyPathInternal(path, allow_relative, NULL, NULL);
+}
+
+
 int
 virStorageFileGetRelativeBackingPath(virStorageSourcePtr from,
                                      virStorageSourcePtr to,
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index cbac30b..70deaef 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -325,6 +325,15 @@ void virStorageSourceFree(virStorageSourcePtr def);
 void virStorageSourceClearBackingStore(virStorageSourcePtr def);
 virStorageSourcePtr virStorageSourceNewFromBacking(virStorageSourcePtr parent);

+typedef int
+(*virStorageFileSimplifyPathReadlinkCallback)(const char *path,
+                                              char **link,
+                                              void *data);
+char *virStorageFileSimplifyPathInternal(const char *path,
+                                         bool allow_relative,
+                                         virStorageFileSimplifyPathReadlinkCallback cb,
+                                         void *cbdata);
+
 char *virStorageFileSimplifyPath(const char *path,
                                  bool allow_relative);

diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c
index 80d73ca..771df0b 100644
--- a/tests/virstoragetest.c
+++ b/tests/virstoragetest.c
@@ -639,6 +639,72 @@ testPathRelative(const void *args)
 }


+struct testPathCanonicalizeData
+{
+    const char *path;
+    const char *expect;
+};
+
+static const char *testPathCanonicalizeSymlinks[][2] =
+{
+    {"/path/blah", "/other/path/huzah"},
+    {"/path/to/relative/symlink", "../../actual/file"},
+};
+
+static int
+testPathCanonicalizeReadlink(const char *path,
+                             char **link,
+                             void *data ATTRIBUTE_UNUSED)
+{
+    size_t i;
+
+    *link = NULL;
+
+    for (i = 0; i < ARRAY_CARDINALITY(testPathCanonicalizeSymlinks); i++) {
+        if (STREQ(path, testPathCanonicalizeSymlinks[i][0])) {
+            if (VIR_STRDUP(*link, testPathCanonicalizeSymlinks[i][1]) < 0)
+                return -1;
+
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+
+static int
+testPathCanonicalize(const void *args)
+{
+    const struct testPathCanonicalizeData *data = args;
+    char *canon = NULL;
+    int ret = -1;
+
+    if (!(canon = virStorageFileSimplifyPathInternal(data->path,
+                                                     false,
+                                                     testPathCanonicalizeReadlink,
+                                                     NULL))) {
+        fprintf(stderr, "path canonicalization failed\n");
+        goto cleanup;
+    }
+
+    if (STRNEQ_NULLABLE(data->expect, canon)) {
+        fprintf(stderr,
+                "path canonicalization of '%s' failed: expected '%s' got '%s'\n",
+                data->path, data->expect, canon);
+
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(canon);
+
+    return ret;
+}
+
+
 static int
 mymain(void)
 {
@@ -647,6 +713,7 @@ mymain(void)
     struct testChainData data;
     struct testPathSimplifyData data3;
     struct testPathRelativeBacking data4;
+    struct testPathCanonicalizeData data5;
     virStorageSourcePtr chain = NULL;

     /* Prep some files with qemu-img; if that is not found on PATH, or
@@ -1200,6 +1267,19 @@ mymain(void)
     TEST_RELATIVE_BACKING(7, backingchain[5], backingchain[7], "../../../below");
     TEST_RELATIVE_BACKING(8, backingchain[5], backingchain[8], "../../../a/little/more/upwards");

+#define TEST_PATH_CANONICALIZE(id, PATH, EXPECT)                            \
+    do {                                                                    \
+        data5.path = PATH;                                                  \
+        data5.expect = EXPECT;                                              \
+        if (virtTestRun("Path canonicalize " #id,                           \
+                        testPathCanonicalize, &data5) < 0)                  \
+            ret = -1;                                                       \
+    } while (0)
+
+    TEST_PATH_CANONICALIZE(1, "/some/full/path", "/some/full/path");
+    TEST_PATH_CANONICALIZE(2, "/path/blah", "/other/path/huzah");
+    TEST_PATH_CANONICALIZE(3, "/path/to/relative/symlink", "/path/actual/file");
+
  cleanup:
     /* Final cleanup */
     virStorageSourceFree(chain);
-- 
1.9.3




More information about the libvir-list mailing list