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