From: Daan De Meyer Date: Fri, 24 Mar 2023 11:10:16 +0000 (+0100) Subject: chase-symlinks: Add chase_and_open_parent() + at() variant X-Git-Tag: v254-rc1~913^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F26961%2Fhead;p=thirdparty%2Fsystemd.git chase-symlinks: Add chase_and_open_parent() + at() variant Helper to chase a path, pin its parent directory and return the filename of the resolved path in its parent directory. --- diff --git a/src/basic/chase.c b/src/basic/chase.c index e3ee01271e1..6c02aeab8ba 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -784,6 +784,18 @@ int chase_and_unlink( return 0; } +int chase_and_open_parent(const char *path, const char *root, ChaseFlags chase_flags, char **ret_filename) { + int pfd, r; + + assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))); + + r = chase(path, root, CHASE_PARENT|CHASE_EXTRACT_FILENAME|chase_flags, ret_filename, &pfd); + if (r < 0) + return r; + + return pfd; +} + int chase_and_openat( int dir_fd, const char *path, @@ -1003,3 +1015,20 @@ int chase_and_unlinkat( return 0; } + +int chase_and_open_parent_at( + int dir_fd, + const char *path, + ChaseFlags chase_flags, + char **ret_filename) { + + int pfd, r; + + assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))); + + r = chaseat(dir_fd, path, CHASE_PARENT|CHASE_EXTRACT_FILENAME|chase_flags, ret_filename, &pfd); + if (r < 0) + return r; + + return pfd; +} diff --git a/src/basic/chase.h b/src/basic/chase.h index c94cbde8fef..1314777cb4f 100644 --- a/src/basic/chase.h +++ b/src/basic/chase.h @@ -40,6 +40,7 @@ int chase_and_stat(const char *path, const char *root, ChaseFlags chase_flags, c int chase_and_access(const char *path, const char *root, ChaseFlags chase_flags, int access_mode, char **ret_path); int chase_and_fopen_unlocked(const char *path, const char *root, ChaseFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file); int chase_and_unlink(const char *path, const char *root, ChaseFlags chase_flags, int unlink_flags, char **ret_path); +int chase_and_open_parent(const char *path, const char *root, ChaseFlags chase_flags, char **ret_filename); int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int *ret_fd); @@ -49,3 +50,5 @@ int chase_and_statat(int dir_fd, const char *path, ChaseFlags chase_flags, char int chase_and_accessat(int dir_fd, const char *path, ChaseFlags chase_flags, int access_mode, char **ret_path); int chase_and_fopenat_unlocked(int dir_fd, const char *path, ChaseFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file); int chase_and_unlinkat(int dir_fd, const char *path, ChaseFlags chase_flags, int unlink_flags, char **ret_path); +int chase_and_open_parent_at(int dir_fd, const char *path, ChaseFlags chase_flags, char **ret_filename); + diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index d79d9603d3c..ab84a5ba83c 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -432,7 +432,7 @@ TEST(chase) { assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -TEST(chase_at) { +TEST(chaseat) { _cleanup_(rm_rf_physical_and_freep) char *t = NULL; _cleanup_close_ int tfd = -EBADF, fd = -EBADF; _cleanup_free_ char *result = NULL; @@ -564,20 +564,20 @@ TEST(chase_at) { assert_se(streq(result, "o/p/e/n/d/i")); result = mfree(result); - /* Test chase_at_and_stat() */ + /* Test chase_and_statat() */ assert_se(chase_and_statat(tfd, "o/p", 0, &result, &st) >= 0); assert_se(stat_verify_directory(&st) >= 0); assert_se(streq(result, "o/p")); result = mfree(result); - /* Test chase_at_and_access() */ + /* Test chase_and_accessat() */ assert_se(chase_and_accessat(tfd, "o/p/e", 0, F_OK, &result) >= 0); assert_se(streq(result, "o/p/e")); result = mfree(result); - /* Test chase_at_and_fopen_unlocked() */ + /* Test chase_and_fopenat_unlocked() */ assert_se(chase_and_fopenat_unlocked(tfd, "o/p/e/n/f/i/l/e", 0, "re", &result, &f) >= 0); assert_se(fread(&(char[1]) {}, 1, 1, f) == 0); @@ -586,11 +586,35 @@ TEST(chase_at) { assert_se(streq(result, "o/p/e/n/f/i/l/e")); result = mfree(result); - /* Test chase_at_and_unlink() */ + /* Test chase_and_unlinkat() */ assert_se(chase_and_unlinkat(tfd, "o/p/e/n/f/i/l/e", 0, 0, &result) >= 0); assert_se(streq(result, "o/p/e/n/f/i/l/e")); result = mfree(result); + + /* Test chase_and_open_parent_at() */ + + assert_se((fd = chase_and_open_parent_at(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_NOFOLLOW, &result)) >= 0); + assert_se(faccessat(fd, result, F_OK, AT_SYMLINK_NOFOLLOW) >= 0); + assert_se(streq(result, "parent")); + fd = safe_close(fd); + result = mfree(result); + + assert_se((fd = chase_and_open_parent_at(tfd, "chase", CHASE_AT_RESOLVE_IN_ROOT, &result)) >= 0); + assert_se(faccessat(fd, result, F_OK, 0) >= 0); + assert_se(streq(result, "chase")); + fd = safe_close(fd); + result = mfree(result); + + assert_se((fd = chase_and_open_parent_at(tfd, "/", CHASE_AT_RESOLVE_IN_ROOT, &result)) >= 0); + assert_se(streq(result, ".")); + fd = safe_close(fd); + result = mfree(result); + + assert_se((fd = chase_and_open_parent_at(tfd, ".", CHASE_AT_RESOLVE_IN_ROOT, &result)) >= 0); + assert_se(streq(result, ".")); + fd = safe_close(fd); + result = mfree(result); } TEST(readlink_and_make_absolute) {