chiark / gitweb /
util: properly escape corner cases in bus_path_escape(), too
authorLennart Poettering <lennart@poettering.net>
Tue, 5 Mar 2013 18:58:32 +0000 (19:58 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 5 Mar 2013 19:05:46 +0000 (20:05 +0100)
This follows the suggestions from:

http://lists.freedesktop.org/archives/systemd-devel/2013-March/009363.html

src/shared/util.c
src/test/test-util.c

index e643cd3..b7ba7fb 100644 (file)
@@ -1325,16 +1325,24 @@ char *bus_path_escape(const char *s) {
         assert(s);
 
         /* Escapes all chars that D-Bus' object path cannot deal
-         * with. Can be reverse with bus_path_unescape() */
+         * with. Can be reverse with bus_path_unescape(). We special
+         * case the empty string. */
 
-        if (!(r = new(char, strlen(s)*3+1)))
+        if (*s == 0)
+                return strdup("_");
+
+        r = new(char, strlen(s)*3 + 1);
+        if (!r)
                 return NULL;
 
         for (f = s, t = r; *f; f++) {
 
+                /* Escape everything that is not a-zA-Z0-9. We also
+                 * escape 0-9 if it's the first character */
+
                 if (!(*f >= 'A' && *f <= 'Z') &&
                     !(*f >= 'a' && *f <= 'z') &&
-                    !(*f >= '0' && *f <= '9')) {
+                    !(f > s && *f >= '0' && *f <= '9')) {
                         *(t++) = '_';
                         *(t++) = hexchar(*f >> 4);
                         *(t++) = hexchar(*f);
@@ -1352,7 +1360,12 @@ char *bus_path_unescape(const char *f) {
 
         assert(f);
 
-        if (!(r = strdup(f)))
+        /* Special case for the empty string */
+        if (streq(f, "_"))
+                return strdup("");
+
+        r = new(char, strlen(f) + 1);
+        if (!r)
                 return NULL;
 
         for (t = r; *f; f++) {
index cb0af4f..789fc08 100644 (file)
@@ -261,6 +261,29 @@ static void test_memdup_multiply(void) {
         free(dup);
 }
 
+static void test_bus_path_escape_one(const char *a, const char *b) {
+        _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
+
+        assert_se(t = bus_path_escape(a));
+        assert_se(streq(t, b));
+
+        assert_se(x = bus_path_unescape(t));
+        assert_se(streq(a, x));
+
+        assert_se(y = bus_path_unescape(b));
+        assert_se(streq(a, y));
+}
+
+static void test_bus_path_escape(void) {
+        test_bus_path_escape_one("foo123bar", "foo123bar");
+        test_bus_path_escape_one("foo.bar", "foo_2ebar");
+        test_bus_path_escape_one("foo_2ebar", "foo_5f2ebar");
+        test_bus_path_escape_one("", "_");
+        test_bus_path_escape_one("_", "_5f");
+        test_bus_path_escape_one("1", "_31");
+        test_bus_path_escape_one(":1", "_3a1");
+}
+
 int main(int argc, char *argv[]) {
         test_streq_ptr();
         test_first_word();
@@ -282,6 +305,7 @@ int main(int argc, char *argv[]) {
         test_foreach_word_quoted();
         test_default_term_for_tty();
         test_memdup_multiply();
+        test_bus_path_escape();
 
         return 0;
 }