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@xxxxxxxxxx> --- .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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list