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