]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
xattr-util: add fgetxattrat_fake_malloc variant
authorLuca Boccassi <luca.boccassi@microsoft.com>
Mon, 16 Aug 2021 14:58:09 +0000 (15:58 +0100)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Tue, 17 Aug 2021 12:04:44 +0000 (13:04 +0100)
src/basic/xattr-util.c
src/basic/xattr-util.h
src/test/test-xattr-util.c

index c175ce1fbcc79c91aef0dab7aa9c1af917880996..e60e8bc920bd3d98785e61ecb3ce7c416b28924e 100644 (file)
@@ -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;
 
index 560e34babda4dc4c20da1ada690dcd8dee5e1d9b..ac64f4a544e8cd8d0fd69ed02874c795a680fffd 100644 (file)
@@ -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);
 
index 7017b02ac9b8d481c2e48529cac557520a24f96a..3fbae5738fe2ff334df406d8cb30ad845abc913d 100644 (file)
 
 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);