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