From: Lennart Poettering Date: Tue, 16 Apr 2019 16:44:28 +0000 (+0200) Subject: chown-recursive: add fd based API X-Git-Tag: v245-rc1~238^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e10720818ec36021bc82767d68ec84377ed23221;p=thirdparty%2Fsystemd.git chown-recursive: add fd based API --- diff --git a/src/shared/chown-recursive.c b/src/shared/chown-recursive.c index 24cdf25b838..1aebac307ac 100644 --- a/src/shared/chown-recursive.c +++ b/src/shared/chown-recursive.c @@ -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 */ +} diff --git a/src/shared/chown-recursive.h b/src/shared/chown-recursive.h index bfee05f3be5..14a79733f53 100644 --- a/src/shared/chown-recursive.h +++ b/src/shared/chown-recursive.h @@ -4,3 +4,5 @@ #include 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);