#ifdef HAVE_SYS_ACL_H
#include <sys/acl.h>
#endif
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
static int setup_acls_posix1e(struct archive_read_disk *,
struct archive_entry *, int fd);
-static int setup_xattrs(struct archive_read_disk *,
+int setup_xattrs(struct archive_read_disk *,
struct archive_entry *, int fd);
int
* to listxattr().
*/
+
static int
setup_xattr(struct archive_read_disk *a,
struct archive_entry *entry, const char *name, int fd)
* to not include the system extattrs that hold ACLs; we handle
* those separately.
*/
-static int
+int
+setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
+ int namespace, const char *name, const char *fullname, int fd);
+
+int
+setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
+ int namespace, const char *name, const char *fullname, int fd)
+{
+ ssize_t size;
+ void *value = NULL;
+ const char *accpath;
+
+ (void)fd; /* UNUSED */
+
+ accpath = archive_entry_sourcepath(entry);
+ if (accpath == NULL)
+ accpath = archive_entry_pathname(entry);
+
+ if (!a->follow_symlinks)
+ size = extattr_get_link(accpath, namespace, name, NULL, 0);
+ else
+ size = extattr_get_file(accpath, namespace, name, NULL, 0);
+
+ if (size == -1) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't query extended attribute");
+ return (ARCHIVE_WARN);
+ }
+
+ if (size > 0 && (value = malloc(size)) == NULL) {
+ archive_set_error(&a->archive, errno, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (!a->follow_symlinks)
+ size = extattr_get_link(accpath, namespace, name, value, size);
+ else
+ size = extattr_get_file(accpath, namespace, name, value, size);
+
+ if (size == -1) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't read extended attribute");
+ return (ARCHIVE_WARN);
+ }
+
+ archive_entry_xattr_add_entry(entry, fullname, value, size);
+
+ free(value);
+ return (ARCHIVE_OK);
+}
+
+int
setup_xattrs(struct archive_read_disk *a,
struct archive_entry *entry, int fd)
{
- (void)a; /* UNUSED */
- (void)entry; /* UNUSED */
- (void)fd; /* UNUSED */
+ char buff[512];
+ char *list, *p;
+ ssize_t list_size;
+ const char *path;
+ int namespace = EXTATTR_NAMESPACE_USER;
+
+ path = archive_entry_pathname(entry);
+ if (path == NULL)
+ path = archive_entry_sourcepath(entry);
+
+ if (!a->follow_symlinks)
+ list_size = extattr_list_link(path, namespace, NULL, 0);
+ else
+ list_size = extattr_list_file(path, namespace, NULL, 0);
+
+ if (list_size == -1) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't list extended attributes");
+ return (ARCHIVE_WARN);
+ }
+
+ if (list_size == 0)
+ return (ARCHIVE_OK);
+
+ if ((list = malloc(list_size)) == NULL) {
+ archive_set_error(&a->archive, errno, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (!a->follow_symlinks)
+ list_size = extattr_list_link(path, namespace, list, list_size);
+ else
+ list_size = extattr_list_file(path, namespace, list, list_size);
+
+ if (list_size == -1) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't retrieve extended attributes");
+ free(list);
+ return (ARCHIVE_WARN);
+ }
+
+ p = list;
+ while ((p - list) < list_size) {
+ size_t len = 255 & (int)*p;
+ char *name;
+
+ strcpy(buff, "user.");
+ name = buff + strlen(buff);
+ memcpy(name, p + 1, len);
+ name[len] = '\0';
+ setup_xattr(a, entry, namespace, name, buff, fd);
+ p += 1 + len;
+ }
+
+ free(list);
return (ARCHIVE_OK);
}
skipping("extattr restore supported only on FreeBSD 5.0 and later");
#else
char buff[64];
+ const char *xname;
+ const void *xval;
+ size_t xsize;
struct stat st;
struct archive *a;
struct archive_entry *ae;
assertEqualString(buff, "123456");
}
}
+
+ /* Use libarchive APIs to read the file back into an entry and
+ * verify that the extattr was read correctly. */
+ assert((a = archive_read_disk_new()) != NULL);
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_pathname(ae, "test0");
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_entry_from_file(a, ae, -1, NULL));
+ assertEqualInt(1, archive_entry_xattr_reset(ae));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_xattr_next(ae, &xname, &xval, &xsize));
+ assertEqualString(xname, "user.foo");
+ assertEqualInt(xsize, 5);
+ assertEqualMem(xval, "12345", xsize);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
#endif
}