From 5ce46344fdbc7be78f4724d8afe87b864cf27ce1 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Mon, 16 Aug 2021 15:58:09 +0100 Subject: [PATCH] xattr-util: add fgetxattrat_fake_malloc variant --- src/basic/xattr-util.c | 76 +++++++++++++++++++++++++++++--------- src/basic/xattr-util.h | 6 +++ src/test/test-xattr-util.c | 12 ++++++ 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index c175ce1fbc..e60e8bc920 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -103,6 +103,43 @@ int fgetxattr_malloc( } } +/* Note: ret_fn should already be allocated for the usual xsprintf and /proc/self/fd/%i pattern. */ +static int getxattrat_fake_prepare( + int dirfd, + const char *filename, + int flags, + char ret_fn[static STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1], + int *ret_fd) { + + _cleanup_close_ int fd = -1; + + assert(ret_fn); + assert(ret_fd); + + /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ + + if (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH)) + return -EINVAL; + + if (isempty(filename)) { + if (!(flags & AT_EMPTY_PATH)) + return -EINVAL; + + snprintf(ret_fn, STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1, "/proc/self/fd/%i", dirfd); + } else { + fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + if (fd < 0) + return -errno; + + snprintf(ret_fn, STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1, "/proc/self/fd/%i", fd); + } + + /* Pass the FD to the caller, since in case we do openat() the filename depends on it. */ + *ret_fd = TAKE_FD(fd); + + return 0; +} + int fgetxattrat_fake( int dirfd, const char *filename, @@ -114,24 +151,11 @@ int fgetxattrat_fake( char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -1; ssize_t l; + int r; - /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - - if (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH)) - return -EINVAL; - - if (isempty(filename)) { - if (!(flags & AT_EMPTY_PATH)) - return -EINVAL; - - xsprintf(fn, "/proc/self/fd/%i", dirfd); - } else { - fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); - if (fd < 0) - return -errno; - - xsprintf(fn, "/proc/self/fd/%i", fd); - } + r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd); + if (r < 0) + return r; l = getxattr(fn, attribute, value, size); if (l < 0) @@ -141,6 +165,24 @@ int fgetxattrat_fake( return 0; } +int fgetxattrat_fake_malloc( + int dirfd, + const char *filename, + const char *attribute, + int flags, + char **value) { + + char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + _cleanup_close_ int fd = -1; + int r; + + r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd); + if (r < 0) + return r; + + return getxattr_malloc(fn, attribute, value, false); +} + static int parse_crtime(le64_t le, usec_t *usec) { uint64_t u; diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h index 560e34babd..ac64f4a544 100644 --- a/src/basic/xattr-util.h +++ b/src/basic/xattr-util.h @@ -17,6 +17,12 @@ int fgetxattrat_fake( void *value, size_t size, int flags, size_t *ret_size); +int fgetxattrat_fake_malloc( + int dirfd, + const char *filename, + const char *attribute, + int flags, + char **value); int fd_setcrtime(int fd, usec_t usec); diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c index 7017b02ac9..3fbae5738f 100644 --- a/src/test/test-xattr-util.c +++ b/src/test/test-xattr-util.c @@ -17,12 +17,15 @@ static void test_fgetxattrat_fake(void) { char t[] = "/var/tmp/xattrtestXXXXXX"; + _cleanup_free_ char *value = NULL; _cleanup_close_ int fd = -1; const char *x; char v[3]; int r; size_t size; + log_info("/* %s */", __func__); + assert_se(mkdtemp(t)); x = strjoina(t, "/test"); assert_se(touch(x) >= 0); @@ -45,6 +48,13 @@ static void test_fgetxattrat_fake(void) { r = fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0, &size); assert_se(r == -ENODATA || ERRNO_IS_NOT_SUPPORTED(r)); + safe_close(fd); + fd = open(x, O_PATH|O_CLOEXEC); + assert_se(fd >= 0); + r = fgetxattrat_fake_malloc(fd, NULL, "user.foo", AT_EMPTY_PATH, &value); + assert_se(r == 3); + assert_se(streq(value, "bar")); + cleanup: assert_se(unlink(x) >= 0); assert_se(rmdir(t) >= 0); @@ -56,6 +66,8 @@ static void test_getcrtime(void) { usec_t usec, k; int r; + log_info("/* %s */", __func__); + assert_se(tmp_dir(&vt) >= 0); fd = open_tmpfile_unlinkable(vt, O_RDWR);