From 57a4359ee0bf65c16336e8157f0f9d2b084ddac3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Nov 2017 18:56:25 +0100 Subject: [PATCH] fs-util: add access_fd() which is like access() but for fds Linux doesn't have faccess(), hence let's emulate it. Linux has access() and faccessat() but neither allows checking the access rights of an fd passed in directly. --- src/basic/fs-util.c | 16 +++++++++++++++- src/basic/fs-util.h | 2 ++ src/test/test-fs-util.c | 27 +++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 946f779a32..ff8b4e8747 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -104,7 +104,6 @@ int rmdir_parents(const char *path, const char *stop) { return 0; } - int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { struct stat buf; int ret; @@ -809,3 +808,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return exists; } + +int access_fd(int fd, int mode) { + char p[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; + int r; + + /* Like access() but operates on an already open fd */ + + xsprintf(p, "/proc/self/fd/%i", fd); + + r = access(p, mode); + if (r < 0) + r = -errno; + + return r; +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index d3342d5cda..9849522f5a 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -98,3 +98,5 @@ static inline void unlink_and_free(char *p) { free(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); + +int access_fd(int fd, int mode); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index a5871a25b0..e8fe2b3ff1 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -315,6 +315,32 @@ static void test_dot_or_dot_dot(void) { assert_se(!dot_or_dot_dot("..foo")); } +static void test_access_fd(void) { + _cleanup_(rmdir_and_freep) char *p = NULL; + _cleanup_close_ int fd = -1; + + assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0); + + fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC); + assert_se(fd >= 0); + + assert_se(access_fd(fd, R_OK) >= 0); + assert_se(access_fd(fd, F_OK) >= 0); + assert_se(access_fd(fd, W_OK) >= 0); + + assert_se(fchmod(fd, 0000) >= 0); + + assert_se(access_fd(fd, F_OK) >= 0); + + if (geteuid() == 0) { + assert_se(access_fd(fd, R_OK) >= 0); + assert_se(access_fd(fd, W_OK) >= 0); + } else { + assert_se(access_fd(fd, R_OK) == -EACCES); + assert_se(access_fd(fd, W_OK) == -EACCES); + } +} + int main(int argc, char *argv[]) { test_unlink_noerrno(); test_get_files_in_directory(); @@ -322,6 +348,7 @@ int main(int argc, char *argv[]) { test_var_tmp(); test_chase_symlinks(); test_dot_or_dot_dot(); + test_access_fd(); return 0; }