file_cmds-46.tar.gz
[apple/file_cmds.git] / pax / cache.c
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
43 static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
44 #else
45 static 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
70 static int pwopn = 0; /* is password file open */
71 static int gropn = 0; /* is group file open */
72 static UIDC **uidtb = NULL; /* uid to name cache */
73 static GIDC **gidtb = NULL; /* gid to name cache */
74 static UIDC **usrtb = NULL; /* user name to uid cache */
75 static 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__
85 int
86 uidtb_start(void)
87 #else
88 int
89 uidtb_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__
114 int
115 gidtb_start(void)
116 #else
117 int
118 gidtb_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__
143 int
144 usrtb_start(void)
145 #else
146 int
147 usrtb_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__
172 int
173 grptb_start(void)
174 #else
175 int
176 grptb_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__
202 char *
203 name_uid(uid_t uid, int frc)
204 #else
205 char *
206 name_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__
283 char *
284 name_gid(gid_t gid, int frc)
285 #else
286 char *
287 name_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__
364 int
365 uid_name(char *name, uid_t *uid)
366 #else
367 int
368 uid_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__
437 int
438 gid_name(char *name, gid_t *gid)
439 #else
440 int
441 gid_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 }