+static bool verify_xattr_content(int fd, const char *xattr_name, const char *expected, ssize_t size) {
+ // Verify that the file referenced by `fd` has an xattr named `xattr_name`
+ // of size `size` and with contents equal to `expected`.
+ char *actual = NULL;
+ bool equal;
+
+ assert(fd > 0 && xattr_name && expected);
+ assert_with_errno(actual = malloc(size));
+ assert_with_errno(fgetxattr(fd, xattr_name, actual, size, 0, 0) == size);
+
+ equal = (memcmp(actual, expected, size) == 0);
+ if (!equal) {
+ printf("xattr %s: content does not match expected\n", xattr_name);
+ }
+
+ free(actual);
+ return equal;
+}
+
+bool verify_fd_xattr_contents(int orig_fd, int copy_fd) {
+ // Verify that both fd's have the same xattrs.
+ // We do so by first verifying that `flistxattr()` returns the same size
+ // for both, and then validating that `copy_fd` has each of the xattrs
+ // that `orig_fd` has.
+ char *namebuf = NULL, *xa_buf = NULL, *name, *end;
+ ssize_t orig_size, copy_size, xa_size;
+ bool equal = true;
+
+ assert((orig_fd > 0) && (copy_fd > 0));
+
+ orig_size = flistxattr(orig_fd, 0, 0, XATTR_SHOWCOMPRESSION);
+ copy_size = flistxattr(copy_fd, 0, 0, XATTR_SHOWCOMPRESSION);
+ if (orig_size != copy_size) {
+ printf("xattrlist size: orig_size(%zu) != (%zu)copy_size\n", orig_size, copy_size);
+ return false;
+ }
+
+ if (orig_size == 0) {
+ return true;
+ }
+
+ assert_with_errno(namebuf = malloc(orig_size));
+
+ assert_with_errno(flistxattr(orig_fd, namebuf, orig_size, 0) == orig_size);
+
+ end = namebuf + orig_size - 1;
+ if (*end != 0) {
+ *end = 0;
+ }
+
+ for (name = namebuf; name <= end; name += strlen(name) + 1) {
+ xa_size = fgetxattr(orig_fd, name, 0, 0, 0, 0);
+ assert(xa_size >= 0);
+ assert_with_errno(xa_buf = malloc(xa_size));
+ assert_with_errno(fgetxattr(orig_fd, name, xa_buf, xa_size, 0, 0) == xa_size);
+ equal = equal && verify_xattr_content(copy_fd, name, xa_buf, xa_size);
+ free(xa_buf);
+
+ if (!equal) {
+ break;
+ }
+ }
+ free(namebuf);
+
+ return equal;
+}
+