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(a)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
Show replies by date
On Mon, Jun 11, 2018 at 04:21:47PM +0200, Pavel Hrdina wrote:
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(a)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
Reviewed-by: Katerina Koukiou <kkoukiou(a)redhat.com>