2
* Copyright (c) 2003-2007 Tim Kientzle
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
#include "archive_platform.h"
27
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk_set_standard_lookup.c 201083 2009-12-28 02:09:57Z kientzle $");
29
#ifdef HAVE_SYS_TYPES_H
30
#include <sys/types.h>
49
#include "archive_private.h"
50
#include "archive_read_private.h"
51
#include "archive_write_disk_private.h"
59
static const size_t cache_size = 127;
60
static unsigned int hash(const char *);
61
static gid_t lookup_gid(void *, const char *uname, gid_t);
62
static uid_t lookup_uid(void *, const char *uname, uid_t);
63
static void cleanup(void *);
66
* Installs functions that use getpwnam()/getgrnam()---along with
67
* a simple cache to accelerate such lookups---into the archive_write_disk
68
* object. This is in a separate file because getpwnam()/getgrnam()
69
* can pull in a LOT of library code (including NIS/LDAP functions, which
70
* pull in DNS resolveers, etc). This can easily top 500kB, which makes
71
* it inappropriate for some space-constrained applications.
73
* Applications that are size-sensitive may want to just use the
74
* real default functions (defined in archive_write_disk.c) that just
75
* use the uid/gid without the lookup. Or define your own custom functions
78
* TODO: Replace these hash tables with simpler move-to-front LRU
79
* lists with a bounded size (128 items?). The hash is a bit faster,
80
* but has a bad pathology in which it thrashes a single bucket. Even
81
* walking a list of 128 items is a lot faster than calling
85
archive_write_disk_set_standard_lookup(struct archive *a)
87
struct bucket *ucache = malloc(cache_size * sizeof(struct bucket));
88
struct bucket *gcache = malloc(cache_size * sizeof(struct bucket));
89
memset(ucache, 0, cache_size * sizeof(struct bucket));
90
memset(gcache, 0, cache_size * sizeof(struct bucket));
91
archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup);
92
archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup);
97
lookup_gid(void *private_data, const char *gname, gid_t gid)
101
struct bucket *gcache = (struct bucket *)private_data;
103
/* If no gname, just use the gid provided. */
104
if (gname == NULL || *gname == '\0')
107
/* Try to find gname in the cache. */
109
b = &gcache[h % cache_size ];
110
if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0)
111
return ((gid_t)b->id);
113
/* Free the cache slot for a new entry. */
116
b->name = strdup(gname);
117
/* Note: If strdup fails, that's okay; we just won't cache. */
123
size_t bufsize = 128;
124
char *buffer = _buffer;
125
struct group grent, *result;
129
result = &grent; /* Old getgrnam_r ignores last arg. */
130
r = getgrnam_r(gname, &grent, buffer, bufsize, &result);
136
if (buffer != _buffer)
138
buffer = malloc(bufsize);
143
gid = result->gr_gid;
144
if (buffer != _buffer)
147
# else /* HAVE_GETGRNAM_R */
149
struct group *result;
151
result = getgrnam(gname);
153
gid = result->gr_gid;
155
# endif /* HAVE_GETGRNAM_R */
156
#elif defined(_WIN32) && !defined(__CYGWIN__)
157
/* TODO: do a gname->gid lookup for Windows. */
159
#error No way to perform gid lookups on this platform
167
lookup_uid(void *private_data, const char *uname, uid_t uid)
171
struct bucket *ucache = (struct bucket *)private_data;
173
/* If no uname, just use the uid provided. */
174
if (uname == NULL || *uname == '\0')
177
/* Try to find uname in the cache. */
179
b = &ucache[h % cache_size ];
180
if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0)
181
return ((uid_t)b->id);
183
/* Free the cache slot for a new entry. */
186
b->name = strdup(uname);
187
/* Note: If strdup fails, that's okay; we just won't cache. */
193
size_t bufsize = 128;
194
char *buffer = _buffer;
195
struct passwd pwent, *result;
199
result = &pwent; /* Old getpwnam_r ignores last arg. */
200
r = getpwnam_r(uname, &pwent, buffer, bufsize, &result);
206
if (buffer != _buffer)
208
buffer = malloc(bufsize);
213
uid = result->pw_uid;
214
if (buffer != _buffer)
217
# else /* HAVE_GETPWNAM_R */
219
struct passwd *result;
221
result = getpwnam(uname);
223
uid = result->pw_uid;
225
#endif /* HAVE_GETPWNAM_R */
226
#elif defined(_WIN32) && !defined(__CYGWIN__)
227
/* TODO: do a uname->uid lookup for Windows. */
229
#error No way to look up uids on this platform
237
cleanup(void *private)
240
struct bucket *cache = (struct bucket *)private;
242
for (i = 0; i < cache_size; i++)
251
/* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
252
as used by ELF for hashing function names. */
256
if ((g = h & 0xF0000000) != 0) {