}
}
-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 */
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;
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;
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);
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);
usec_t usec, k;
int r;
+ log_info("/* %s */", __func__);
+
assert_se(tmp_dir(&vt) >= 0);
fd = open_tmpfile_unlinkable(vt, O_RDWR);