+#ifdef HAVE_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 wimlib_xattr_entry *entry = entries;
+
+ wimlib_assert((uintptr_t)entries % 4 == 0 &&
+ entries_size % 4 == 0 && names_size != 0);
+ 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 ||
+ (u16)name_len != name_len) {
+ ERROR("\"%s\": malformed extended attribute names list",
+ path);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Note: we 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) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ entry->name_len = cpu_to_le16(name_len);
+ entry->reserved = 0;
+ value = mempcpy(entry->name, name, name_len);
+
+ 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 ((u32)value_len != value_len) {
+ ERROR("\"%s\": value of extended attribute \"%s\" is too large",
+ path, name);
+ errno = EINVAL;
+ return -1;
+ }
+ entry->value_len = cpu_to_le32(value_len);
+
+ /*
+ * Zero-pad the entry to the next 4-byte boundary.
+ * Note: because we've guaranteed that @entries_size is a
+ * multiple of 4, this cannot overflow the @entries buffer.
+ */
+ value += value_len;
+ while ((uintptr_t)value & 3) {
+ *(u8 *)value = 0;
+ value++;
+ }
+
+ entry = value;
+ name += name_len + 1;
+ } while (name < names_end);
+
+ return (void *)entry - entries;
+}
+