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)
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;
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
* 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 (FLAGS_SET(flags, PATH_STARTSWITH_RETURN_LEADING_SLASH)) {
+
+ if (p <= original_path)
+ return NULL;
+
+ p--;
+
+ if (*p != '/')
+ return NULL;
+ }
+
+ return (char*) p;
+ }
- if (r != k)
+ if (m != n)
return NULL;
- if (!strneq(p, q, r))
+ if (!strneq(p, q, m))
return NULL;
}
}
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_;
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;