From: Luca Boccassi Date: Mon, 16 Aug 2021 14:58:09 +0000 (+0100) Subject: xattr-util: add fgetxattrat_fake_malloc variant X-Git-Tag: v250-rc1~819^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5ce46344fdbc7be78f4724d8afe87b864cf27ce1;p=thirdparty%2Fsystemd.git xattr-util: add fgetxattrat_fake_malloc variant --- diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index c175ce1fbcc..e60e8bc920b 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -103,17 +103,18 @@ int fgetxattr_malloc( } } -int fgetxattrat_fake( +/* 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, - const char *attribute, - void *value, size_t size, int flags, - size_t *ret_size) { + char ret_fn[static STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1], + int *ret_fd) { - char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -1; - ssize_t l; + + assert(ret_fn); + assert(ret_fd); /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ @@ -124,15 +125,38 @@ int fgetxattrat_fake( if (!(flags & AT_EMPTY_PATH)) return -EINVAL; - xsprintf(fn, "/proc/self/fd/%i", dirfd); + 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; - xsprintf(fn, "/proc/self/fd/%i", fd); + 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, + const char *attribute, + void *value, size_t size, + int flags, + size_t *ret_size) { + + char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + _cleanup_close_ int fd = -1; + ssize_t l; + int r; + + r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd); + if (r < 0) + return r; + l = getxattr(fn, attribute, value, size); if (l < 0) return -errno; @@ -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 560e34babda..ac64f4a544e 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 7017b02ac9b..3fbae5738fe 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);