[libvirt] [dbus PATCH] util: Introduce virtDBusUtil(En|De)codeStr helpers

Pavel Hrdina phrdina at redhat.com
Mon Jun 11 14:21:47 UTC 2018


D-Bus object path element can contain only [a-zA-Z0-9_] characters so
we need to encode existing unique IDs.  In case of UUID it's simple, we
just change '-' into '_' but in case of storage volumes we need to use
'key' which is arbitrary string.

This helpers encode the string using this algorithm:

    [a-zA-Z0-9]         >       [a-zA-Z0-9]
    anything else       >       _XX where XX is hex representation

Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
---
 .gitignore        |  4 ++-
 src/util.c        | 64 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util.h        |  6 +++++
 tests/Makefile.am | 20 +++++++++++++++
 tests/test_util.c | 47 ++++++++++++++++++++++++++++++++++
 5 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 tests/test_util.c

diff --git a/.gitignore b/.gitignore
index 0bf09cf..c5e16a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 *Makefile
 *Makefile.in
 *~
+.deps
 __pycache__
 vgcore.*
 
@@ -31,6 +32,7 @@ vgcore.*
 
 /docs/*.1
 
-/src/.deps/
 /src/libvirt-dbus
 /src/org.libvirt.service
+
+/tests/test_util
diff --git a/src/util.c b/src/util.c
index 53dbc57..1268736 100644
--- a/src/util.c
+++ b/src/util.c
@@ -181,6 +181,70 @@ virtDBusUtilDecodeUUID(const gchar *uuid)
     return g_strdelimit(ret, "_", '-');
 }
 
+static guchar
+virtDBusUtilNumToHexchar(const guchar c)
+{
+    if (c < 10)
+        return '0' + c;
+    return 'a' + (c & 0x0f) - 10;
+}
+
+static guchar
+virtDBusUtilHexcharToNum(const guchar c)
+{
+    if (c >= 'a')
+        return 10 + c - 'a';
+    return c - '0';
+}
+
+gchar *
+virtDBusUtilEncodeStr(const gchar *str)
+{
+    gint len = strlen(str);
+    gint j = 0;
+    gchar *ret = g_new(gchar, len * 3 + 1);
+
+    for (gint i = 0; i < len; i++) {
+        guchar c = str[i];
+        if ((c >= 'A' && c <= 'Z') ||
+            (c >= 'a' && c <= 'z') ||
+            (c >= '0' && c <= '9')) {
+            ret[j++] = c;
+        } else {
+            ret[j] = '_';
+            ret[j + 1] = virtDBusUtilNumToHexchar(c >> 4);
+            ret[j + 2] = virtDBusUtilNumToHexchar(c);
+            j += 3;
+        }
+    }
+    ret[j] = 0;
+
+    return ret;
+}
+
+gchar *
+virtDBusUtilDecodeStr(const gchar *str)
+{
+    gint len = strlen(str);
+    gint j = 0;
+    gchar *ret = g_new(gchar, len + 1);
+
+    for (gint i = 0; i < len; i++) {
+        gchar c = str[i];
+        if (c != '_' || (i + 2) >= len) {
+            ret[j++] = c;
+        } else {
+            guchar a = virtDBusUtilHexcharToNum(str[i + 1]);
+            guchar b = virtDBusUtilHexcharToNum(str[i + 2]);
+            ret[j++] = (a << 4) + b;
+            i += 2;
+        }
+    }
+    ret[j] = 0;
+
+    return ret;
+}
+
 gchar *
 virtDBusUtilBusPathForVirDomain(virDomainPtr domain,
                                 const gchar *domainPath)
diff --git a/src/util.h b/src/util.h
index 4d87549..56e0409 100644
--- a/src/util.h
+++ b/src/util.h
@@ -42,6 +42,12 @@ virtDBusUtilGVariantToTypedParams(GVariantIter *iter,
 void
 virtDBusUtilSetLastVirtError(GError **error);
 
+gchar *
+virtDBusUtilEncodeStr(const gchar *str);
+
+gchar *
+virtDBusUtilDecodeStr(const gchar *str);
+
 gchar *
 virtDBusUtilBusPathForVirDomain(virDomainPtr domain,
                                 const gchar *domainPath);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5e224f8..4cae303 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,11 +3,31 @@ test_helpers = \
 	conftest.py
 
 test_programs = \
+	$(check_PROGRAMS) \
 	test_connect.py \
 	test_domain.py \
 	test_network.py \
 	test_storage.py
 
+check_PROGRAMS = \
+	test_util
+
+test_util_SOURCES = \
+	test_util.c $(top_srcdir)/src/util.c
+test_util_CFLAGS = \
+	-I$(top_srcdir)/src \
+	$(GIO2_CFLAGS) \
+	$(GLIB2_CFLAGS) \
+	$(LIBVIRT_CFLAGS)
+test_util_LDFLAGS = \
+	$(GIO2_LDFLAGS) \
+	$(GLIB2_LDFLAGS) \
+	$(LIBVIRT_LDFLAGS)
+test_util_LDADD = \
+	$(GIO2_LIBS) \
+	$(GLIB2_LIBS) \
+	$(LIBVIRT_LIBS)
+
 EXTRA_DIST = \
 	$(test_helpers) \
 	$(test_programs) \
diff --git a/tests/test_util.c b/tests/test_util.c
new file mode 100644
index 0000000..9611192
--- /dev/null
+++ b/tests/test_util.c
@@ -0,0 +1,47 @@
+#include "util.h"
+
+static gint
+virtTestEncodeStr(const gchar *input,
+                  const gchar *expected)
+{
+    g_autofree gchar *encoded = virtDBusUtilEncodeStr(input);
+
+    if (!g_str_equal(encoded, expected)) {
+        g_printerr("encode failed: expected '%s' actual '%s'\n",
+                   expected, encoded);
+        return -1;
+    }
+
+    return 0;
+}
+
+static gint
+virtTestDecodeStr(const gchar *input,
+                  const gchar *expected)
+{
+    g_autofree gchar *decoded = virtDBusUtilDecodeStr(input);
+
+    if (!g_str_equal(decoded, expected)) {
+        g_printerr("decode failed: expected '%s' actual '%s'\n",
+                   expected, decoded);
+        return -1;
+    }
+
+    return 0;
+}
+
+gint
+main(void)
+{
+#define TEST_ENCODE_DECODE(input, output) \
+    if (virtTestEncodeStr(input, output) < 0) \
+        return EXIT_FAILURE; \
+    if (virtTestDecodeStr(output, input) < 0) \
+        return EXIT_FAILURE;
+
+    TEST_ENCODE_DECODE("foobar", "foobar");
+    TEST_ENCODE_DECODE("_", "_5f");
+    TEST_ENCODE_DECODE("/path/to/some/file.img", "_2fpath_2fto_2fsome_2ffile_2eimg");
+
+    return EXIT_SUCCESS;
+}
-- 
2.17.1




More information about the libvir-list mailing list