diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2023-06-06 15:01:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-06 15:01:37 +0200 |
commit | 0bb56535309d646ccd12e5e75483c3b19cf69bcc (patch) | |
tree | b3de15793f8839a78b121f98855920dfc8e031c0 /src | |
parent | generators: change TimeoutSec=0 to TimeoutSec=infinity (diff) | |
parent | chase: handle root path more carefully in chase_and_open() (diff) | |
download | systemd-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.c | 53 | ||||
-rw-r--r-- | src/basic/chase.h | 1 | ||||
-rw-r--r-- | src/test/test-chase.c | 36 | ||||
-rw-r--r-- | src/test/test-path-util.c | 11 |
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); |