From: Tim Kientzle Date: Mon, 19 Dec 2011 01:05:50 +0000 (-0500) Subject: Refactor the UID/GID lookup in write_disk so that it can be X-Git-Tag: v3.0.2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4f791ea7c9a4632152c252db7d84a35b787fbef;p=thirdparty%2Flibarchive.git Refactor the UID/GID lookup in write_disk so that it can be called from outside of this module. SVN-Revision: 3943 --- diff --git a/Makefile.am b/Makefile.am index 1cdaea063..5775432d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -382,6 +382,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_write_disk.c \ libarchive/test/test_write_disk_failures.c \ libarchive/test/test_write_disk_hardlink.c \ + libarchive/test/test_write_disk_lookup.c \ libarchive/test/test_write_disk_perms.c \ libarchive/test/test_write_disk_secure.c \ libarchive/test/test_write_disk_sparse.c \ diff --git a/libarchive/archive.h b/libarchive/archive.h index c4fcd0c8d..14c2aed98 100644 --- a/libarchive/archive.h +++ b/libarchive/archive.h @@ -724,6 +724,8 @@ __LA_DECL int archive_write_disk_set_user_lookup(struct archive *, void * /* private_data */, __LA_INT64_T (*)(void *, const char *, __LA_INT64_T), void (* /* cleanup */)(void *)); +__LA_DECL __LA_INT64_T archive_write_disk_gid(struct archive *, const char *, __LA_INT64_T); +__LA_DECL __LA_INT64_T archive_write_disk_uid(struct archive *, const char *, __LA_INT64_T); /* * ARCHIVE_READ_DISK API diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c index 98356a942..99afab2f6 100644 --- a/libarchive/archive_write_disk_posix.c +++ b/libarchive/archive_write_disk_posix.c @@ -286,8 +286,6 @@ static int set_times(struct archive_write_disk *, int, int, const char *, time_t, long, time_t, long, time_t, long, time_t, long); static int set_times_from_entry(struct archive_write_disk *); static struct fixup_entry *sort_dir_list(struct fixup_entry *p); -static int64_t trivial_lookup_gid(void *, const char *, int64_t); -static int64_t trivial_lookup_uid(void *, const char *, int64_t); static ssize_t write_data_block(struct archive_write_disk *, const char *, size_t); @@ -805,14 +803,14 @@ _archive_write_disk_finish_entry(struct archive *_a) * TODO: the TODO_SGID condition can be dropped here, can't it? */ if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { - a->uid = a->lookup_uid(a->lookup_uid_data, + a->uid = archive_write_disk_uid(&a->archive, archive_entry_uname(a->entry), archive_entry_uid(a->entry)); } /* Look up the "real" GID only if we're going to need it. */ /* TODO: the TODO_SUID condition can be dropped here, can't it? */ if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { - a->gid = a->lookup_gid(a->lookup_gid_data, + a->gid = archive_write_disk_gid(&a->archive, archive_entry_gname(a->entry), archive_entry_gid(a->entry)); } @@ -910,6 +908,9 @@ archive_write_disk_set_group_lookup(struct archive *_a, archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); + if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) + (a->cleanup_gid)(a->lookup_gid_data); + a->lookup_gid = lookup_gid; a->cleanup_gid = cleanup_gid; a->lookup_gid_data = private_data; @@ -926,12 +927,36 @@ archive_write_disk_set_user_lookup(struct archive *_a, archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); + if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) + (a->cleanup_uid)(a->lookup_uid_data); + a->lookup_uid = lookup_uid; a->cleanup_uid = cleanup_uid; a->lookup_uid_data = private_data; return (ARCHIVE_OK); } +int64_t +archive_write_disk_gid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_gid"); + if (a->lookup_gid) + return (a->lookup_gid)(a->lookup_gid_data, name, id); + return (id); +} + +int64_t +archive_write_disk_uid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_uid"); + if (a->lookup_uid) + return (a->lookup_uid)(a->lookup_uid_data, name, id); + return (id); +} /* * Create a new archive_write_disk object and initialize it with global state. @@ -949,8 +974,6 @@ archive_write_disk_new(void) /* We're ready to write a header immediately. */ a->archive.state = ARCHIVE_STATE_HEADER; a->archive.vtable = archive_write_disk_vtable(); - a->lookup_uid = trivial_lookup_uid; - a->lookup_gid = trivial_lookup_gid; a->start_time = time(NULL); /* Query and restore the umask. */ umask(a->user_umask = umask(0)); @@ -1386,10 +1409,8 @@ _archive_write_disk_free(struct archive *_a) ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); a = (struct archive_write_disk *)_a; ret = _archive_write_disk_close(&a->archive); - if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) - (a->cleanup_gid)(a->lookup_gid_data); - if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) - (a->cleanup_uid)(a->lookup_uid_data); + archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); + archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); if (a->entry) archive_entry_free(a->entry); archive_string_free(&a->_name_data); @@ -2571,13 +2592,13 @@ set_acl(struct archive_write_disk *a, int fd, const char *name, switch (ae_tag) { case ARCHIVE_ENTRY_ACL_USER: acl_set_tag_type(acl_entry, ACL_USER); - ae_uid = a->lookup_uid(a->lookup_uid_data, + ae_uid = archive_write_disk_uid(&a->archive, ae_name, ae_id); acl_set_qualifier(acl_entry, &ae_uid); break; case ARCHIVE_ENTRY_ACL_GROUP: acl_set_tag_type(acl_entry, ACL_GROUP); - ae_gid = a->lookup_gid(a->lookup_gid_data, + ae_gid = archive_write_disk_gid(&a->archive, ae_name, ae_id); acl_set_qualifier(acl_entry, &ae_gid); break; @@ -2778,28 +2799,6 @@ set_xattrs(struct archive_write_disk *a) } #endif - -/* - * Trivial implementations of gid/uid lookup functions. - * These are normally overridden by the client, but these stub - * versions ensure that we always have something that works. - */ -static int64_t -trivial_lookup_gid(void *private_data, const char *gname, int64_t gid) -{ - (void)private_data; /* UNUSED */ - (void)gname; /* UNUSED */ - return (gid); -} - -static int64_t -trivial_lookup_uid(void *private_data, const char *uname, int64_t uid) -{ - (void)private_data; /* UNUSED */ - (void)uname; /* UNUSED */ - return (uid); -} - /* * Test if file on disk is older than entry. */ diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c index 92d54e041..9df9ddc72 100644 --- a/libarchive/archive_write_disk_windows.c +++ b/libarchive/archive_write_disk_windows.c @@ -236,8 +236,6 @@ static int set_times(struct archive_write_disk *, HANDLE, int, const wchar_t *, time_t, long, time_t, long, time_t, long, time_t, long); static int set_times_from_entry(struct archive_write_disk *); static struct fixup_entry *sort_dir_list(struct fixup_entry *p); -static int64_t trivial_lookup_gid(void *, const char *, int64_t); -static int64_t trivial_lookup_uid(void *, const char *, int64_t); static ssize_t write_data_block(struct archive_write_disk *, const char *, size_t); @@ -1090,14 +1088,14 @@ _archive_write_disk_finish_entry(struct archive *_a) * TODO: the TODO_SGID condition can be dropped here, can't it? */ if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { - a->uid = a->lookup_uid(a->lookup_uid_data, + a->uid = archive_write_disk_uid(&a->archive, archive_entry_uname(a->entry), archive_entry_uid(a->entry)); } /* Look up the "real" GID only if we're going to need it. */ /* TODO: the TODO_SUID condition can be dropped here, can't it? */ if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { - a->gid = a->lookup_gid(a->lookup_gid_data, + a->gid = archive_write_disk_gid(&a->archive, archive_entry_gname(a->entry), archive_entry_gid(a->entry)); } @@ -1182,6 +1180,9 @@ archive_write_disk_set_group_lookup(struct archive *_a, archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); + if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) + (a->cleanup_gid)(a->lookup_gid_data); + a->lookup_gid = lookup_gid; a->cleanup_gid = cleanup_gid; a->lookup_gid_data = private_data; @@ -1198,12 +1199,36 @@ archive_write_disk_set_user_lookup(struct archive *_a, archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); + if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) + (a->cleanup_uid)(a->lookup_uid_data); + a->lookup_uid = lookup_uid; a->cleanup_uid = cleanup_uid; a->lookup_uid_data = private_data; return (ARCHIVE_OK); } +int64_t +archive_write_disk_gid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_gid"); + if (a->lookup_gid) + return (a->lookup_gid)(a->lookup_gid_data, name, id); + return (id); +} + +int64_t +archive_write_disk_uid(struct archive *_a, const char *name, int64_t id) +{ + struct archive_write_disk *a = (struct archive_write_disk *)_a; + archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, + ARCHIVE_STATE_ANY, "archive_write_disk_uid"); + if (a->lookup_uid) + return (a->lookup_uid)(a->lookup_uid_data, name, id); + return (id); +} /* * Create a new archive_write_disk object and initialize it with global state. @@ -1221,8 +1246,6 @@ archive_write_disk_new(void) /* We're ready to write a header immediately. */ a->archive.state = ARCHIVE_STATE_HEADER; a->archive.vtable = archive_write_disk_vtable(); - a->lookup_uid = trivial_lookup_uid; - a->lookup_gid = trivial_lookup_gid; a->start_time = time(NULL); /* Query and restore the umask. */ umask(a->user_umask = umask(0)); @@ -1671,10 +1694,8 @@ _archive_write_disk_free(struct archive *_a) ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); a = (struct archive_write_disk *)_a; ret = _archive_write_disk_close(&a->archive); - if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) - (a->cleanup_gid)(a->lookup_gid_data); - if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) - (a->cleanup_uid)(a->lookup_uid_data); + archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); + archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); if (a->entry) archive_entry_free(a->entry); archive_wstring_free(&a->_name_data); @@ -2459,28 +2480,6 @@ set_xattrs(struct archive_write_disk *a) return (ARCHIVE_OK); } - -/* - * Trivial implementations of gid/uid lookup functions. - * These are normally overridden by the client, but these stub - * versions ensure that we always have something that works. - */ -static int64_t -trivial_lookup_gid(void *private_data, const char *gname, int64_t gid) -{ - (void)private_data; /* UNUSED */ - (void)gname; /* UNUSED */ - return (gid); -} - -static int64_t -trivial_lookup_uid(void *private_data, const char *uname, int64_t uid) -{ - (void)private_data; /* UNUSED */ - (void)uname; /* UNUSED */ - return (uid); -} - static void fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns) { diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 8bbe6a419..d9be74f19 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -142,6 +142,7 @@ IF(ENABLE_TEST) test_write_disk.c test_write_disk_failures.c test_write_disk_hardlink.c + test_write_disk_lookup.c test_write_disk_perms.c test_write_disk_secure.c test_write_disk_sparse.c diff --git a/libarchive/test/test_write_disk_lookup.c b/libarchive/test/test_write_disk_lookup.c new file mode 100644 index 000000000..54a63bb0a --- /dev/null +++ b/libarchive/test/test_write_disk_lookup.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2003-2010 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 +group_cleanup(void *d) +{ + int *mp = d; + assertEqualInt(*mp, 0x13579); + *mp = 0x2468; +} + +static int64_t +group_lookup(void *d, const char *name, int64_t g) +{ + int *mp = d; + assertEqualInt(*mp, 0x13579); + if (strcmp(name, "FOOGROUP")) + return (1); + return (73); +} + +static void +user_cleanup(void *d) +{ + int *mp = d; + assertEqualInt(*mp, 0x1234); + *mp = 0x2345; +} + +static int64_t +user_lookup(void *d, const char *name, int64_t u) +{ + int *mp = d; + assertEqualInt(*mp, 0x1234); + if (strcmp("FOO", name) == 0) + return (2); + return (74); +} + +DEFINE_TEST(test_write_disk_lookup) +{ + struct archive *a; + int gmagic = 0x13579, umagic = 0x1234; + int64_t id; + + assert((a = archive_write_disk_new()) != NULL); + + /* Default uname/gname lookups always return ID. */ + assertEqualInt(0, archive_write_disk_gid(a, "", 0)); + assertEqualInt(12, archive_write_disk_gid(a, "root", 12)); + assertEqualInt(12, archive_write_disk_gid(a, "wheel", 12)); + assertEqualInt(0, archive_write_disk_uid(a, "", 0)); + assertEqualInt(18, archive_write_disk_uid(a, "root", 18)); + + /* Register some weird lookup functions. */ + assertEqualInt(ARCHIVE_OK, archive_write_disk_set_group_lookup(a, + &gmagic, &group_lookup, &group_cleanup)); + /* Verify that our new function got called. */ + assertEqualInt(73, archive_write_disk_gid(a, "FOOGROUP", 8)); + assertEqualInt(1, archive_write_disk_gid(a, "NOTFOOGROUP", 8)); + + /* De-register. */ + assertEqualInt(ARCHIVE_OK, + archive_write_disk_set_group_lookup(a, NULL, NULL, NULL)); + /* Ensure our cleanup function got called. */ + assertEqualInt(gmagic, 0x2468); + + /* Same thing with uname lookup.... */ + assertEqualInt(ARCHIVE_OK, archive_write_disk_set_user_lookup(a, + &umagic, &user_lookup, &user_cleanup)); + assertEqualInt(2, archive_write_disk_uid(a, "FOO", 0)); + assertEqualInt(74, archive_write_disk_uid(a, "NOTFOO", 1)); + assertEqualInt(ARCHIVE_OK, + archive_write_disk_set_user_lookup(a, NULL, NULL, NULL)); + assertEqualInt(umagic, 0x2345); + + /* Try the standard lookup functions. */ + if (archive_write_disk_set_standard_lookup(a) != ARCHIVE_OK) { + skipping("standard uname/gname lookup"); + } else { + /* Try a few common names for group #0. */ + id = archive_write_disk_gid(a, "wheel", 8); + if (id != 0) + id = archive_write_disk_gid(a, "root", 8); + failure("Unable to verify lookup of group #0"); + assertEqualInt(0, id); + + /* Try a few common names for user #0. */ + id = archive_write_disk_uid(a, "root", 8); + failure("Unable to verify lookup of user #0"); + assertEqualInt(0, id); + } + + /* Deregister again and verify the default lookups again. */ + assertEqualInt(ARCHIVE_OK, + archive_write_disk_set_group_lookup(a, NULL, NULL, NULL)); + assertEqualInt(ARCHIVE_OK, + archive_write_disk_set_user_lookup(a, NULL, NULL, NULL)); + assertEqualInt(0, archive_write_disk_gid(a, "", 0)); + assertEqualInt(0, archive_write_disk_uid(a, "", 0)); + + /* Re-register our custom handlers. */ + gmagic = 0x13579; + umagic = 0x1234; + assertEqualInt(ARCHIVE_OK, archive_write_disk_set_group_lookup(a, + &gmagic, &group_lookup, &group_cleanup)); + assertEqualInt(ARCHIVE_OK, archive_write_disk_set_user_lookup(a, + &umagic, &user_lookup, &user_cleanup)); + + /* Destroy the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + /* Verify our cleanup functions got called. */ + assertEqualInt(gmagic, 0x2468); + assertEqualInt(umagic, 0x2345); +}