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;
+ }
+}
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);