]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase-symlinks: Add more chase_symlinks_at() helpers 26866/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 14 Mar 2023 13:03:28 +0000 (14:03 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 21 Mar 2023 15:08:35 +0000 (16:08 +0100)
Copies of the corresponding chase_symlinks() helpers.

src/basic/chase-symlinks.c
src/basic/chase-symlinks.h
src/test/test-fs-util.c

index 2eb1701e44dc20ea8e904755ab128bbf1034e0f5..e3041ad6be33ac915f3d360da97d60784fe0097b 100644 (file)
@@ -829,3 +829,180 @@ int chase_symlinks_at_and_open(
         return r;
 }
 
+int chase_symlinks_at_and_opendir(
+                int dir_fd,
+                const char *path,
+                ChaseSymlinksFlags chase_flags,
+                char **ret_path,
+                DIR **ret_dir) {
+
+        _cleanup_close_ int path_fd = -EBADF;
+        _cleanup_free_ char *p = NULL;
+        DIR *d;
+        int r;
+
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
+        assert(ret_dir);
+
+        if (dir_fd == AT_FDCWD && !ret_path &&
+            (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
+                /* Shortcut this call if none of the special features of this call are requested */
+                d = opendir(path);
+                if (!d)
+                        return -errno;
+
+                *ret_dir = d;
+                return 0;
+        }
+
+        r = chase_symlinks_at(dir_fd, path, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
+
+        d = xopendirat(path_fd, ".", O_NOFOLLOW);
+        if (!d)
+                return -errno;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        *ret_dir = d;
+        return 0;
+}
+
+int chase_symlinks_at_and_stat(
+                int dir_fd,
+                const char *path,
+                ChaseSymlinksFlags chase_flags,
+                char **ret_path,
+                struct stat *ret_stat) {
+
+        _cleanup_close_ int path_fd = -EBADF;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(path);
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
+        assert(ret_stat);
+
+        if (dir_fd == AT_FDCWD && !ret_path &&
+            (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
+                /* Shortcut this call if none of the special features of this call are requested */
+                return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
+                                          FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
+
+        r = chase_symlinks_at(dir_fd, path, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
+
+        if (fstat(path_fd, ret_stat) < 0)
+                return -errno;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        return 0;
+}
+
+int chase_symlinks_at_and_access(
+                int dir_fd,
+                const char *path,
+                ChaseSymlinksFlags chase_flags,
+                int access_mode,
+                char **ret_path) {
+
+        _cleanup_close_ int path_fd = -EBADF;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(path);
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
+
+        if (dir_fd == AT_FDCWD && !ret_path &&
+            (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
+                /* Shortcut this call if none of the special features of this call are requested */
+                return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
+                                            FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
+
+        r = chase_symlinks_at(dir_fd, path, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
+
+        r = access_fd(path_fd, access_mode);
+        if (r < 0)
+                return r;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        return 0;
+}
+
+int chase_symlinks_at_and_fopen_unlocked(
+                int dir_fd,
+                const char *path,
+                ChaseSymlinksFlags chase_flags,
+                const char *open_flags,
+                char **ret_path,
+                FILE **ret_file) {
+
+        _cleanup_free_ char *final_path = NULL;
+        _cleanup_close_ int fd = -EBADF;
+        int mode_flags, r;
+
+        assert(path);
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT)));
+        assert(open_flags);
+        assert(ret_file);
+
+        mode_flags = fopen_mode_to_flags(open_flags);
+        if (mode_flags < 0)
+                return mode_flags;
+
+        fd = chase_symlinks_at_and_open(dir_fd, path, chase_flags, mode_flags, ret_path ? &final_path : NULL);
+        if (fd < 0)
+                return fd;
+
+        r = take_fdopen_unlocked(&fd, open_flags, ret_file);
+        if (r < 0)
+                return r;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(final_path);
+
+        return 0;
+}
+
+int chase_symlinks_at_and_unlink(
+                int dir_fd,
+                const char *path,
+                ChaseSymlinksFlags chase_flags,
+                int unlink_flags,
+                char **ret_path) {
+
+        _cleanup_free_ char *p = NULL, *fname = NULL;
+        _cleanup_close_ int fd = -EBADF;
+        int r;
+
+        assert(path);
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT)));
+
+        fd = chase_symlinks_at_and_open(dir_fd, path, chase_flags|CHASE_PARENT|CHASE_NOFOLLOW, O_PATH|O_DIRECTORY|O_CLOEXEC, &p);
+        if (fd < 0)
+                return fd;
+
+        r = path_extract_filename(p, &fname);
+        if (r < 0)
+                return r;
+
+        if (unlinkat(fd, fname, unlink_flags) < 0)
+                return -errno;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        return 0;
+}
index 0064b88cb3ac1db62de1b2a754d7c1f42759565f..de7910a5e67ac311ee21af7346f30ec1ade487b1 100644 (file)
@@ -42,4 +42,10 @@ int chase_symlinks_and_fopen_unlocked(const char *path, const char *root, ChaseS
 int chase_symlinks_and_unlink(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int unlink_flags, char **ret_path);
 
 int chase_symlinks_at(int dir_fd, const char *path, ChaseSymlinksFlags flags, char **ret_path, int *ret_fd);
+
 int chase_symlinks_at_and_open(int dir_fd, const char *path, ChaseSymlinksFlags chase_flags, int open_flags, char **ret_path);
+int chase_symlinks_at_and_opendir(int dir_fd, const char *path, ChaseSymlinksFlags chase_flags, char **ret_path, DIR **ret_dir);
+int chase_symlinks_at_and_stat(int dir_fd, const char *path, ChaseSymlinksFlags chase_flags, char **ret_path, struct stat *ret_stat);
+int chase_symlinks_at_and_access(int dir_fd, const char *path, ChaseSymlinksFlags chase_flags, int access_mode, char **ret_path);
+int chase_symlinks_at_and_fopen_unlocked(int dir_fd, const char *path, ChaseSymlinksFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
+int chase_symlinks_at_and_unlink(int dir_fd, const char *path, ChaseSymlinksFlags chase_flags, int unlink_flags, char **ret_path);
index 69c43485f1610f77e39289b8a09f136a80f04779..ce61f28017a4d7828cca9e666aea1e3e7ea6a2e3 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc-util.h"
 #include "chase-symlinks.h"
 #include "copy.h"
+#include "dirent-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
@@ -434,6 +435,9 @@ TEST(chase_symlinks_at) {
         _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
         _cleanup_close_ int tfd = -EBADF, fd = -EBADF;
         _cleanup_free_ char *result = NULL;
+        _cleanup_closedir_ DIR *dir = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        struct stat st;
         const char *p;
 
         assert_se((tfd = mkdtemp_open(NULL, 0, &t)) >= 0);
@@ -550,6 +554,42 @@ TEST(chase_symlinks_at) {
         assert_se(fd >= 0);
         assert_se(fd_verify_directory(fd) >= 0);
         fd = safe_close(fd);
+
+        /* Test chase_symlinks_at_and_opendir() */
+
+        assert_se(chase_symlinks_at_and_opendir(tfd, "o/p/e/n/d/i", 0, &result, &dir) >= 0);
+        FOREACH_DIRENT(de, dir, assert_not_reached())
+                assert_se(streq(de->d_name, "r"));
+        assert_se(streq(result, "o/p/e/n/d/i"));
+        result = mfree(result);
+
+        /* Test chase_symlinks_at_and_stat() */
+
+        assert_se(chase_symlinks_at_and_stat(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_symlinks_at_and_access() */
+
+        assert_se(chase_symlinks_at_and_access(tfd, "o/p/e", 0, F_OK, &result) >= 0);
+        assert_se(streq(result, "o/p/e"));
+        result = mfree(result);
+
+        /* Test chase_symlinks_at_and_fopen_unlocked() */
+
+        assert_se(chase_symlinks_at_and_fopen_unlocked(tfd, "o/p/e/n/f/i/l/e", 0, "re", &result, &f) >= 0);
+        assert_se(fread(&(char[1]) {}, 1, 1, f) == 0);
+        assert_se(feof(f));
+        f = safe_fclose(f);
+        assert_se(streq(result, "o/p/e/n/f/i/l/e"));
+        result = mfree(result);
+
+        /* Test chase_symlinks_at_and_unlink() */
+
+        assert_se(chase_symlinks_at_and_unlink(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(readlink_and_make_absolute) {