g_canonicalize_filename was not introduced until glib 2.58
so we need a temporary backport of its impl.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/glibcompat.c | 106 +++++++++++++++++++++++++++++++++++++++
src/util/glibcompat.h | 3 ++
3 files changed, 110 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 951ba7f0ca..bb2b461cea 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1504,6 +1504,7 @@ virSecurityManagerVerify;
# util/glibcompat.h
+vir_g_canonicalize_filename;
vir_g_fsync;
vir_g_strdup_printf;
vir_g_strdup_vprintf;
diff --git a/src/util/glibcompat.c b/src/util/glibcompat.c
index 42f9353c8f..c6390c5c2e 100644
--- a/src/util/glibcompat.c
+++ b/src/util/glibcompat.c
@@ -19,15 +19,121 @@
#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) */
+}
+
+
gint
vir_g_fsync(gint fd)
{
diff --git a/src/util/glibcompat.h b/src/util/glibcompat.h
index ce31a4de04..6f50a76f3c 100644
--- a/src/util/glibcompat.h
+++ b/src/util/glibcompat.h
@@ -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
--
2.24.1