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