diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-04-07 05:39:44 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-04-08 05:08:51 +0900 |
commit | 6808e00463661322553ae0756ad9e3a486d0cc61 (patch) | |
tree | 2697a0c04b741b95a07bab445d5140b5822a4c93 | |
parent | a5af5f80ca53ccc3896d107de99c3b9fd1508d0b (diff) | |
download | systemd-6808e00463661322553ae0756ad9e3a486d0cc61.tar.gz |
path-util: introduce path_compare_filename()
-rw-r--r-- | src/basic/path-util.c | 40 | ||||
-rw-r--r-- | src/basic/path-util.h | 9 | ||||
-rw-r--r-- | src/test/test-path-util.c | 54 |
3 files changed, 79 insertions, 24 deletions
diff --git a/src/basic/path-util.c b/src/basic/path-util.c index ae0b25d155..a5ab6045cd 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -491,25 +491,33 @@ bool path_equal_or_files_same(const char *a, const char *b, int flags) { return path_equal(a, b) || files_same(a, b, flags) > 0; } -bool path_equal_filename(const char *a, const char *b) { - _cleanup_free_ char *a_basename = NULL, *b_basename = NULL; - int r; +int path_compare_filename(const char *a, const char *b) { + _cleanup_free_ char *fa = NULL, *fb = NULL; + int r, j, k; - assert(a); - assert(b); + /* Order NULL before non-NULL */ + r = CMP(!!a, !!b); + if (r != 0) + return r; - r = path_extract_filename(a, &a_basename); - if (r < 0) { - log_debug_errno(r, "Failed to parse basename of %s: %m", a); - return false; - } - r = path_extract_filename(b, &b_basename); - if (r < 0) { - log_debug_errno(r, "Failed to parse basename of %s: %m", b); - return false; - } + j = path_extract_filename(a, &fa); + k = path_extract_filename(b, &fb); + + /* When one of paths is "." or root, then order it earlier. */ + r = CMP(j != -EADDRNOTAVAIL, k != -EADDRNOTAVAIL); + if (r != 0) + return r; + + /* When one of paths is invalid (or we get OOM), order invalid path after valid one. */ + r = CMP(j < 0, k < 0); + if (r != 0) + return r; + + /* fallback to use strcmp() if both paths are invalid. */ + if (j < 0) + return strcmp(a, b); - return path_equal(a_basename, b_basename); + return strcmp(fa, fb); } char* path_extend_internal(char **x, ...) { diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 56f01f41d8..7843599816 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -66,15 +66,18 @@ char *path_startswith_full(const char *path, const char *prefix, bool accept_dot 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_; +int path_compare(const char *a, const char *b) _pure_; static inline bool path_equal(const char *a, const char *b) { return path_compare(a, b) == 0; } +int path_compare_filename(const char *a, const char *b); +static inline bool path_equal_filename(const char *a, const char *b) { + return path_compare_filename(a, b) == 0; +} + bool path_equal_or_files_same(const char *a, const char *b, int flags); -/* Compares only the last portion of the input paths, ie: the filenames */ -bool path_equal_filename(const char *a, const char *b); char* path_extend_internal(char **x, ...); #define path_extend(x, ...) path_extend_internal(x, __VA_ARGS__, POINTER_MAX) diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 136005d51f..87e33919e0 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -46,11 +46,6 @@ TEST(path) { assert_se(!path_equal_ptr("/a", "/b")); assert_se(!path_equal_ptr("/a", NULL)); assert_se(!path_equal_ptr(NULL, "/a")); - - assert_se(path_equal_filename("/a/c", "/b/c")); - assert_se(path_equal_filename("/a", "/a")); - assert_se(!path_equal_filename("/a/b", "/a/c")); - assert_se(!path_equal_filename("/b", "/c")); } static void test_path_simplify_one(const char *in, const char *out) { @@ -150,6 +145,55 @@ TEST(path_compare) { test_path_compare_one("/foo/a/b", "/foo/aaa", -1); } +static void test_path_compare_filename_one(const char *a, const char *b, int expected) { + int r; + + assert_se(path_compare_filename(a, a) == 0); + assert_se(path_compare_filename(b, b) == 0); + + r = path_compare_filename(a, b); + assert_se((r > 0) == (expected > 0) && (r < 0) == (expected < 0)); + r = path_compare_filename(b, a); + assert_se((r < 0) == (expected > 0) && (r > 0) == (expected < 0)); + + assert_se(path_equal_filename(a, a) == 1); + assert_se(path_equal_filename(b, b) == 1); + assert_se(path_equal_filename(a, b) == (expected == 0)); + assert_se(path_equal_filename(b, a) == (expected == 0)); +} + +TEST(path_compare_filename) { + test_path_compare_filename_one("/goo", "/goo", 0); + test_path_compare_filename_one("/goo", "/goo", 0); + test_path_compare_filename_one("//goo", "/goo", 0); + test_path_compare_filename_one("//goo/////", "/goo", 0); + test_path_compare_filename_one("goo/////", "goo", 0); + test_path_compare_filename_one("/goo/boo", "/goo//boo", 0); + test_path_compare_filename_one("//goo/boo", "/goo/boo//", 0); + test_path_compare_filename_one("//goo/././//./boo//././//", "/goo/boo//.", 0); + test_path_compare_filename_one("/.", "//.///", -1); + test_path_compare_filename_one("/x", "x/", 0); + test_path_compare_filename_one("x/", "/", 1); + test_path_compare_filename_one("/x/./y", "x/y", 0); + test_path_compare_filename_one("/x/./y", "/x/y", 0); + test_path_compare_filename_one("/x/./././y", "/x/y/././.", 0); + test_path_compare_filename_one("./x/./././y", "./x/y/././.", 0); + test_path_compare_filename_one(".", "./.", -1); + test_path_compare_filename_one(".", "././.", -1); + test_path_compare_filename_one("./..", ".", 1); + test_path_compare_filename_one("x/.y", "x/y", -1); + test_path_compare_filename_one("foo", "/foo", 0); + test_path_compare_filename_one("/foo", "/foo/bar", 1); + test_path_compare_filename_one("/foo/aaa", "/foo/b", -1); + test_path_compare_filename_one("/foo/aaa", "/foo/b/a", 1); + test_path_compare_filename_one("/foo/a", "/foo/aaa", -1); + test_path_compare_filename_one("/foo/a/b", "/foo/aaa", 1); + test_path_compare_filename_one("/a/c", "/b/c", 0); + test_path_compare_filename_one("/a", "/a", 0); + test_path_compare_filename_one("/a/b", "/a/c", -1); + test_path_compare_filename_one("/b", "/c", -1); +} + TEST(path_equal_root) { /* Nail down the details of how path_equal("/", ...) works. */ |