]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: add compat impl of g_canonicalize_filename
authorDaniel P. Berrangé <berrange@redhat.com>
Mon, 6 Jan 2020 11:54:20 +0000 (11:54 +0000)
committerDaniel P. Berrangé <berrange@redhat.com>
Tue, 7 Jan 2020 14:42:26 +0000 (14:42 +0000)
g_canonicalize_filename was not introduced until glib 2.58
so we need a temporary backport of its impl.

Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
src/libvirt_private.syms
src/util/glibcompat.c
src/util/glibcompat.h

index 9185e49fda1751e12df72e0e7b2c0454bd87b1ee..d8f049b96097872356a0c61350269c011d4ef253 100644 (file)
@@ -1504,6 +1504,7 @@ virSecurityManagerVerify;
 
 
 # util/glibcompat.h
+vir_g_canonicalize_filename;
 vir_g_fsync;
 vir_g_strdup_printf;
 vir_g_strdup_vprintf;
index 049ac587caff89dd3d66adf5c658e27ccec47f59..c61772f953f4f6c7d2295c91e500d4c5682d63fb 100644 (file)
 #include <config.h>
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include "glibcompat.h"
 
+#undef g_canonicalize_filename
 #undef g_fsync
 #undef g_strdup_printf
 #undef g_strdup_vprintf
 
 
+gchar *
+vir_g_canonicalize_filename(const gchar *filename,
+                            const gchar *relative_to)
+{
+#if GLIB_CHECK_VERSION(2, 58, 0)
+    return g_canonicalize_filename(filename, relative_to);
+#else /* ! GLIB_CHECK_VERSION(2, 58, 0) */
+    gchar *canon, *start, *p, *q;
+    guint i;
+
+    g_return_val_if_fail(relative_to == NULL || g_path_is_absolute(relative_to), NULL);
+
+    if (!g_path_is_absolute(filename)) {
+        gchar *cwd_allocated = NULL;
+        const gchar  *cwd;
+
+        if (relative_to != NULL)
+            cwd = relative_to;
+        else
+            cwd = cwd_allocated = g_get_current_dir();
+
+        canon = g_build_filename(cwd, filename, NULL);
+        g_free(cwd_allocated);
+    } else {
+        canon = g_strdup(filename);
+    }
+
+    start = (char *)g_path_skip_root(canon);
+
+    if (start == NULL) {
+        /* This shouldn't really happen, as g_get_current_dir() should
+           return an absolute pathname, but bug 573843 shows this is
+           not always happening */
+        g_free(canon);
+        return g_build_filename(G_DIR_SEPARATOR_S, filename, NULL);
+    }
+
+    /* POSIX allows double slashes at the start to
+     * mean something special (as does windows too).
+     * So, "//" != "/", but more than two slashes
+     * is treated as "/".
+     */
+    i = 0;
+    for (p = start - 1;
+         (p >= canon) &&
+             G_IS_DIR_SEPARATOR(*p);
+         p--)
+        i++;
+    if (i > 2) {
+        i -= 1;
+        start -= i;
+        memmove(start, start+i, strlen(start+i) + 1);
+    }
+
+    /* Make sure we're using the canonical dir separator */
+    p++;
+    while (p < start && G_IS_DIR_SEPARATOR(*p))
+        *p++ = G_DIR_SEPARATOR;
+
+    p = start;
+    while (*p != 0) {
+        if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR(p[1]))) {
+            memmove(p, p+1, strlen(p+1)+1);
+        } else if (p[0] == '.' && p[1] == '.' &&
+                   (p[2] == 0 || G_IS_DIR_SEPARATOR(p[2]))) {
+            q = p + 2;
+            /* Skip previous separator */
+            p = p - 2;
+            if (p < start)
+                p = start;
+            while (p > start && !G_IS_DIR_SEPARATOR(*p))
+                p--;
+            if (G_IS_DIR_SEPARATOR(*p))
+                *p++ = G_DIR_SEPARATOR;
+            memmove(p, q, strlen(q)+1);
+        } else {
+            /* Skip until next separator */
+            while (*p != 0 && !G_IS_DIR_SEPARATOR(*p))
+                p++;
+
+            if (*p != 0) {
+                /* Canonicalize one separator */
+                *p++ = G_DIR_SEPARATOR;
+            }
+        }
+
+        /* Remove additional separators */
+        q = p;
+        while (*q && G_IS_DIR_SEPARATOR(*q))
+            q++;
+
+        if (p != q)
+            memmove(p, q, strlen(q) + 1);
+    }
+
+    /* Remove trailing slashes */
+    if (p > start && G_IS_DIR_SEPARATOR(*(p-1)))
+        *(p-1) = 0;
+
+    return canon;
+#endif /* ! GLIB_CHECK_VERSION(2, 58, 0) */
+}
+
+
 /* Drop when min glib >= 2.63.0 */
 gint
 vir_g_fsync(gint fd)
index ce31a4de0432768432a4dcac2c4e57fe16fae8dc..6f50a76f3c2b86911d5e16d2d6675b68ab342ad4 100644 (file)
@@ -21,6 +21,8 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 
+gchar * vir_g_canonicalize_filename(const gchar *filename,
+                                    const gchar *relative_to);
 gint vir_g_fsync(gint fd);
 char *vir_g_strdup_printf(const char *msg, ...)
     G_GNUC_PRINTF(1, 2);
@@ -32,5 +34,6 @@ char *vir_g_strdup_vprintf(const char *msg, va_list args)
 # define g_strdup_vprintf vir_g_strdup_vprintf
 #endif
 
+#define g_canonicalize_filename vir_g_canonicalize_filename
 #undef g_fsync
 #define g_fsync vir_g_fsync