svn commit: r189429 - in head/lib/libarchive: . test

Tim Kientzle kientzle at FreeBSD.org
Thu Mar 5 20:35:32 PST 2009


Author: kientzle
Date: Fri Mar  6 04:35:31 2009
New Revision: 189429
URL: http://svn.freebsd.org/changeset/base/189429

Log:
  Merge r399,401,402,405,415,430,440,452,453,458,506,533,536,538,544,590
  from libarchive.googlecode.com:  Add a new "archive_read_disk" API
  that provides the important service of reading metadata from the
  disk.  In particular, this will make it possible to remove all
  knowledge of extended attributes, ACLs, etc, from clients such
  as bsdtar and bsdcpio.
  
  Closely related, this API also provides pluggable uid->uname
  and gid->gname lookup and caching services similar to
  the uname->uid and gname->gid services provided by archive_write_disk.
  Remember this is also required for correct ACL management.
  
  Documentation is still pending...

Added:
  head/lib/libarchive/archive_read_disk.c   (contents, props changed)
  head/lib/libarchive/archive_read_disk_entry_from_file.c   (contents, props changed)
  head/lib/libarchive/archive_read_disk_private.h   (contents, props changed)
  head/lib/libarchive/archive_read_disk_set_standard_lookup.c   (contents, props changed)
  head/lib/libarchive/test/test_read_disk.c   (contents, props changed)
Modified:
  head/lib/libarchive/Makefile
  head/lib/libarchive/archive.h
  head/lib/libarchive/archive_private.h
  head/lib/libarchive/config_freebsd.h
  head/lib/libarchive/test/Makefile

Modified: head/lib/libarchive/Makefile
==============================================================================
--- head/lib/libarchive/Makefile	Fri Mar  6 04:22:34 2009	(r189428)
+++ head/lib/libarchive/Makefile	Fri Mar  6 04:35:31 2009	(r189429)
@@ -25,6 +25,9 @@ SRCS=	archive_check_magic.c				\
 	archive_entry_link_resolver.c			\
 	archive_read.c					\
 	archive_read_data_into_fd.c			\
+	archive_read_disk.c				\
+	archive_read_disk_entry_from_file.c		\
+	archive_read_disk_set_standard_lookup.c		\
 	archive_read_extract.c				\
 	archive_read_open_fd.c				\
 	archive_read_open_file.c			\

Modified: head/lib/libarchive/archive.h
==============================================================================
--- head/lib/libarchive/archive.h	Fri Mar  6 04:22:34 2009	(r189428)
+++ head/lib/libarchive/archive.h	Fri Mar  6 04:35:31 2009	(r189429)
@@ -36,6 +36,7 @@
  * platform macros.
  */
 
+#include <sys/stat.h>
 #include <sys/types.h>  /* Linux requires this for off_t */
 #if !defined(__WATCOMC__) && !defined(_MSC_VER)
 /* Header unavailable on Watcom C or MS Visual C++. */
@@ -605,6 +606,40 @@ __LA_DECL int	 archive_write_disk_set_us
 			    void (* /* cleanup */)(void *));
 
 /*
+ * ARCHIVE_READ_DISK API
+ *
+ * This is still evolving and somewhat experimental.
+ */
+__LA_DECL struct archive *archive_read_disk_new(void);
+/* The names for symlink modes here correspond to an old BSD
+ * command-line argument convention: -L, -P, -H */
+/* Follow all symlinks. */
+__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *);
+/* Follow no symlinks. */
+__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *);
+/* Follow symlink initially, then not. */
+__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *);
+/* TODO: Handle Linux stat32/stat64 ugliness. <sigh> */
+__LA_DECL int archive_read_disk_entry_from_file(struct archive *,
+    struct archive_entry *, int /* fd */, const struct stat *);
+/* Look up gname for gid or uname for uid. */
+/* Default implementations are very, very stupid. */
+__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_GID_T);
+__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_UID_T);
+/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
+ * results for performance. */
+__LA_DECL int	archive_read_disk_set_standard_lookup(struct archive *);
+/* You can install your own lookups if you like. */
+__LA_DECL int	archive_read_disk_set_gname_lookup(struct archive *,
+    void * /* private_data */,
+    const char *(* /* lookup_fn */)(void *, __LA_GID_T),
+    void (* /* cleanup_fn */)(void *));
+__LA_DECL int	archive_read_disk_set_uname_lookup(struct archive *,
+    void * /* private_data */,
+    const char *(* /* lookup_fn */)(void *, __LA_UID_T),
+    void (* /* cleanup_fn */)(void *));
+
+/*
  * Accessor functions to read/set various information in
  * the struct archive object:
  */

Modified: head/lib/libarchive/archive_private.h
==============================================================================
--- head/lib/libarchive/archive_private.h	Fri Mar  6 04:22:34 2009	(r189428)
+++ head/lib/libarchive/archive_private.h	Fri Mar  6 04:35:31 2009	(r189429)
@@ -41,6 +41,7 @@
 #define	ARCHIVE_WRITE_MAGIC	(0xb0c5c0deU)
 #define	ARCHIVE_READ_MAGIC	(0xdeb0c5U)
 #define	ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
+#define	ARCHIVE_READ_DISK_MAGIC	(0xbadb0c5U)
 
 #define	ARCHIVE_STATE_ANY	0xFFFFU
 #define	ARCHIVE_STATE_NEW	1U

Added: head/lib/libarchive/archive_read_disk.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libarchive/archive_read_disk.c	Fri Mar  6 04:35:31 2009	(r189429)
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_read_disk_private.h"
+
+static int	_archive_read_finish(struct archive *);
+static int	_archive_read_close(struct archive *);
+static const char *trivial_lookup_gname(void *, gid_t gid);
+static const char *trivial_lookup_uname(void *, uid_t uid);
+
+static struct archive_vtable *
+archive_read_disk_vtable(void)
+{
+	static struct archive_vtable av;
+	static int inited = 0;
+
+	if (!inited) {
+		av.archive_finish = _archive_read_finish;
+		av.archive_close = _archive_read_close;
+	}
+	return (&av);
+}
+
+const char *
+archive_read_disk_gname(struct archive *_a, gid_t gid)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	if (a->lookup_gname != NULL)
+		return ((*a->lookup_gname)(a->lookup_gname_data, gid));
+	return (NULL);
+}
+
+const char *
+archive_read_disk_uname(struct archive *_a, uid_t uid)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	if (a->lookup_uname != NULL)
+		return ((*a->lookup_uname)(a->lookup_uname_data, uid));
+	return (NULL);
+}
+
+int
+archive_read_disk_set_gname_lookup(struct archive *_a,
+    void *private_data,
+    const char * (*lookup_gname)(void *private, gid_t gid),
+    void (*cleanup_gname)(void *private))
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	__archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");
+
+	if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
+		(a->cleanup_gname)(a->lookup_gname_data);
+
+	a->lookup_gname = lookup_gname;
+	a->cleanup_gname = cleanup_gname;
+	a->lookup_gname_data = private_data;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_uname_lookup(struct archive *_a,
+    void *private_data,
+    const char * (*lookup_uname)(void *private, uid_t uid),
+    void (*cleanup_uname)(void *private))
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	__archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");
+
+	if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
+		(a->cleanup_uname)(a->lookup_uname_data);
+
+	a->lookup_uname = lookup_uname;
+	a->cleanup_uname = cleanup_uname;
+	a->lookup_uname_data = private_data;
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Create a new archive_read_disk object and initialize it with global state.
+ */
+struct archive *
+archive_read_disk_new(void)
+{
+	struct archive_read_disk *a;
+
+	a = (struct archive_read_disk *)malloc(sizeof(*a));
+	if (a == NULL)
+		return (NULL);
+	memset(a, 0, sizeof(*a));
+	a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
+	/* We're ready to write a header immediately. */
+	a->archive.state = ARCHIVE_STATE_HEADER;
+	a->archive.vtable = archive_read_disk_vtable();
+	a->lookup_uname = trivial_lookup_uname;
+	a->lookup_gname = trivial_lookup_gname;
+	return (&a->archive);
+}
+
+static int
+_archive_read_finish(struct archive *_a)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+	if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
+		(a->cleanup_gname)(a->lookup_gname_data);
+	if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
+		(a->cleanup_uname)(a->lookup_uname_data);
+	archive_string_free(&a->archive.error_string);
+	free(a);
+	return (ARCHIVE_OK);
+}
+
+static int
+_archive_read_close(struct archive *_a)
+{
+	(void)_a; /* UNUSED */
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_symlink_logical(struct archive *_a)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	a->symlink_mode = 'L';
+	a->follow_symlinks = 1;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_symlink_physical(struct archive *_a)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	a->symlink_mode = 'P';
+	a->follow_symlinks = 0;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_symlink_hybrid(struct archive *_a)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	a->symlink_mode = 'H';
+	a->follow_symlinks = 1; /* Follow symlinks initially. */
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Trivial implementations of gname/uname lookup functions.
+ * These are normally overridden by the client, but these stub
+ * versions ensure that we always have something that works.
+ */
+static const char *
+trivial_lookup_gname(void *private_data, gid_t gid)
+{
+	(void)private_data; /* UNUSED */
+	(void)gid; /* UNUSED */
+	return (NULL);
+}
+
+static const char *
+trivial_lookup_uname(void *private_data, uid_t uid)
+{
+	(void)private_data; /* UNUSED */
+	(void)uid; /* UNUSED */
+	return (NULL);
+}

Added: head/lib/libarchive/archive_read_disk_entry_from_file.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libarchive/archive_read_disk_entry_from_file.c	Fri Mar  6 04:35:31 2009	(r189429)
@@ -0,0 +1,537 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_TYPES_H
+/* Mac OSX requires sys/types.h before sys/acl.h. */
+#include <sys/types.h>
+#endif
+#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
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_read_disk_private.h"
+
+/*
+ * Linux and FreeBSD plug this obvious hole in POSIX.1e in
+ * different ways.
+ */
+#if HAVE_ACL_GET_PERM
+#define	ACL_GET_PERM acl_get_perm
+#elif HAVE_ACL_GET_PERM_NP
+#define	ACL_GET_PERM acl_get_perm_np
+#endif
+
+static int setup_acls_posix1e(struct archive_read_disk *,
+    struct archive_entry *, int fd);
+static int setup_xattrs(struct archive_read_disk *,
+    struct archive_entry *, int fd);
+
+int
+archive_read_disk_entry_from_file(struct archive *_a,
+    struct archive_entry *entry,
+    int fd, const struct stat *st)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	const char *path;
+	struct stat s;
+	int initial_fd = fd;
+	int r, r1;
+
+	path = archive_entry_sourcepath(entry);
+	if (path == NULL)
+		path = archive_entry_pathname(entry);
+
+#ifdef EXT2_IOC_GETFLAGS
+	/* Linux requires an extra ioctl to pull the flags.  Although
+	 * this is an extra step, it has a nice side-effect: We get an
+	 * open file descriptor which we can use in the subsequent lookups. */
+	if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
+		if (fd < 0)
+			fd = open(pathname, O_RDONLY | O_NONBLOCK);
+		if (fd >= 0) {
+			unsigned long stflags;
+			int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
+			if (r == 0 && stflags != 0)
+				archive_entry_set_fflags(entry, stflags, 0);
+		}
+	}
+#endif
+
+	if (st == NULL) {
+#if HAVE_FSTAT
+		if (fd >= 0) {
+			if (fstat(fd, &s) != 0)
+				return (ARCHIVE_FATAL);
+		} else
+#endif
+#if HAVE_LSTAT
+		if (!a->follow_symlinks) {
+			if (lstat(path, &s) != 0)
+				return (ARCHIVE_FATAL);
+		} else
+#endif
+		if (stat(path, &s) != 0)
+			return (ARCHIVE_FATAL);
+		st = &s;
+	}
+	archive_entry_copy_stat(entry, st);
+
+#ifdef HAVE_STRUCT_STAT_ST_FLAGS
+	/* On FreeBSD, we get flags for free with the stat. */
+	/* TODO: Does this belong in copy_stat()? */
+	if (st->st_flags != 0)
+		archive_entry_set_fflags(entry, st->st_flags, 0);
+#endif
+
+#ifdef HAVE_READLINK
+	if (S_ISLNK(st->st_mode)) {
+		char linkbuffer[PATH_MAX + 1];
+		int lnklen = readlink(path, linkbuffer, PATH_MAX);
+		if (lnklen < 0) {
+			archive_set_error(&a->archive, errno,
+			    "Couldn't read link data");
+			return (ARCHIVE_WARN);
+		}
+		linkbuffer[lnklen] = 0;
+		archive_entry_set_symlink(entry, linkbuffer);
+	}
+#endif
+
+	r = setup_acls_posix1e(a, entry, fd);
+	r1 = setup_xattrs(a, entry, fd);
+	if (r1 < r)
+		r = r1;
+	/* If we opened the file earlier in this function, close it. */
+	if (initial_fd != fd)
+		close(fd);
+	return (r);
+}
+
+#ifdef HAVE_POSIX_ACL
+static void setup_acl_posix1e(struct archive_read_disk *a,
+    struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
+
+static int
+setup_acls_posix1e(struct archive_read_disk *a,
+    struct archive_entry *entry, int fd)
+{
+	const char	*accpath;
+	acl_t		 acl;
+
+	accpath = archive_entry_sourcepath(entry);
+	if (accpath == NULL)
+		accpath = archive_entry_pathname(entry);
+
+	archive_entry_acl_clear(entry);
+
+	/* Retrieve access ACL from file. */
+	if (fd >= 0)
+		acl = acl_get_fd(fd);
+#if HAVE_ACL_GET_LINK_NP
+	else if (!a->follow_symlinks)
+		acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
+#endif
+	else
+		acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
+	if (acl != NULL) {
+		setup_acl_posix1e(a, entry, acl,
+		    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+		acl_free(acl);
+	}
+
+	/* Only directories can have default ACLs. */
+	if (S_ISDIR(archive_entry_mode(entry))) {
+		acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
+		if (acl != NULL) {
+			setup_acl_posix1e(a, entry, acl,
+			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
+			acl_free(acl);
+		}
+	}
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Translate POSIX.1e ACL into libarchive internal structure.
+ */
+static void
+setup_acl_posix1e(struct archive_read_disk *a,
+    struct archive_entry *entry, acl_t acl, int archive_entry_acl_type)
+{
+	acl_tag_t	 acl_tag;
+	acl_entry_t	 acl_entry;
+	acl_permset_t	 acl_permset;
+	int		 s, ae_id, ae_tag, ae_perm;
+	const char	*ae_name;
+
+	s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
+	while (s == 1) {
+		ae_id = -1;
+		ae_name = NULL;
+
+		acl_get_tag_type(acl_entry, &acl_tag);
+		if (acl_tag == ACL_USER) {
+			ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
+			ae_name = archive_read_disk_uname(&a->archive, ae_id);
+			ae_tag = ARCHIVE_ENTRY_ACL_USER;
+		} else if (acl_tag == ACL_GROUP) {
+			ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
+			ae_name = archive_read_disk_gname(&a->archive, ae_id);
+			ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+		} else if (acl_tag == ACL_MASK) {
+			ae_tag = ARCHIVE_ENTRY_ACL_MASK;
+		} else if (acl_tag == ACL_USER_OBJ) {
+			ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+		} else if (acl_tag == ACL_GROUP_OBJ) {
+			ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+		} else if (acl_tag == ACL_OTHER) {
+			ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
+		} else {
+			/* Skip types that libarchive can't support. */
+			continue;
+		}
+
+		acl_get_permset(acl_entry, &acl_permset);
+		ae_perm = 0;
+		/*
+		 * acl_get_perm() is spelled differently on different
+		 * platforms; see above.
+		 */
+		if (ACL_GET_PERM(acl_permset, ACL_EXECUTE))
+			ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
+		if (ACL_GET_PERM(acl_permset, ACL_READ))
+			ae_perm |= ARCHIVE_ENTRY_ACL_READ;
+		if (ACL_GET_PERM(acl_permset, ACL_WRITE))
+			ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
+
+		archive_entry_acl_add_entry(entry,
+		    archive_entry_acl_type, ae_perm, ae_tag,
+		    ae_id, ae_name);
+
+		s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
+	}
+}
+#else
+static int
+setup_acls_posix1e(struct archive_read_disk *a,
+    struct archive_entry *entry, int fd)
+{
+	(void)a;      /* UNUSED */
+	(void)entry;  /* UNUSED */
+	(void)fd;     /* UNUSED */
+	return (ARCHIVE_OK);
+}
+#endif
+
+#if HAVE_LISTXATTR && HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR
+
+/*
+ * Linux extended attribute support.
+ *
+ * TODO:  By using a stack-allocated buffer for the first
+ * call to getxattr(), we might be able to avoid the second
+ * call entirely.  We only need the second call if the
+ * stack-allocated buffer is too small.  But a modest buffer
+ * of 1024 bytes or so will often be big enough.  Same applies
+ * to listxattr().
+ */
+
+
+static int
+setup_xattr(struct archive_read_disk *a,
+    struct archive_entry *entry, const char *name, 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 = lgetxattr(accpath, name, NULL, 0);
+	else
+		size = getxattr(accpath, 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 = lgetxattr(accpath, name, value, size);
+	else
+		size = getxattr(accpath, 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, name, value, size);
+
+	free(value);
+	return (ARCHIVE_OK);
+}
+
+static int
+setup_xattrs(struct archive_read_disk *a,
+    struct archive_entry *entry, int fd)
+{
+	char *list, *p;
+	const char *path;
+	ssize_t list_size;
+
+
+	path = archive_entry_sourcepath(entry);
+	if (path == NULL)
+		path = archive_entry_pathname(entry);
+
+	if (!a->follow_symlinks)
+		list_size = llistxattr(path, NULL, 0);
+	else
+		list_size = listxattr(path, NULL, 0);
+
+	if (list_size == -1) {
+		if (errno == ENOTSUP)
+			return (ARCHIVE_OK);
+		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 = llistxattr(path, list, list_size);
+	else
+		list_size = listxattr(path, list, list_size);
+
+	if (list_size == -1) {
+		archive_set_error(&a->archive, errno,
+			"Couldn't retrieve extended attributes");
+		free(list);
+		return (ARCHIVE_WARN);
+	}
+
+	for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
+		if (strncmp(p, "system.", 7) == 0 ||
+				strncmp(p, "xfsroot.", 8) == 0)
+			continue;
+		setup_xattr(a, entry, p, fd);
+	}
+
+	free(list);
+	return (ARCHIVE_OK);
+}
+
+#elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE
+
+/*
+ * FreeBSD extattr interface.
+ */
+
+/* TODO: Implement this.  Follow the Linux model above, but
+ * with FreeBSD-specific system calls, of course.  Be careful
+ * to not include the system extattrs that hold ACLs; we handle
+ * those separately.
+ */
+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);
+}
+
+static int
+setup_xattrs(struct archive_read_disk *a,
+    struct archive_entry *entry, int fd)
+{
+	char buff[512];
+	char *list, *p;
+	ssize_t list_size;
+	const char *path;
+	int namespace = EXTATTR_NAMESPACE_USER;
+
+	path = archive_entry_sourcepath(entry);
+	if (path == NULL)
+		path = archive_entry_pathname(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 && errno == EOPNOTSUPP)
+		return (ARCHIVE_OK);
+	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);
+}
+
+#else
+
+/*
+ * Generic (stub) extended attribute support.
+ */
+static int
+setup_xattrs(struct archive_read_disk *a,
+    struct archive_entry *entry, int fd)
+{
+	(void)a;     /* UNUSED */
+	(void)entry; /* UNUSED */
+	(void)fd;    /* UNUSED */
+	return (ARCHIVE_OK);
+}
+
+#endif

Added: head/lib/libarchive/archive_read_disk_private.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libarchive/archive_read_disk_private.h	Fri Mar  6 04:35:31 2009	(r189429)
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+
+struct archive_read_disk {
+	struct archive	archive;
+
+	/*
+	 * Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid,
+	 * following an old BSD convention.  'L' follows all symlinks,
+	 * 'P' follows none, 'H' follows symlinks only for the first
+	 * item.
+	 */
+	char	symlink_mode;
+
+	/*
+	 * Since symlink interaction changes, we need to track whether
+	 * we're following symlinks for the current item.  'L' mode above
+	 * sets this true, 'P' sets it false, 'H' changes it as we traverse.
+	 */
+	char	follow_symlinks;  /* Either 'L' or 'P'. */
+
+	const char * (*lookup_gname)(void *private, gid_t gid);
+	void	(*cleanup_gname)(void *private);
+	void	 *lookup_gname_data;
+	const char * (*lookup_uname)(void *private, gid_t gid);
+	void	(*cleanup_uname)(void *private);
+	void	 *lookup_uname_data;
+};
+
+#endif

Added: head/lib/libarchive/archive_read_disk_set_standard_lookup.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libarchive/archive_read_disk_set_standard_lookup.c	Fri Mar  6 04:35:31 2009	(r189429)
@@ -0,0 +1,229 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+
+#ifdef _WIN32
+int
+archive_read_disk_set_standard_lookup(struct archive *a)
+{
+	archive_set_error(a, -1, "Standard lookups not available on Windows");
+	return (ARCHIVE_FATAL);
+}
+#else
+#define	name_cache_size 127
+
+static const char * const NO_NAME = "(noname)";
+
+struct name_cache {
+	struct archive *archive;
+	int	probes;
+	int	hits;
+	size_t	size;
+	struct {
+		id_t id;
+		const char *name;
+	} cache[name_cache_size];
+};
+
+static const char *	lookup_gname(void *, gid_t);
+static const char *	lookup_uname(void *, uid_t);
+static void	cleanup(void *);
+static const char *	lookup_gname_helper(struct archive *, id_t gid);
+static const char *	lookup_uname_helper(struct archive *, id_t uid);
+
+/*
+ * Installs functions that use getpwuid()/getgrgid()---along with
+ * a simple cache to accelerate such lookups---into the archive_read_disk
+ * object.  This is in a separate file because getpwuid()/getgrgid()
+ * can pull in a LOT of library code (including NIS/LDAP functions, which
+ * pull in DNS resolveers, etc).  This can easily top 500kB, which makes
+ * it inappropriate for some space-constrained applications.
+ *
+ * Applications that are size-sensitive may want to just use the
+ * real default functions (defined in archive_read_disk.c) that just
+ * use the uid/gid without the lookup.  Or define your own custom functions
+ * if you prefer.
+ */
+int
+archive_read_disk_set_standard_lookup(struct archive *a)
+{
+	struct name_cache *ucache = malloc(sizeof(struct name_cache));
+	struct name_cache *gcache = malloc(sizeof(struct name_cache));
+
+	if (ucache == NULL || gcache == NULL) {
+		archive_set_error(a, ENOMEM,
+		    "Can't allocate uname/gname lookup cache");
+		free(ucache);
+		free(gcache);
+		return (ARCHIVE_FATAL);
+	}
+
+	memset(ucache, 0, sizeof(*ucache));
+	ucache->archive = a;
+	ucache->size = name_cache_size;
+	memset(gcache, 0, sizeof(*gcache));
+	gcache->archive = a;
+	gcache->size = name_cache_size;
+
+	archive_read_disk_set_gname_lookup(a, gcache, lookup_gname, cleanup);
+	archive_read_disk_set_uname_lookup(a, ucache, lookup_uname, cleanup);
+
+	return (ARCHIVE_OK);
+}
+
+static void
+cleanup(void *data)
+{
+	struct name_cache *cache = (struct name_cache *)data;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list