]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
path-util: use path_find_first_component() in path_startswith()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 1 May 2021 11:17:16 +0000 (20:17 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 28 May 2021 04:41:23 +0000 (13:41 +0900)
This makes path_startswith() stricter. If one of the path component in
arguments is longer than NAME_MAX, it returns NULL.

src/basic/path-util.c
src/basic/path-util.h
src/test/test-path-util.c

index 4b83232df882fd7796203b5c97add7be2a131fb0..aa65e2950fb06068d48016f80939a5566d3a3b17 100644 (file)
@@ -430,7 +430,7 @@ int path_simplify_and_warn(
         return 0;
 }
 
-char* path_startswith(const char *path, const char *prefix) {
+char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
         assert(path);
         assert(prefix);
 
@@ -448,28 +448,25 @@ char* path_startswith(const char *path, const char *prefix) {
                 return NULL;
 
         for (;;) {
-                size_t a, b;
-
-                path += strspn(path, "/");
-                prefix += strspn(prefix, "/");
+                const char *p, *q;
+                int r, k;
 
-                if (*prefix == 0)
-                        return (char*) path;
+                r = path_find_first_component(&path, accept_dot_dot, &p);
+                if (r < 0)
+                        return NULL;
 
-                if (*path == 0)
+                k = path_find_first_component(&prefix, accept_dot_dot, &q);
+                if (k < 0)
                         return NULL;
 
-                a = strcspn(path, "/");
-                b = strcspn(prefix, "/");
+                if (k == 0)
+                        return (char*) (p ?: path);
 
-                if (a != b)
+                if (r != k)
                         return NULL;
 
-                if (memcmp(path, prefix, a) != 0)
+                if (!strneq(p, q, r))
                         return NULL;
-
-                path += a;
-                prefix += b;
         }
 }
 
index 52ceb9b5a955696924ecc0c45dd401d7bbf90339..50a7b021a49330a82d06bfa7f99bf48c53b51166 100644 (file)
@@ -57,7 +57,10 @@ char* path_make_absolute(const char *p, const char *prefix);
 int safe_getcwd(char **ret);
 int path_make_absolute_cwd(const char *p, char **ret);
 int path_make_relative(const char *from_dir, const char *to_path, char **_r);
-char* path_startswith(const char *path, const char *prefix) _pure_;
+char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
+static inline char* path_startswith(const char *path, const char *prefix) {
+        return path_startswith_full(path, prefix, true);
+}
 int path_compare(const char *a, const char *b) _pure_;
 bool path_equal(const char *a, const char *b) _pure_;
 bool path_equal_or_files_same(const char *a, const char *b, int flags);
index c68603fc9bab34589bd9bcba67ff3d44308f71fd..49a547422e626fdae1207d12ed84915eb951c95b 100644 (file)
@@ -473,49 +473,42 @@ static void test_strv_resolve(void) {
         assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
 }
 
-static void test_path_startswith(void) {
-        const char *p;
-
-        log_info("/* %s */", __func__);
-
-        p = path_startswith("/foo/bar/barfoo/", "/foo");
-        assert_se(streq_ptr(p, "bar/barfoo/"));
-
-        p = path_startswith("/foo/bar/barfoo/", "/foo/");
-        assert_se(streq_ptr(p, "bar/barfoo/"));
-
-        p = path_startswith("/foo/bar/barfoo/", "/");
-        assert_se(streq_ptr(p, "foo/bar/barfoo/"));
-
-        p = path_startswith("/foo/bar/barfoo/", "////");
-        assert_se(streq_ptr(p, "foo/bar/barfoo/"));
+static void test_path_startswith_one(const char *path, const char *prefix, const char *skipped, const char *expected) {
+        const char *p, *q;
 
-        p = path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///");
-        assert_se(streq_ptr(p, ""));
+        log_debug("/* %s(%s, %s) */", __func__, path, prefix);
 
-        p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////");
-        assert_se(streq_ptr(p, ""));
-
-        p = path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/");
-        assert_se(streq_ptr(p, ""));
-
-        p = path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/");
-        assert_se(streq_ptr(p, ""));
-
-        p = path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/");
-        assert_se(streq_ptr(p, ""));
+        p = path_startswith(path, prefix);
+        assert_se(streq_ptr(p, expected));
+        if (p) {
+                q = strjoina(skipped, p);
+                assert_se(streq(q, path));
+                assert_se(p == path + strlen(skipped));
+        }
+}
 
-        p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo");
-        assert_se(streq_ptr(p, ""));
+static void test_path_startswith(void) {
+        log_info("/* %s */", __func__);
 
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
-        assert_se(!path_startswith("/foo/bar/barfoo/", ""));
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo"));
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/bar"));
-        assert_se(!path_startswith("/foo/bar/barfoo/", "/fo"));
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo", "/foo/", "bar/barfoo/");
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/", "/foo/", "bar/barfoo/");
+        test_path_startswith_one("/foo/bar/barfoo/", "/", "/", "foo/bar/barfoo/");
+        test_path_startswith_one("/foo/bar/barfoo/", "////", "/",  "foo/bar/barfoo/");
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo//bar/////barfoo///", "/foo/bar/barfoo/", "");
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfoo////", "/foo/bar/barfoo/", "");
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar///barfoo/", "/foo/bar/barfoo/", "");
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo////bar/barfoo/", "/foo/bar/barfoo/", "");
+        test_path_startswith_one("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", "");
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", "");
+
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "/bar/foo", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "/f/b/b/", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfo", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/bar", NULL, NULL);
+        test_path_startswith_one("/foo/bar/barfoo/", "/fo", NULL, NULL);
 }
 
 static void test_prefix_root_one(const char *r, const char *p, const char *expected) {