From dd92ba8a7a69016116e14d309829efff1e3c3d34 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Mar 2024 23:17:11 +0100 Subject: [PATCH] path-util: add helper that checks if a path definitely refers to a dir --- src/basic/path-util.c | 14 ++++++++++++++ src/basic/path-util.h | 2 ++ src/test/test-path-util.c | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 6810bf66aa..05a21f8f8e 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -1336,6 +1336,20 @@ bool dot_or_dot_dot(const char *path) { return path[2] == 0; } +bool path_implies_directory(const char *path) { + + /* Sometimes, if we look at a path we already know it must refer to a directory, because it is + * suffixed with a slash, or its last component is "." or ".." */ + + if (!path) + return false; + + if (dot_or_dot_dot(path)) + return true; + + return ENDSWITH_SET(path, "/", "/.", "/.."); +} + bool empty_or_root(const char *path) { /* For operations relative to some root directory, returns true if the specified root directory is diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 39b6714525..052bbd7031 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -201,6 +201,8 @@ bool valid_device_allow_pattern(const char *path); bool dot_or_dot_dot(const char *path); +bool path_implies_directory(const char *path); + static inline const char *skip_dev_prefix(const char *p) { const char *e; diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index f5a425689a..ca11bf3a29 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -1305,4 +1305,28 @@ TEST(print_MAX) { assert_cc(FILENAME_MAX == PATH_MAX); } +TEST(path_implies_directory) { + assert_se(!path_implies_directory(NULL)); + assert_se(!path_implies_directory("")); + assert_se(path_implies_directory("/")); + assert_se(path_implies_directory("////")); + assert_se(path_implies_directory("////.///")); + assert_se(path_implies_directory("////./")); + assert_se(path_implies_directory("////.")); + assert_se(path_implies_directory(".")); + assert_se(path_implies_directory("./")); + assert_se(path_implies_directory("/.")); + assert_se(path_implies_directory("..")); + assert_se(path_implies_directory("../")); + assert_se(path_implies_directory("/..")); + assert_se(!path_implies_directory("a")); + assert_se(!path_implies_directory("ab")); + assert_se(path_implies_directory("ab/")); + assert_se(!path_implies_directory("ab/a")); + assert_se(path_implies_directory("ab/a/")); + assert_se(path_implies_directory("ab/a/..")); + assert_se(path_implies_directory("ab/a/.")); + assert_se(path_implies_directory("ab/a//")); +} + DEFINE_TEST_MAIN(LOG_DEBUG); -- 2.25.1