archive_entry_link_resolver.c \
archive_read.c \
archive_read_data_into_fd.c \
+ archive_read_disk.c \
+ archive_read_disk_set_standard_lookup.c \
archive_read_extract.c \
archive_read_open_fd.c \
archive_read_open_file.c \
__LA_UID_T (*)(void *, const char *, __LA_UID_T),
void (* /* cleanup */)(void *));
+/*
+ * ARCHIVE_READ_DISK API
+ */
+__LA_DECL struct archive *archive_read_disk_new(void);
+__LA_DECL int archive_read_disk_set_standard_lookup(struct archive *);
+__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);
+__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:
--- /dev/null
+/*-
+ * 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 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;
+ }
+ 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);
+}
+
+/*
+ * 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);
+}
--- /dev/null
+/*-
+ * 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;
+
+ 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
--- /dev/null
+/*-
+ * 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"
+
+#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;
+ size_t i;
+
+ if (cache != NULL) {
+ for (i = 0; i < cache->size; i++) {
+ if (cache->cache[i].name != NULL &&
+ cache->cache[i].name != NO_NAME)
+ free((void *)(uintptr_t)cache->cache[i].name);
+ }
+ free(cache);
+ }
+}
+
+/*
+ * Lookup uid/gid from uname/gname, return NULL if no match.
+ */
+static const char *
+lookup_name(struct name_cache *cache,
+ const char * (*lookup_fn)(struct archive *, id_t), id_t id)
+{
+ const char *name;
+ int slot;
+
+
+ cache->probes++;
+
+ slot = id % cache->size;
+ if (cache->cache[slot].name != NULL) {
+ if (cache->cache[slot].id == id) {
+ cache->hits++;
+ if (cache->cache[slot].name == NO_NAME)
+ return (NULL);
+ return (cache->cache[slot].name);
+ }
+ if (cache->cache[slot].name != NO_NAME)
+ free((void *)(uintptr_t)cache->cache[slot].name);
+ cache->cache[slot].name = NULL;
+ }
+
+ name = (lookup_fn)(cache->archive, id);
+ if (name == NULL) {
+ /* Cache and return the negative response. */
+ cache->cache[slot].name = NO_NAME;
+ cache->cache[slot].id = id;
+ return (NULL);
+ }
+
+ cache->cache[slot].name = name;
+ cache->cache[slot].id = id;
+ return (cache->cache[slot].name);
+}
+
+static const char *
+lookup_uname(void *data, uid_t uid)
+{
+ struct name_cache *uname_cache = (struct name_cache *)data;
+ return (lookup_name(uname_cache,
+ &lookup_uname_helper, (id_t)uid));
+}
+
+static const char *
+lookup_uname_helper(struct archive *a, id_t id)
+{
+ char buffer[64];
+ struct passwd pwent, *result;
+ int r;
+
+ errno = 0;
+ r = getpwuid_r((uid_t)id, &pwent, buffer, sizeof(buffer), &result);
+ if (r != 0) {
+ archive_set_error(a, errno,
+ "Can't lookup user for id %d", (int)id);
+ return (NULL);
+ }
+ if (result == NULL)
+ return (NULL);
+
+ return strdup(pwent.pw_name);
+}
+
+static const char *
+lookup_gname(void *data, gid_t gid)
+{
+ struct name_cache *gname_cache = (struct name_cache *)data;
+ return (lookup_name(gname_cache,
+ &lookup_gname_helper, (id_t)gid));
+}
+
+static const char *
+lookup_gname_helper(struct archive *a, id_t id)
+{
+ char buffer[64];
+ struct group grent, *result;
+ int r;
+
+ errno = 0;
+ r = getgrgid_r((gid_t)id, &grent, buffer, sizeof(buffer), &result);
+ if (r != 0) {
+ archive_set_error(a, errno,
+ "Can't lookup group for id %d", (int)id);
+ return (NULL);
+ }
+ if (result == NULL)
+ return (NULL);
+
+ return strdup(grent.gr_name);
+}
test_pax_filename_encoding.c \
test_read_compress_program.c \
test_read_data_large.c \
+ test_read_disk.c \
test_read_extract.c \
test_read_format_ar.c \
test_read_format_cpio_bin.c \
--- /dev/null
+/*-
+ * 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 "test.h"
+__FBSDID("$FreeBSD$");
+
+static void
+gname_cleanup(void *d)
+{
+ int *mp = d;
+ assertEqualInt(*mp, 0x13579);
+ *mp = 0x2468;
+}
+
+static const char *
+gname_lookup(void *d, gid_t g)
+{
+ int *mp = d;
+ assertEqualInt(*mp, 0x13579);
+ if (g == 1)
+ return ("FOOGROUP");
+ return ("NOTFOOGROUP");
+}
+
+static void
+uname_cleanup(void *d)
+{
+ int *mp = d;
+ assertEqualInt(*mp, 0x1234);
+ *mp = 0x2345;
+}
+
+static const char *
+uname_lookup(void *d, uid_t u)
+{
+ int *mp = d;
+ assertEqualInt(*mp, 0x1234);
+ if (u == 1)
+ return ("FOO");
+ return ("NOTFOO");
+}
+
+DEFINE_TEST(test_read_disk)
+{
+ struct archive *a;
+ int gmagic = 0x13579, umagic = 0x1234;
+
+ assert((a = archive_read_disk_new()) != NULL);
+
+ /* Default uname/gname lookups always return NULL. */
+ assert(archive_read_disk_gname(a, 0) == NULL);
+ assert(archive_read_disk_uname(a, 0) == NULL);
+
+ /* Register some weird lookup functions. */
+ assertEqualInt(ARCHIVE_OK, archive_read_disk_set_gname_lookup(a,
+ &gmagic, &gname_lookup, &gname_cleanup));
+ /* Verify that our new function got called. */
+ assertEqualString(archive_read_disk_gname(a, 0), "NOTFOOGROUP");
+ assertEqualString(archive_read_disk_gname(a, 1), "FOOGROUP");
+
+ /* De-register. */
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_set_gname_lookup(a, NULL, NULL, NULL));
+ /* Ensure our cleanup function got called. */
+ assertEqualInt(gmagic, 0x2468);
+
+ /* Same thing with uname lookup.... */
+ assertEqualInt(ARCHIVE_OK, archive_read_disk_set_uname_lookup(a,
+ &umagic, &uname_lookup, &uname_cleanup));
+ assertEqualString(archive_read_disk_uname(a, 0), "NOTFOO");
+ assertEqualString(archive_read_disk_uname(a, 1), "FOO");
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_set_uname_lookup(a, NULL, NULL, NULL));
+ assertEqualInt(umagic, 0x2345);
+
+ /* Try the standard lookup functions. */
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_set_standard_lookup(a));
+ assertEqualString(archive_read_disk_uname(a, 0), "root");
+ assertEqualString(archive_read_disk_gname(a, 0), "wheel");
+
+ /* Deregister again and verify the default lookups again. */
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_set_gname_lookup(a, NULL, NULL, NULL));
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_set_uname_lookup(a, NULL, NULL, NULL));
+ assert(archive_read_disk_gname(a, 0) == NULL);
+ assert(archive_read_disk_uname(a, 0) == NULL);
+
+ /* Re-register our custom handlers. */
+ gmagic = 0x13579;
+ umagic = 0x1234;
+ assertEqualInt(ARCHIVE_OK, archive_read_disk_set_gname_lookup(a,
+ &gmagic, &gname_lookup, &gname_cleanup));
+ assertEqualInt(ARCHIVE_OK, archive_read_disk_set_uname_lookup(a,
+ &umagic, &uname_lookup, &uname_cleanup));
+
+ /* Destroy the archive. */
+ assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+
+ /* Verify our cleanup functions got called. */
+ assertEqualInt(gmagic, 0x2468);
+ assertEqualInt(umagic, 0x2345);
+}