+int
+namecmp(const void *aa, const void *bb)
+{
+ char * const *a = aa;
+ char * const *b = bb;
+
+ return strcmp(*a, *b);
+}
+
+int
+sum_xattrs(int fd, sum_t *dst)
+{
+ ssize_t buflen;
+ ssize_t len;
+ char *buf;
+ char *p;
+ char **names = NULL;
+ int num_xattrs = 0;
+ int ret = 0;
+ int i;
+
+ buflen = flistxattr(fd, NULL, 0);
+ if (buflen < 0)
+ return -errno;
+ /* no xattrs exist */
+ if (buflen == 0)
+ return 0;
+
+ buf = malloc(buflen);
+ if (!buf)
+ return -ENOMEM;
+
+ buflen = flistxattr(fd, buf, buflen);
+ if (buflen < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ /*
+ * Keep the list of xattrs sorted, because the order in which they are
+ * listed is filesystem dependent, so we want to get the same checksum
+ * on different filesystems.
+ */
+
+ p = buf;
+ len = buflen;
+ while (len > 0) {
+ int keylen;
+
+ keylen = strlen(p) + 1; /* +1 for NULL terminator */
+ len -= keylen;
+ p += keylen;
+ num_xattrs++;
+ }
+
+ names = malloc(sizeof(char *) * num_xattrs);
+ if (!names) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ p = buf;
+ for (i = 0; i < num_xattrs; i++) {
+ names[i] = p;
+ p += strlen(p) + 1; /* +1 for NULL terminator */
+ }
+
+ qsort(names, num_xattrs, sizeof(char *), namecmp);
+
+ for (i = 0; i < num_xattrs; i++) {
+ len = fgetxattr(fd, names[i], NULL, 0);
+ if (len < 0) {
+ ret = -errno;
+ goto out;
+ }
+ sum_add(dst, names[i], strlen(names[i]));
+ /* no value */
+ if (len == 0)
+ continue;
+ p = malloc(len);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ len = fgetxattr(fd, names[i], p, len);
+ if (len < 0) {
+ ret = -errno;
+ free(p);
+ goto out;
+ }
+ sum_add(dst, p, len);
+ free(p);
+ }
+out:
+ free(buf);
+ free(names);
+
+ return ret;
+}
+