path-util: add flavour of path_startswith() that leaves a leading slash in place (#37572)

This commit is contained in:
Yu Watanabe
2025-05-24 00:20:40 +09:00
committed by GitHub
7 changed files with 60 additions and 33 deletions
+2 -8
View File
@@ -959,13 +959,12 @@ int cg_get_root_path(char **ret_path) {
}
int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted) {
_cleanup_free_ char *rt = NULL;
char *p;
int r;
assert(cgroup);
assert(ret_shifted);
_cleanup_free_ char *rt = NULL;
if (!root) {
/* If the root was specified let's use that, otherwise
* let's determine it from PID 1 */
@@ -977,12 +976,7 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted
root = rt;
}
p = path_startswith(cgroup, root);
if (p && p > cgroup)
*ret_shifted = p - 1;
else
*ret_shifted = cgroup;
*ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup;
return 0;
}
+1 -1
View File
@@ -67,7 +67,7 @@ int rmdir_parents(const char *path, const char *stop) {
assert(*slash == '/');
*slash = '\0';
if (path_startswith_full(stop, p, /* accept_dot_dot= */ false))
if (path_startswith_full(stop, p, PATH_STARTSWITH_REFUSE_DOT_DOT))
return 0;
if (rmdir(p) < 0 && errno != ENOENT)
+1 -1
View File
@@ -151,7 +151,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
assert(_mkdirat != mkdirat);
if (prefix) {
p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false);
p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT);
if (!p)
return -EINVAL;
+28 -11
View File
@@ -433,8 +433,8 @@ int path_simplify_alloc(const char *path, char **ret) {
return 0;
}
char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
assert(path);
char* path_startswith_full(const char *original_path, const char *prefix, PathStartWithFlags flags) {
assert(original_path);
assert(prefix);
/* Returns a pointer to the start of the first component after the parts matched by
@@ -447,28 +447,45 @@ char* path_startswith_full(const char *path, const char *prefix, bool accept_dot
* Returns NULL otherwise.
*/
const char *path = original_path;
if ((path[0] == '/') != (prefix[0] == '/'))
return NULL;
for (;;) {
const char *p, *q;
int r, k;
int m, n;
r = path_find_first_component(&path, accept_dot_dot, &p);
if (r < 0)
m = path_find_first_component(&path, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &p);
if (m < 0)
return NULL;
k = path_find_first_component(&prefix, accept_dot_dot, &q);
if (k < 0)
n = path_find_first_component(&prefix, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &q);
if (n < 0)
return NULL;
if (k == 0)
return (char*) (p ?: path);
if (n == 0) {
if (!p)
p = path;
if (r != k)
if (FLAGS_SET(flags, PATH_STARTSWITH_RETURN_LEADING_SLASH)) {
if (p <= original_path)
return NULL;
p--;
if (*p != '/')
return NULL;
}
return (char*) p;
}
if (m != n)
return NULL;
if (!strneq(p, q, r))
if (!strneq(p, q, m))
return NULL;
}
}
+8 -2
View File
@@ -43,9 +43,15 @@ int safe_getcwd(char **ret);
int path_make_absolute_cwd(const char *p, char **ret);
int path_make_relative(const char *from, const char *to, char **ret);
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
typedef enum PathStartWithFlags {
PATH_STARTSWITH_REFUSE_DOT_DOT = 1U << 0,
PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1,
} PathStartWithFlags;
char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_;
static inline char* path_startswith(const char *path, const char *prefix) {
return path_startswith_full(path, prefix, true);
return path_startswith_full(path, prefix, 0);
}
int path_compare(const char *a, const char *b) _pure_;
+4 -10
View File
@@ -2808,19 +2808,13 @@ static int unit_prune_cgroup_via_bus(Unit *u) {
return -EOWNERDEAD;
/* Determine this unit's cgroup path relative to our cgroup root */
const char *pp = path_startswith(crt->cgroup_path, u->manager->cgroup_root);
const char *pp = path_startswith_full(
crt->cgroup_path,
u->manager->cgroup_root,
PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT);
if (!pp)
return -EINVAL;
_cleanup_free_ char *absolute = NULL;
if (!path_is_absolute(pp)) { /* RemoveSubgroupFromUnit() wants an absolute path */
absolute = strjoin("/", pp);
if (!absolute)
return -ENOMEM;
pp = absolute;
}
r = bus_call_method(u->manager->system_bus,
bus_systemd_mgr,
"RemoveSubgroupFromUnit",
+16
View File
@@ -756,6 +756,22 @@ TEST(path_startswith) {
test_path_startswith_one("/foo/bar/barfoo/", "/fo", NULL, NULL);
}
static void test_path_startswith_return_leading_slash_one(const char *path, const char *prefix, const char *expected) {
const char *p;
log_debug("/* %s(%s, %s) */", __func__, path, prefix);
p = path_startswith_full(path, prefix, PATH_STARTSWITH_RETURN_LEADING_SLASH);
ASSERT_STREQ(p, expected);
}
TEST(path_startswith_return_leading_slash) {
test_path_startswith_return_leading_slash_one("/foo/bar", "/", "/foo/bar");
test_path_startswith_return_leading_slash_one("/foo/bar", "/foo", "/bar");
test_path_startswith_return_leading_slash_one("/foo/bar", "/foo/bar", NULL);
test_path_startswith_return_leading_slash_one("/foo/bar/", "/foo/bar", "/");
}
static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
_cleanup_free_ char *s = NULL;