xref: /freebsd/bin/pax/cache.c (revision afe61c15161c324a7af299a9b8457aba5afc92db)
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 
38 #ifndef lint
39 static char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
40 #endif /* not lint */
41 
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/stat.h>
45 #include <sys/param.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include "pax.h"
54 #include "cache.h"
55 #include "extern.h"
56 
57 /*
58  * routines that control user, group, uid and gid caches (for the archive
59  * member print routine).
60  * IMPORTANT:
61  * these routines cache BOTH hits and misses, a major performance improvement
62  */
63 
64 static	int pwopn = 0;		/* is password file open */
65 static	int gropn = 0;		/* is group file open */
66 static UIDC **uidtb = NULL;	/* uid to name cache */
67 static GIDC **gidtb = NULL;	/* gid to name cache */
68 static UIDC **usrtb = NULL;	/* user name to uid cache */
69 static GIDC **grptb = NULL;	/* group name to gid cache */
70 
71 /*
72  * uidtb_start
73  *	creates an an empty uidtb
74  * Return:
75  *	0 if ok, -1 otherwise
76  */
77 
78 #if __STDC__
79 int
80 uidtb_start(void)
81 #else
82 int
83 uidtb_start()
84 #endif
85 {
86 	static int fail = 0;
87 
88 	if (uidtb != NULL)
89 		return(0);
90 	if (fail)
91 		return(-1);
92 	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
93 		++fail;
94 		warn(1, "Unable to allocate memory for user id cache table");
95 		return(-1);
96 	}
97 	return(0);
98 }
99 
100 /*
101  * gidtb_start
102  *	creates an an empty gidtb
103  * Return:
104  *	0 if ok, -1 otherwise
105  */
106 
107 #if __STDC__
108 int
109 gidtb_start(void)
110 #else
111 int
112 gidtb_start()
113 #endif
114 {
115 	static int fail = 0;
116 
117 	if (gidtb != NULL)
118 		return(0);
119 	if (fail)
120 		return(-1);
121 	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
122 		++fail;
123 		warn(1, "Unable to allocate memory for group id cache table");
124 		return(-1);
125 	}
126 	return(0);
127 }
128 
129 /*
130  * usrtb_start
131  *	creates an an empty usrtb
132  * Return:
133  *	0 if ok, -1 otherwise
134  */
135 
136 #if __STDC__
137 int
138 usrtb_start(void)
139 #else
140 int
141 usrtb_start()
142 #endif
143 {
144 	static int fail = 0;
145 
146 	if (usrtb != NULL)
147 		return(0);
148 	if (fail)
149 		return(-1);
150 	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
151 		++fail;
152 		warn(1, "Unable to allocate memory for user name cache table");
153 		return(-1);
154 	}
155 	return(0);
156 }
157 
158 /*
159  * grptb_start
160  *	creates an an empty grptb
161  * Return:
162  *	0 if ok, -1 otherwise
163  */
164 
165 #if __STDC__
166 int
167 grptb_start(void)
168 #else
169 int
170 grptb_start()
171 #endif
172 {
173 	static int fail = 0;
174 
175 	if (grptb != NULL)
176 		return(0);
177 	if (fail)
178 		return(-1);
179 	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
180 		++fail;
181 		warn(1,"Unable to allocate memory for group name cache table");
182 		return(-1);
183 	}
184 	return(0);
185 }
186 
187 /*
188  * name_uid()
189  *	caches the name (if any) for the uid. If frc set, we always return the
190  *	the stored name (if valid or invalid match). We use a simple hash table.
191  * Return
192  *	Pointer to stored name (or a empty string)
193  */
194 
195 #if __STDC__
196 char *
197 name_uid(uid_t uid, int frc)
198 #else
199 char *
200 name_uid(uid, frc)
201 	uid_t uid;
202 	int frc;
203 #endif
204 {
205 	register struct passwd *pw;
206 	register UIDC *ptr;
207 
208 	if ((uidtb == NULL) && (uidtb_start() < 0))
209 		return("");
210 
211 	/*
212 	 * see if we have this uid cached
213 	 */
214 	ptr = uidtb[uid % UID_SZ];
215 	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
216 		/*
217 		 * have an entry for this uid
218 		 */
219 		if (frc || (ptr->valid == VALID))
220 			return(ptr->name);
221 		return("");
222 	}
223 
224 	/*
225 	 * No entry for this uid, we will add it
226 	 */
227 	if (!pwopn) {
228 		setpassent(1);
229 		++pwopn;
230 	}
231 	if (ptr == NULL)
232 		ptr = (UIDC *)malloc(sizeof(UIDC));
233 
234 	if ((pw = getpwuid(uid)) == NULL) {
235 		/*
236 		 * no match for this uid in the local password file
237 		 * a string that is the uid in numberic format
238 		 */
239 		if (ptr == NULL)
240 			return("");
241 		ptr->uid = uid;
242 		ptr->valid = INVALID;
243 #		ifdef NET2_STAT
244 		(void)sprintf(ptr->name, "%u", uid);
245 #		else
246 		(void)sprintf(ptr->name, "%lu", uid);
247 #		endif
248 		if (frc == 0)
249 			return("");
250 	} else {
251 		/*
252 		 * there is an entry for this uid in the password file
253 		 */
254 		if (ptr == NULL)
255 			return(pw->pw_name);
256 		ptr->uid = uid;
257 		(void)strncpy(ptr->name, pw->pw_name, UNMLEN);
258 		ptr->name[UNMLEN-1] = '\0';
259 		ptr->valid = VALID;
260 	}
261 	return(ptr->name);
262 }
263 
264 /*
265  * name_gid()
266  *	caches the name (if any) for the gid. If frc set, we always return the
267  *	the stored name (if valid or invalid match). We use a simple hash table.
268  * Return
269  *	Pointer to stored name (or a empty string)
270  */
271 
272 #if __STDC__
273 char *
274 name_gid(gid_t gid, int frc)
275 #else
276 char *
277 name_gid(gid, frc)
278 	gid_t gid;
279 	int frc;
280 #endif
281 {
282 	register struct group *gr;
283 	register GIDC *ptr;
284 
285 	if ((gidtb == NULL) && (gidtb_start() < 0))
286 		return("");
287 
288 	/*
289 	 * see if we have this gid cached
290 	 */
291 	ptr = gidtb[gid % GID_SZ];
292 	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
293 		/*
294 		 * have an entry for this gid
295 		 */
296 		if (frc || (ptr->valid == VALID))
297 			return(ptr->name);
298 		return("");
299 	}
300 
301 	/*
302 	 * No entry for this gid, we will add it
303 	 */
304 	if (!gropn) {
305 		setgroupent(1);
306 		++gropn;
307 	}
308 	if (ptr == NULL)
309 		ptr = (GIDC *)malloc(sizeof(GIDC));
310 
311 	if ((gr = getgrgid(gid)) == NULL) {
312 		/*
313 		 * no match for this gid in the local group file, put in
314 		 * a string that is the gid in numberic format
315 		 */
316 		if (ptr == NULL)
317 			return("");
318 		ptr->gid = gid;
319 		ptr->valid = INVALID;
320 #		ifdef NET2_STAT
321 		(void)sprintf(ptr->name, "%u", gid);
322 #		else
323 		(void)sprintf(ptr->name, "%lu", gid);
324 #		endif
325 		if (frc == 0)
326 			return("");
327 	} else {
328 		/*
329 		 * there is an entry for this group in the group file
330 		 */
331 		if (ptr == NULL)
332 			return(gr->gr_name);
333 		ptr->gid = gid;
334 		(void)strncpy(ptr->name, gr->gr_name, GNMLEN);
335 		ptr->name[GNMLEN-1] = '\0';
336 		ptr->valid = VALID;
337 	}
338 	return(ptr->name);
339 }
340 
341 /*
342  * uid_name()
343  *	caches the uid for a given user name. We use a simple hash table.
344  * Return
345  *	the uid (if any) for a user name, or a -1 if no match can be found
346  */
347 
348 #if __STDC__
349 int
350 uid_name(char *name, uid_t *uid)
351 #else
352 int
353 uid_name(name, uid)
354 	char *name;
355 	uid_t *uid;
356 #endif
357 {
358 	register struct passwd *pw;
359 	register UIDC *ptr;
360 	register int namelen;
361 
362 	/*
363 	 * return -1 for mangled names
364 	 */
365 	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
366 		return(-1);
367 	if ((usrtb == NULL) && (usrtb_start() < 0))
368 		return(-1);
369 
370 	/*
371 	 * look up in hash table, if found and valid return the uid,
372 	 * if found and invalid, return a -1
373 	 */
374 	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
375 	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
376 		if (ptr->valid == INVALID)
377 			return(-1);
378 		*uid = ptr->uid;
379 		return(0);
380 	}
381 
382 	if (!pwopn) {
383 		setpassent(1);
384 		++pwopn;
385 	}
386 
387 	if (ptr == NULL)
388 		ptr = (UIDC *)malloc(sizeof(UIDC));
389 
390 	/*
391 	 * no match, look it up, if no match store it as an invalid entry,
392 	 * or store the matching uid
393 	 */
394 	if (ptr == NULL) {
395 		if ((pw = getpwnam(name)) == NULL)
396 			return(-1);
397 		*uid = pw->pw_uid;
398 		return(0);
399 	}
400 	(void)strncpy(ptr->name, name, UNMLEN);
401 	ptr->name[UNMLEN-1] = '\0';
402 	if ((pw = getpwnam(name)) == NULL) {
403 		ptr->valid = INVALID;
404 		return(-1);
405 	}
406 	ptr->valid = VALID;
407 	*uid = ptr->uid = pw->pw_uid;
408 	return(0);
409 }
410 
411 /*
412  * gid_name()
413  *	caches the gid for a given group name. We use a simple hash table.
414  * Return
415  *	the gid (if any) for a group name, or a -1 if no match can be found
416  */
417 
418 #if __STDC__
419 int
420 gid_name(char *name, gid_t *gid)
421 #else
422 int
423 gid_name(name, gid)
424 	char *name;
425 	gid_t *gid;
426 #endif
427 {
428 	register struct group *gr;
429 	register GIDC *ptr;
430 	register int namelen;
431 
432 	/*
433 	 * return -1 for mangled names
434 	 */
435 	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
436 		return(-1);
437 	if ((grptb == NULL) && (grptb_start() < 0))
438 		return(-1);
439 
440 	/*
441 	 * look up in hash table, if found and valid return the uid,
442 	 * if found and invalid, return a -1
443 	 */
444 	ptr = grptb[st_hash(name, namelen, GID_SZ)];
445 	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
446 		if (ptr->valid == INVALID)
447 			return(-1);
448 		*gid = ptr->gid;
449 		return(0);
450 	}
451 
452 	if (!gropn) {
453 		setgroupent(1);
454 		++gropn;
455 	}
456 	if (ptr == NULL)
457 		ptr = (GIDC *)malloc(sizeof(GIDC));
458 
459 	/*
460 	 * no match, look it up, if no match store it as an invalid entry,
461 	 * or store the matching gid
462 	 */
463 	if (ptr == NULL) {
464 		if ((gr = getgrnam(name)) == NULL)
465 			return(-1);
466 		*gid = gr->gr_gid;
467 		return(0);
468 	}
469 
470 	(void)strncpy(ptr->name, name, GNMLEN);
471 	ptr->name[GNMLEN-1] = '\0';
472 	if ((gr = getgrnam(name)) == NULL) {
473 		ptr->valid = INVALID;
474 		return(-1);
475 	}
476 	ptr->valid = VALID;
477 	*gid = ptr->gid = gr->gr_gid;
478 	return(0);
479 }
480