1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-25 10:04:04 +03:00

xattr-util: Add xsetxattr()

Like getxattr_malloc() but for setxattr() and friends.
This commit is contained in:
Daan De Meyer 2023-02-13 21:49:38 +01:00
parent ec96dad2f4
commit a4d2461c46
2 changed files with 76 additions and 0 deletions

View File

@ -293,3 +293,77 @@ int listxattr_at_malloc(
l = (size_t) n;
}
}
int xsetxattr(int fd,
const char *path,
const char *name,
const char *value,
size_t size,
int flags) {
_cleanup_close_ int opened_fd = -EBADF;
bool by_procfs = false;
int r;
assert(fd >= 0 || fd == AT_FDCWD);
assert(name);
assert(value);
assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
/* So, this is a single function that does what setxattr()/lsetxattr()/fsetxattr() do, but in one go,
* and with additional bells and whistles. Specifically:
*
* 1. This works on O_PATH fds (which fsetxattr() does not)
* 2. Provides full openat()-style semantics, i.e. by-fd, by-path and combination thereof
* 3. As extension to openat()-style semantics implies AT_EMPTY_PATH if path is NULL.
*/
if (!path) /* If path is NULL, imply AT_EMPTY_PATH. But if it's "", don't — for safety reasons. */
flags |= AT_EMPTY_PATH;
if (size == SIZE_MAX)
size = strlen(value);
if (isempty(path)) {
if (!FLAGS_SET(flags, AT_EMPTY_PATH))
return -EINVAL;
if (fd == AT_FDCWD) /* Both unspecified? Then operate on current working directory */
path = ".";
else
path = NULL;
} else if (fd != AT_FDCWD) {
/* If both have been specified, then we go via O_PATH */
opened_fd = openat(fd, path, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : O_NOFOLLOW));
if (opened_fd < 0)
return -errno;
fd = opened_fd;
path = NULL;
by_procfs = true; /* fsetxattr() is not going to work, go via /proc/ link right-away */
}
for (;;) {
if (path)
r = FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? setxattr(path, name, value, size, 0)
: lsetxattr(path, name, value, size, 0);
else
r = by_procfs ? setxattr(FORMAT_PROC_FD_PATH(fd), name, value, size, 0)
: fsetxattr(fd, name, value, size, 0);
if (r < 0) {
if (errno == EBADF) {
if (by_procfs || path)
return -EBADF;
by_procfs = true; /* Might be an O_PATH fd, try again via /proc/ link */
continue;
}
return -errno;
}
return 0;
}
}

View File

@ -36,3 +36,5 @@ static inline int llistxattr_malloc(const char *path, char **ret) {
static inline int flistxattr_malloc(int fd, char **ret) {
return listxattr_at_malloc(fd, NULL, AT_EMPTY_PATH, ret);
}
int xsetxattr(int fd, const char *path, const char *name, const char *value, size_t size, int flags);