From: Tim Kientzle Date: Mon, 19 Jan 2009 06:33:42 +0000 (-0500) Subject: Read extended attributes from disk on FreeBSD. X-Git-Tag: v2.7.0~409 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=faa9066cecaea4100a9b0268c3feaa9ab5dcca5d;p=thirdparty%2Flibarchive.git Read extended attributes from disk on FreeBSD. This should be the last piece needed for functional extended attribute handling on FreeBSD. More testing is required, though. SVN-Revision: 453 --- diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c index 03ab73eb8..ff3cbff6d 100644 --- a/libarchive/archive_read_disk_entry_from_file.c +++ b/libarchive/archive_read_disk_entry_from_file.c @@ -29,6 +29,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_SYS_ACL_H #include #endif +#ifdef HAVE_SYS_EXTATTR_H +#include +#endif #ifdef HAVE_SYS_PARAM_H #include #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); } diff --git a/libarchive/test/test_extattr_freebsd.c b/libarchive/test/test_extattr_freebsd.c index 72575dd1b..7d2abb9aa 100644 --- a/libarchive/test/test_extattr_freebsd.c +++ b/libarchive/test/test_extattr_freebsd.c @@ -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 }