]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Read extended attributes from disk on FreeBSD.
authorTim Kientzle <kientzle@gmail.com>
Mon, 19 Jan 2009 06:33:42 +0000 (01:33 -0500)
committerTim Kientzle <kientzle@gmail.com>
Mon, 19 Jan 2009 06:33:42 +0000 (01:33 -0500)
This should be the last piece needed for functional extended attribute
handling on FreeBSD.  More testing is required, though.

SVN-Revision: 453

libarchive/archive_read_disk_entry_from_file.c
libarchive/test/test_extattr_freebsd.c

index 03ab73eb8b6c467af2571034d5e44c3467be857f..ff3cbff6df77a5b869d0715f41eac5a41f4cc341 100644 (file)
@@ -29,6 +29,9 @@ __FBSDID("$FreeBSD$");
 #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
@@ -62,7 +65,7 @@ __FBSDID("$FreeBSD$");
 
 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
@@ -275,6 +278,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
  * to listxattr().
  */
 
+
 static int
 setup_xattr(struct archive_read_disk *a,
     struct archive_entry *entry, const char *name, int fd)
@@ -382,13 +386,116 @@ setup_xattrs(struct archive_read_disk *a,
  * 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);
 }
 
index 72575dd1be0f040f1d55f72114f79b07c6b54ee3..7d2abb9aa62421ebf86482e5be5e648caf2aede3 100644 (file)
@@ -41,6 +41,9 @@ DEFINE_TEST(test_extattr_freebsd)
        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;
@@ -150,5 +153,21 @@ DEFINE_TEST(test_extattr_freebsd)
                        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
 }