mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
path-util: add flavour of path_startswith() that leaves a leading slash in place
This commit is contained in:
@@ -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, /* flags= */ 0))
|
||||
return 0;
|
||||
|
||||
if (rmdir(p) < 0 && errno != ENOENT)
|
||||
|
||||
@@ -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, /* flags= */ 0);
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -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_ACCEPT_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_ACCEPT_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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_ACCEPT_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, PATH_STARTSWITH_ACCEPT_DOT_DOT);
|
||||
}
|
||||
|
||||
int path_compare(const char *a, const char *b) _pure_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user