From: Daan De Meyer Date: Mon, 13 Feb 2023 20:49:38 +0000 (+0100) Subject: xattr-util: Add xsetxattr() X-Git-Tag: v254-rc1~1278^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a4d2461c46f40c9ae5002a2aea35b35ccb60ef9c;p=thirdparty%2Fsystemd.git xattr-util: Add xsetxattr() Like getxattr_malloc() but for setxattr() and friends. --- diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 5b6131b56a3..746e9f369e0 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -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; + } +} diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h index 0eb745a7a3b..649a842fe26 100644 --- a/src/basic/xattr-util.h +++ b/src/basic/xattr-util.h @@ -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);