path-util: move empty_or_root_to_null() from chase.c

And rename it to empty_or_root_harder_to_null(), as it also checks if
the input path effectively points to the root by calling path_is_root().
This also adds simple test cases for the function.
This commit is contained in:
Yu Watanabe
2025-06-28 20:55:11 +09:00
parent cdd3aba3df
commit 8ce463639a
4 changed files with 61 additions and 24 deletions

View File

@@ -565,27 +565,6 @@ chased_one:
return 0;
}
static int empty_or_root_to_null(const char **path) {
int r;
assert(path);
/* This nullifies the input path when the path is empty or points to "/". */
if (empty_or_root(*path)) {
*path = NULL;
return 0;
}
r = path_is_root(*path);
if (r < 0)
return r;
if (r > 0)
*path = NULL;
return 0;
}
int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, int *ret_fd) {
_cleanup_free_ char *root_abs = NULL, *absolute = NULL, *p = NULL;
_cleanup_close_ int fd = -EBADF, pfd = -EBADF;
@@ -596,7 +575,7 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path,
if (isempty(path))
return -EINVAL;
r = empty_or_root_to_null(&root);
r = empty_or_root_harder_to_null(&root);
if (r < 0)
return r;
@@ -696,7 +675,7 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) {
if (!path_is_absolute(path)) {
_cleanup_free_ char *root_abs = NULL;
r = empty_or_root_to_null(&root);
r = empty_or_root_harder_to_null(&root);
if (r < 0 && r != -ENOENT)
return r;
@@ -735,7 +714,7 @@ int chase_extract_filename(const char *path, const char *root, char **ret) {
if (!path_is_absolute(path))
return -EINVAL;
r = empty_or_root_to_null(&root);
r = empty_or_root_harder_to_null(&root);
if (r < 0 && r != -ENOENT)
return r;

View File

@@ -1406,6 +1406,27 @@ const char* empty_to_root(const char *path) {
return isempty(path) ? "/" : path;
}
int empty_or_root_harder_to_null(const char **path) {
int r;
assert(path);
/* This nullifies the input path when the path is empty or points to "/". */
if (empty_or_root(*path)) {
*path = NULL;
return 0;
}
r = path_is_root(*path);
if (r < 0)
return r;
if (r > 0)
*path = NULL;
return 0;
}
bool path_strv_contains(char * const *l, const char *path) {
assert(path);

View File

@@ -179,6 +179,7 @@ static inline const char* skip_dev_prefix(const char *p) {
bool empty_or_root(const char *path) _pure_;
const char* empty_to_root(const char *path) _pure_;
int empty_or_root_harder_to_null(const char **path);
bool path_strv_contains(char * const *l, const char *path);
bool prefixed_path_strv_contains(char * const *l, const char *path);

View File

@@ -1238,6 +1238,42 @@ TEST(empty_or_root) {
assert_se(!empty_or_root("//yy//"));
}
TEST(empty_or_root_harder_to_null) {
const char *p;
p = NULL;
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_NULL(p);
p = "/";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_NULL(p);
p = "////////";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_NULL(p);
p = "/../../././//";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_NULL(p);
p = "/usr";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_STREQ(p, "/usr");
p = "/usr/../../../";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_NULL(p);
p = "/usr/";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_STREQ(p, "/usr/");
p = "///././/../../usr////";
ASSERT_OK(empty_or_root_harder_to_null(&p));
ASSERT_STREQ(p, "///././/../../usr////");
}
TEST(path_startswith_set) {
ASSERT_STREQ(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/bar", "/zzz"), "");
ASSERT_STREQ(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/", "/zzz"), "bar");