add a config file for git-buildpackage
[debian/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[] = "$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
214         if ((uidtb == NULL) && (uidtb_start() < 0))
215                 return("");
216
217         /*
218          * see if we have this uid cached
219          */
220         ptr = uidtb[uid % UID_SZ];
221         if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
222                 /*
223                  * have an entry for this uid
224                  */
225                 if (frc || (ptr->valid == VALID))
226                         return(ptr->name);
227                 return("");
228         }
229
230         /*
231          * No entry for this uid, we will add it
232          */
233         if (!pwopn) {
234 #ifdef DEBIAN
235                 setpwent();
236 #else
237                 setpassent(1);
238 #endif
239                 ++pwopn;
240         }
241         if (ptr == NULL)
242                 ptr = (UIDC *)malloc(sizeof(UIDC));
243
244         if ((pw = getpwuid(uid)) == NULL) {
245                 /*
246                  * no match for this uid in the local password file
247                  * a string that is the uid in numberic format
248                  */
249                 if (ptr == NULL)
250                         return("");
251                 ptr->uid = uid;
252                 ptr->valid = INVALID;
253 #               ifdef NET2_STAT
254                 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
255 #               else
256                 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
257                                (unsigned long)uid);
258 #               endif
259                 if (frc == 0)
260                         return("");
261         } else {
262                 /*
263                  * there is an entry for this uid in the password file
264                  */
265                 if (ptr == NULL)
266                         return(pw->pw_name);
267                 ptr->uid = uid;
268                 (void)strncpy(ptr->name, pw->pw_name, UNMLEN-1);
269                 ptr->name[UNMLEN-1] = '\0';
270                 ptr->valid = VALID;
271         }
272         return(ptr->name);
273 }
274
275 /*
276  * name_gid()
277  *      caches the name (if any) for the gid. If frc set, we always return the
278  *      the stored name (if valid or invalid match). We use a simple hash table.
279  * Return
280  *      Pointer to stored name (or a empty string)
281  */
282
283 #ifdef __STDC__
284 char *
285 name_gid(gid_t gid, int frc)
286 #else
287 char *
288 name_gid(gid, frc)
289         gid_t gid;
290         int frc;
291 #endif
292 {
293         register struct group *gr;
294         register GIDC *ptr;
295
296         if ((gidtb == NULL) && (gidtb_start() < 0))
297                 return("");
298
299         /*
300          * see if we have this gid cached
301          */
302         ptr = gidtb[gid % GID_SZ];
303         if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
304                 /*
305                  * have an entry for this gid
306                  */
307                 if (frc || (ptr->valid == VALID))
308                         return(ptr->name);
309                 return("");
310         }
311
312         /*
313          * No entry for this gid, we will add it
314          */
315         if (!gropn) {
316 #ifdef DEBIAN
317                 setgrent();
318 #else
319                 setgroupent(1);
320 #endif
321                 ++gropn;
322         }
323         if (ptr == NULL)
324                 ptr = (GIDC *)malloc(sizeof(GIDC));
325
326         if ((gr = getgrgid(gid)) == NULL) {
327                 /*
328                  * no match for this gid in the local group file, put in
329                  * a string that is the gid in numberic format
330                  */
331                 if (ptr == NULL)
332                         return("");
333                 ptr->gid = gid;
334                 ptr->valid = INVALID;
335 #               ifdef NET2_STAT
336                 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
337 #               else
338                 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
339                                (unsigned long)gid);
340 #               endif
341                 if (frc == 0)
342                         return("");
343         } else {
344                 /*
345                  * there is an entry for this group in the group file
346                  */
347                 if (ptr == NULL)
348                         return(gr->gr_name);
349                 ptr->gid = gid;
350                 (void)strncpy(ptr->name, gr->gr_name, GNMLEN-1);
351                 ptr->name[GNMLEN-1] = '\0';
352                 ptr->valid = VALID;
353         }
354         return(ptr->name);
355 }
356
357 /*
358  * uid_name()
359  *      caches the uid for a given user name. We use a simple hash table.
360  * Return
361  *      the uid (if any) for a user name, or a -1 if no match can be found
362  */
363
364 #ifdef __STDC__
365 int
366 uid_name(char *name, uid_t *uid)
367 #else
368 int
369 uid_name(name, uid)
370         char *name;
371         uid_t *uid;
372 #endif
373 {
374         register struct passwd *pw;
375         register UIDC *ptr;
376         register int namelen;
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         ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
391         if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
392                 if (ptr->valid == INVALID)
393                         return(-1);
394                 *uid = ptr->uid;
395                 return(0);
396         }
397
398         if (!pwopn) {
399 #ifdef DEBIAN
400                 setpwent();
401 #else
402                 setpassent(1);
403 #endif
404                 ++pwopn;
405         }
406
407         if (ptr == NULL)
408                 ptr = (UIDC *)malloc(sizeof(UIDC));
409
410         /*
411          * no match, look it up, if no match store it as an invalid entry,
412          * or store the matching uid
413          */
414         if (ptr == NULL) {
415                 if ((pw = getpwnam(name)) == NULL)
416                         return(-1);
417                 *uid = pw->pw_uid;
418                 return(0);
419         }
420         (void)strncpy(ptr->name, name, UNMLEN-1);
421         ptr->name[UNMLEN-1] = '\0';
422         if ((pw = getpwnam(name)) == NULL) {
423                 ptr->valid = INVALID;
424                 return(-1);
425         }
426         ptr->valid = VALID;
427         *uid = ptr->uid = pw->pw_uid;
428         return(0);
429 }
430
431 /*
432  * gid_name()
433  *      caches the gid for a given group name. We use a simple hash table.
434  * Return
435  *      the gid (if any) for a group name, or a -1 if no match can be found
436  */
437
438 #ifdef __STDC__
439 int
440 gid_name(char *name, gid_t *gid)
441 #else
442 int
443 gid_name(name, gid)
444         char *name;
445         gid_t *gid;
446 #endif
447 {
448         register struct group *gr;
449         register GIDC *ptr;
450         register int namelen;
451
452         /*
453          * return -1 for mangled names
454          */
455         if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
456                 return(-1);
457         if ((grptb == NULL) && (grptb_start() < 0))
458                 return(-1);
459
460         /*
461          * look up in hash table, if found and valid return the uid,
462          * if found and invalid, return a -1
463          */
464         ptr = grptb[st_hash(name, namelen, GID_SZ)];
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 #ifdef DEBIAN
474                 setgrent();
475 #else
476                 setgroupent(1);
477 #endif
478                 ++gropn;
479         }
480         if (ptr == NULL)
481                 ptr = (GIDC *)malloc(sizeof(GIDC));
482
483         /*
484          * no match, look it up, if no match store it as an invalid entry,
485          * or store the matching gid
486          */
487         if (ptr == NULL) {
488                 if ((gr = getgrnam(name)) == NULL)
489                         return(-1);
490                 *gid = gr->gr_gid;
491                 return(0);
492         }
493
494         (void)strncpy(ptr->name, name, GNMLEN-1);
495         ptr->name[GNMLEN-1] = '\0';
496         if ((gr = getgrnam(name)) == NULL) {
497                 ptr->valid = INVALID;
498                 return(-1);
499         }
500         ptr->valid = VALID;
501         *gid = ptr->gid = gr->gr_gid;
502         return(0);
503 }