]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chown-recursive: add fd based API
authorLennart Poettering <lennart@poettering.net>
Tue, 16 Apr 2019 16:44:28 +0000 (18:44 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 17 Dec 2019 19:03:40 +0000 (20:03 +0100)
src/shared/chown-recursive.c
src/shared/chown-recursive.h

index 24cdf25b838b2353ea1b4cba6073c03ddc08a433..1aebac307ac3042c96736398e06c4bbd81cb772a 100644 (file)
@@ -139,3 +139,40 @@ int path_chown_recursive(
 
         return chown_recursive_internal(TAKE_FD(fd), &st, uid, gid, mask); /* we donate the fd to the call, regardless if it succeeded or failed */
 }
+
+int fd_chown_recursive(
+                int fd,
+                uid_t uid,
+                gid_t gid,
+                mode_t mask) {
+
+        int duplicated_fd = -1;
+        struct stat st;
+
+        /* Note that the slightly different order of fstat() and the checks here and in
+         * path_chown_recursive(). That's because when we open the dirctory ourselves we can specify
+         * O_DIRECTORY and we always want to ensure we are operating on a directory before deciding whether
+         * the operation is otherwise redundant. */
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode))
+                return -ENOTDIR;
+
+        if (!uid_is_valid(uid) && !gid_is_valid(gid) && (mask & 07777) == 07777)
+                return 0; /* nothing to do */
+
+        /* Shortcut, as above */
+        if ((!uid_is_valid(uid) || st.st_uid == uid) &&
+            (!gid_is_valid(gid) || st.st_gid == gid) &&
+            ((st.st_mode & ~mask & 07777) == 0))
+                return 0;
+
+        /* Let's duplicate the fd here, as opendir() wants to take possession of it and close it afterwards */
+        duplicated_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+        if (duplicated_fd < 0)
+                return -errno;
+
+        return chown_recursive_internal(duplicated_fd, &st, uid, gid, mask); /* fd donated even on failure */
+}
index bfee05f3be56159ec03fc11c8763c32718db9398..14a79733f531e1b4b7a79161ade98e9700d99db6 100644 (file)
@@ -4,3 +4,5 @@
 #include <sys/types.h>
 
 int path_chown_recursive(const char *path, uid_t uid, gid_t gid, mode_t mask);
+
+int fd_chown_recursive(int fd, uid_t uid, gid_t gid, mode_t mask);