summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-06-06 15:01:37 +0200
committerGitHub <noreply@github.com>2023-06-06 15:01:37 +0200
commit0bb56535309d646ccd12e5e75483c3b19cf69bcc (patch)
treeb3de15793f8839a78b121f98855920dfc8e031c0 /src
parentgenerators: change TimeoutSec=0 to TimeoutSec=infinity (diff)
parentchase: handle root path more carefully in chase_and_open() (diff)
downloadsystemd-0bb56535309d646ccd12e5e75483c3b19cf69bcc.tar.xz
systemd-0bb56535309d646ccd12e5e75483c3b19cf69bcc.zip
Merge pull request #27918 from yuwata/chase-filename
chase: handle root path more carefully in chase_and_open()
Diffstat (limited to 'src')
-rw-r--r--src/basic/chase.c53
-rw-r--r--src/basic/chase.h1
-rw-r--r--src/test/test-chase.c36
-rw-r--r--src/test/test-path-util.c11
4 files changed, 88 insertions, 13 deletions
diff --git a/src/basic/chase.c b/src/basic/chase.c
index 600e2b9d33..02b52791ce 100644
--- a/src/basic/chase.c
+++ b/src/basic/chase.c
@@ -618,11 +618,51 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) {
return 0;
}
+int chase_extract_filename(const char *path, const char *root, char **ret) {
+ int r;
+
+ /* This is similar to path_extract_filename(), but takes root directory.
+ * The result should be consistent with chase() with CHASE_EXTRACT_FILENAME. */
+
+ assert(path);
+ assert(ret);
+
+ if (isempty(path))
+ return -EINVAL;
+
+ if (!path_is_absolute(path))
+ return -EINVAL;
+
+ if (!empty_or_root(root)) {
+ _cleanup_free_ char *root_abs = NULL;
+
+ r = path_make_absolute_cwd(root, &root_abs);
+ if (r < 0)
+ return r;
+
+ path = path_startswith(path, root_abs);
+ if (!path)
+ return -EINVAL;
+ }
+
+ if (!isempty(path)) {
+ r = path_extract_filename(path, ret);
+ if (r != -EADDRNOTAVAIL)
+ return r;
+ }
+
+ char *fname = strdup(".");
+ if (!fname)
+ return -ENOMEM;
+
+ *ret = fname;
+ return 0;
+}
+
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path) {
_cleanup_close_ int path_fd = -EBADF;
_cleanup_free_ char *p = NULL, *fname = NULL;
mode_t mode = open_flags & O_DIRECTORY ? 0755 : 0644;
- const char *q;
int r;
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
@@ -640,13 +680,10 @@ int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, i
return r;
assert(path_fd >= 0);
- assert_se(q = path_startswith(p, empty_to_root(root)));
- if (isempty(q))
- q = ".";
-
- if (!FLAGS_SET(chase_flags, CHASE_PARENT)) {
- r = path_extract_filename(q, &fname);
- if (r < 0 && r != -EADDRNOTAVAIL)
+ if (!FLAGS_SET(chase_flags, CHASE_PARENT) &&
+ !FLAGS_SET(chase_flags, CHASE_EXTRACT_FILENAME)) {
+ r = chase_extract_filename(p, root, &fname);
+ if (r < 0)
return r;
}
diff --git a/src/basic/chase.h b/src/basic/chase.h
index f37e836822..cfc714b9f7 100644
--- a/src/basic/chase.h
+++ b/src/basic/chase.h
@@ -43,6 +43,7 @@ bool unsafe_transition(const struct stat *a, const struct stat *b);
int chase(const char *path_with_prefix, const char *root, ChaseFlags chase_flags, char **ret_path, int *ret_fd);
int chaseat_prefix_root(const char *path, const char *root, char **ret);
+int chase_extract_filename(const char *path, const char *root, char **ret);
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path);
int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags, char **ret_path, DIR **ret_dir);
diff --git a/src/test/test-chase.c b/src/test/test-chase.c
index 558f4109e3..bee33bc8b2 100644
--- a/src/test/test-chase.c
+++ b/src/test/test-chase.c
@@ -17,6 +17,19 @@
static const char *arg_test_dir = NULL;
+static void test_chase_extract_filename_one(const char *path, const char *root, const char *expected) {
+ _cleanup_free_ char *ret1 = NULL, *ret2 = NULL, *fname = NULL;
+
+ log_debug("/* %s(path=%s, root=%s) */", __func__, path, strnull(root));
+
+ assert_se(chase(path, root, CHASE_EXTRACT_FILENAME, &ret1, NULL) > 0);
+ assert_se(streq(ret1, expected));
+
+ assert_se(chase(path, root, 0, &ret2, NULL) > 0);
+ assert_se(chase_extract_filename(ret2, root, &fname) >= 0);
+ assert_se(streq(fname, expected));
+}
+
TEST(chase) {
_cleanup_free_ char *result = NULL, *pwd = NULL;
_cleanup_close_ int pfd = -EBADF;
@@ -111,6 +124,19 @@ TEST(chase) {
assert_se(path_equal(result, temp));
result = mfree(result);
+ /* Tests for CHASE_EXTRACT_FILENAME and chase_extract_filename() */
+
+ p = strjoina(temp, "/start");
+ pslash = strjoina(p, "/");
+ test_chase_extract_filename_one(p, NULL, "usr");
+ test_chase_extract_filename_one(pslash, NULL, "usr");
+ test_chase_extract_filename_one(p, temp, "usr");
+ test_chase_extract_filename_one(pslash, temp, "usr");
+
+ p = strjoina(temp, "/slash");
+ test_chase_extract_filename_one(p, NULL, ".");
+ test_chase_extract_filename_one(p, temp, ".");
+
/* Paths that would "escape" outside of the "root" */
p = strjoina(temp, "/6dots");
@@ -643,11 +669,6 @@ TEST(chaseat) {
result = mfree(result);
}
-static int intro(void) {
- arg_test_dir = saved_argv[1];
- return EXIT_SUCCESS;
-}
-
TEST(chaseat_prefix_root) {
_cleanup_free_ char *cwd = NULL, *ret = NULL, *expected = NULL;
@@ -685,4 +706,9 @@ TEST(chaseat_prefix_root) {
assert_se(streq(ret, expected));
}
+static int intro(void) {
+ arg_test_dir = saved_argv[1];
+ return EXIT_SUCCESS;
+}
+
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 6b685a816f..31e2a3d296 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -600,6 +600,17 @@ TEST(path_startswith) {
test_path_startswith_one("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", "");
test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", "");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo", "/foo/./", "bar///barfoo/./.");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/", "/foo/./", "bar///barfoo/./.");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/", "/", "foo/./bar///barfoo/./.");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "////", "/", "foo/./bar///barfoo/./.");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo//bar/////barfoo///", "/foo/./bar///barfoo/./.", "");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar/barfoo////", "/foo/./bar///barfoo/./.", "");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar///barfoo/", "/foo/./bar///barfoo/./.", "");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo////bar/barfoo/", "/foo/./bar///barfoo/./.", "");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "////foo/bar/barfoo/", "/foo/./bar///barfoo/./.", "");
+ test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar/barfoo", "/foo/./bar///barfoo/./.", "");
+
test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL);
test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL);
test_path_startswith_one("/foo/bar/barfoo/", "", NULL, NULL);