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:
parent
ec96dad2f4
commit
a4d2461c46
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user