file_cmds-287.40.2.tar.gz
[apple/file_cmds.git] / pax / cache.c
1 /* $OpenBSD: cache.c,v 1.17 2004/03/16 03:28:34 tedu Exp $ */
2 /* $NetBSD: cache.c,v 1.4 1995/03/21 09:07:10 cgd Exp $ */
3
4 /*-
5 * Copyright (c) 1992 Keith Muller.
6 * Copyright (c) 1992, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Keith Muller of the University of California, San Diego.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 #if 0
40 static const char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
41 #else
42 __used static const char rcsid[] = "$OpenBSD: cache.c,v 1.17 2004/03/16 03:28:34 tedu Exp $";
43 #endif
44 #endif /* not lint */
45
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <sys/stat.h>
49 #include <sys/param.h>
50 #include <string.h>
51 #include <stdio.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include "pax.h"
57 #include "cache.h"
58 #include "extern.h"
59
60 /*
61 * routines that control user, group, uid and gid caches (for the archive
62 * member print routine).
63 * IMPORTANT:
64 * these routines cache BOTH hits and misses, a major performance improvement
65 */
66
67 static int pwopn = 0; /* is password file open */
68 static int gropn = 0; /* is group file open */
69 static UIDC **uidtb = NULL; /* uid to name cache */
70 static GIDC **gidtb = NULL; /* gid to name cache */
71 static UIDC **usrtb = NULL; /* user name to uid cache */
72 static GIDC **grptb = NULL; /* group name to gid cache */
73
74 /*
75 * uidtb_start
76 * creates an empty uidtb
77 * Return:
78 * 0 if ok, -1 otherwise
79 */
80
81 int
82 uidtb_start(void)
83 {
84 static int fail = 0;
85
86 if (uidtb != NULL)
87 return(0);
88 if (fail)
89 return(-1);
90 if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
91 ++fail;
92 paxwarn(1, "Unable to allocate memory for user id cache table");
93 return(-1);
94 }
95 return(0);
96 }
97
98 /*
99 * gidtb_start
100 * creates an empty gidtb
101 * Return:
102 * 0 if ok, -1 otherwise
103 */
104
105 int
106 gidtb_start(void)
107 {
108 static int fail = 0;
109
110 if (gidtb != NULL)
111 return(0);
112 if (fail)
113 return(-1);
114 if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
115 ++fail;
116 paxwarn(1, "Unable to allocate memory for group id cache table");
117 return(-1);
118 }
119 return(0);
120 }
121
122 /*
123 * usrtb_start
124 * creates an empty usrtb
125 * Return:
126 * 0 if ok, -1 otherwise
127 */
128
129 int
130 usrtb_start(void)
131 {
132 static int fail = 0;
133
134 if (usrtb != NULL)
135 return(0);
136 if (fail)
137 return(-1);
138 if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
139 ++fail;
140 paxwarn(1, "Unable to allocate memory for user name cache table");
141 return(-1);
142 }
143 return(0);
144 }
145
146 /*
147 * grptb_start
148 * creates an empty grptb
149 * Return:
150 * 0 if ok, -1 otherwise
151 */
152
153 int
154 grptb_start(void)
155 {
156 static int fail = 0;
157
158 if (grptb != NULL)
159 return(0);
160 if (fail)
161 return(-1);
162 if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
163 ++fail;
164 paxwarn(1,"Unable to allocate memory for group name cache table");
165 return(-1);
166 }
167 return(0);
168 }
169
170 /*
171 * name_uid()
172 * caches the name (if any) for the uid. If frc set, we always return the
173 * the stored name (if valid or invalid match). We use a simple hash table.
174 * Return
175 * Pointer to stored name (or a empty string)
176 */
177
178 char *
179 name_uid(uid_t uid, int frc)
180 {
181 struct passwd *pw;
182 UIDC *ptr;
183
184 if ((uidtb == NULL) && (uidtb_start() < 0))
185 return("");
186
187 /*
188 * see if we have this uid cached
189 */
190 ptr = uidtb[uid % UID_SZ];
191 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
192 /*
193 * have an entry for this uid
194 */
195 if (frc || (ptr->valid == VALID))
196 return(ptr->name);
197 return("");
198 }
199
200 /*
201 * No entry for this uid, we will add it
202 */
203 if (!pwopn) {
204 setpassent(1);
205 ++pwopn;
206 }
207 if (ptr == NULL)
208 ptr = uidtb[uid % UID_SZ] = malloc(sizeof(UIDC));
209
210 if ((pw = getpwuid(uid)) == NULL) {
211 /*
212 * no match for this uid in the local password file
213 * a string that is the uid in numeric format
214 */
215 if (ptr == NULL)
216 return("");
217 ptr->uid = uid;
218 ptr->valid = INVALID;
219 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
220 (unsigned long)uid);
221 if (frc == 0)
222 return("");
223 } else {
224 /*
225 * there is an entry for this uid in the password file
226 */
227 if (ptr == NULL)
228 return(pw->pw_name);
229 ptr->uid = uid;
230 (void)strlcpy(ptr->name, pw->pw_name, sizeof(ptr->name));
231 ptr->valid = VALID;
232 }
233 return(ptr->name);
234 }
235
236 /*
237 * name_gid()
238 * caches the name (if any) for the gid. If frc set, we always return the
239 * the stored name (if valid or invalid match). We use a simple hash table.
240 * Return
241 * Pointer to stored name (or a empty string)
242 */
243
244 char *
245 name_gid(gid_t gid, int frc)
246 {
247 struct group *gr;
248 GIDC *ptr;
249
250 if ((gidtb == NULL) && (gidtb_start() < 0))
251 return("");
252
253 /*
254 * see if we have this gid cached
255 */
256 ptr = gidtb[gid % GID_SZ];
257 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
258 /*
259 * have an entry for this gid
260 */
261 if (frc || (ptr->valid == VALID))
262 return(ptr->name);
263 return("");
264 }
265
266 /*
267 * No entry for this gid, we will add it
268 */
269 if (!gropn) {
270 setgroupent(1);
271 ++gropn;
272 }
273 if (ptr == NULL)
274 ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC));
275
276 if ((gr = getgrgid(gid)) == NULL) {
277 /*
278 * no match for this gid in the local group file, put in
279 * a string that is the gid in numberic format
280 */
281 if (ptr == NULL)
282 return("");
283 ptr->gid = gid;
284 ptr->valid = INVALID;
285 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
286 (unsigned long)gid);
287 if (frc == 0)
288 return("");
289 } else {
290 /*
291 * there is an entry for this group in the group file
292 */
293 if (ptr == NULL)
294 return(gr->gr_name);
295 ptr->gid = gid;
296 (void)strlcpy(ptr->name, gr->gr_name, sizeof(ptr->name));
297 ptr->valid = VALID;
298 }
299 return(ptr->name);
300 }
301
302 /*
303 * uid_name()
304 * caches the uid for a given user name. We use a simple hash table.
305 * Return
306 * the uid (if any) for a user name, or a -1 if no match can be found
307 */
308
309 int
310 uid_name(char *name, uid_t *uid)
311 {
312 struct passwd *pw;
313 UIDC *ptr;
314 int namelen;
315
316 /*
317 * return -1 for mangled names
318 */
319 if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
320 return(-1);
321 if ((usrtb == NULL) && (usrtb_start() < 0))
322 return(-1);
323
324 /*
325 * look up in hash table, if found and valid return the uid,
326 * if found and invalid, return a -1
327 */
328 ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
329 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
330 if (ptr->valid == INVALID)
331 return(-1);
332 *uid = ptr->uid;
333 return(0);
334 }
335
336 if (!pwopn) {
337 setpassent(1);
338 ++pwopn;
339 }
340
341 if (ptr == NULL)
342 ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
343 (UIDC *)malloc(sizeof(UIDC));
344
345 /*
346 * no match, look it up, if no match store it as an invalid entry,
347 * or store the matching uid
348 */
349 if (ptr == NULL) {
350 if ((pw = getpwnam(name)) == NULL)
351 return(-1);
352 *uid = pw->pw_uid;
353 return(0);
354 }
355 (void)strlcpy(ptr->name, name, sizeof(ptr->name));
356 if ((pw = getpwnam(name)) == NULL) {
357 ptr->valid = INVALID;
358 return(-1);
359 }
360 ptr->valid = VALID;
361 *uid = ptr->uid = pw->pw_uid;
362 return(0);
363 }
364
365 /*
366 * gid_name()
367 * caches the gid for a given group name. We use a simple hash table.
368 * Return
369 * the gid (if any) for a group name, or a -1 if no match can be found
370 */
371
372 int
373 gid_name(char *name, gid_t *gid)
374 {
375 struct group *gr;
376 GIDC *ptr;
377 int namelen;
378
379 /*
380 * return -1 for mangled names
381 */
382 if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
383 return(-1);
384 if ((grptb == NULL) && (grptb_start() < 0))
385 return(-1);
386
387 /*
388 * look up in hash table, if found and valid return the uid,
389 * if found and invalid, return a -1
390 */
391 ptr = grptb[st_hash(name, namelen, GID_SZ)];
392 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
393 if (ptr->valid == INVALID)
394 return(-1);
395 *gid = ptr->gid;
396 return(0);
397 }
398
399 if (!gropn) {
400 setgroupent(1);
401 ++gropn;
402 }
403 if (ptr == NULL)
404 ptr = grptb[st_hash(name, namelen, GID_SZ)] =
405 (GIDC *)malloc(sizeof(GIDC));
406
407 /*
408 * no match, look it up, if no match store it as an invalid entry,
409 * or store the matching gid
410 */
411 if (ptr == NULL) {
412 if ((gr = getgrnam(name)) == NULL)
413 return(-1);
414 *gid = gr->gr_gid;
415 return(0);
416 }
417
418 (void)strlcpy(ptr->name, name, sizeof(ptr->name));
419 if ((gr = getgrnam(name)) == NULL) {
420 ptr->valid = INVALID;
421 return(-1);
422 }
423 ptr->valid = VALID;
424 *gid = ptr->gid = gr->gr_gid;
425 return(0);
426 }