+#ifdef HAVE_LINUX_XATTR_SUPPORT
+/*
+ * Retrieves the values of the xattrs named by the null-terminated @names of the
+ * file at @path and serializes the xattr names and values into @entries. If
+ * successful, returns the number of bytes used in @entries. If unsuccessful,
+ * returns -1 and sets errno (ERANGE if @entries was too small).
+ */
+static ssize_t
+gather_xattr_entries(const char *path, const char *names, size_t names_size,
+ void *entries, size_t entries_size)
+{
+ const char * const names_end = names + names_size;
+ void * const entries_end = entries + entries_size;
+ const char *name = names;
+ struct wim_xattr_entry *entry = entries;
+
+ do {
+ size_t name_len = strnlen(name, names_end - name);
+ void *value;
+ ssize_t value_len;
+
+ if (name_len == 0 || name_len >= names_end - name) {
+ ERROR("\"%s\": malformed extended attribute names list",
+ path);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (name_len > WIM_XATTR_NAME_MAX) {
+ WARNING("\"%s\": name of extended attribute \"%s\" is too long to store",
+ path, name);
+ goto next_name;
+ }
+
+ /*
+ * Take care to always call lgetxattr() with a nonzero size,
+ * since zero size means to return the value length only.
+ */
+ if (entries_end - (void *)entry <=
+ sizeof(*entry) + name_len + 1) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ entry->name_len = name_len;
+ entry->flags = 0;
+ value = mempcpy(entry->name, name, name_len + 1);
+
+ value_len = lgetxattr(path, name, value, entries_end - value);
+ if (value_len < 0) {
+ if (errno != ERANGE) {
+ ERROR_WITH_ERRNO("\"%s\": unable to read extended attribute \"%s\"",
+ path, name);
+ }
+ return -1;
+ }
+ if (value_len > WIM_XATTR_SIZE_MAX) {
+ WARNING("\"%s\": value of extended attribute \"%s\" is too large to store",
+ path, name);
+ goto next_name;
+ }
+ entry->value_len = cpu_to_le16(value_len);
+ entry = value + value_len;
+ next_name:
+ name += name_len + 1;
+ } while (name < names_end);
+
+ return (void *)entry - entries;
+}
+