prototyping-20040623
[openafs.git] / src / ptserver / utils.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <sys/types.h>
17 #include <lock.h>
18 #include <ubik.h>
19 #include <stdio.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #else
23 #include <netinet/in.h>
24 #include <netdb.h>
25 #endif
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #endif
33 #include "ptserver.h"
34 #include "pterror.h"
35
36 #if defined(SUPERGROUPS)
37 extern afs_int32 depthsg;
38 afs_int32 IsAMemberOfSG(struct ubik_trans *at, afs_int32 aid, afs_int32 gid,
39                         afs_int32 depth);
40 #endif
41
42 afs_int32
43 IDHash(afs_int32 x)
44 {
45     /* returns hash bucket for x */
46     return ((abs(x)) % HASHSIZE);
47 }
48
49 afs_int32
50 NameHash(register unsigned char *aname)
51 {
52     /* returns hash bucket for aname */
53     register unsigned int hash = 0;
54     register int i;
55 /* stolen directly from the HashString function in the vol package */
56     for (i = strlen(aname), aname += i - 1; i--; aname--)
57         hash = (hash * 31) + (*aname - 31);
58     return (hash % HASHSIZE);
59 }
60
61
62 afs_int32
63 pr_Write(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, char *buff, afs_int32 len)
64 {
65     /* package up seek and write into one procedure for ease of use */
66     afs_int32 code;
67     if ((pos < sizeof(cheader)) && (buff != (char *)&cheader + pos)) {
68         fprintf(stderr,
69                 "ptserver: dbwrite: Illegal attempt to write a location 0\n");
70         return PRDBFAIL;
71     }
72     code = ubik_Seek(tt, afd, pos);
73     if (code)
74         return code;
75     code = ubik_Write(tt, buff, len);
76     return code;
77 }
78
79 afs_int32
80 pr_Read(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, char *buff, afs_int32 len)
81 {
82     /* same thing for read */
83     afs_int32 code;
84     code = ubik_Seek(tt, afd, pos);
85     if (code)
86         return code;
87     code = ubik_Read(tt, buff, len);
88     return code;
89 }
90
91 int
92 pr_WriteEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct prentry *tentry)
93 {
94     afs_int32 code;
95     register afs_int32 i;
96     struct prentry nentry;
97
98     if (ntohl(1) != 1) {        /* Need to swap bytes. */
99         memset(&nentry, 0, sizeof(nentry));     /* make sure reseved fields are zero */
100         nentry.flags = htonl(tentry->flags);
101         nentry.id = htonl(tentry->id);
102         nentry.cellid = htonl(tentry->cellid);
103         nentry.next = htonl(tentry->next);
104         nentry.nextID = htonl(tentry->nextID);
105         nentry.nextName = htonl(tentry->nextName);
106         nentry.owner = htonl(tentry->owner);
107         nentry.creator = htonl(tentry->creator);
108         nentry.ngroups = htonl(tentry->ngroups);
109         nentry.nusers = htonl(tentry->nusers);
110         nentry.count = htonl(tentry->count);
111         nentry.instance = htonl(tentry->instance);
112         nentry.owned = htonl(tentry->owned);
113         nentry.nextOwned = htonl(tentry->nextOwned);
114         nentry.parent = htonl(tentry->parent);
115         nentry.sibling = htonl(tentry->sibling);
116         nentry.child = htonl(tentry->child);
117         strncpy(nentry.name, tentry->name, PR_MAXNAMELEN);
118 #ifdef PR_REMEMBER_TIMES
119         nentry.createTime = htonl(tentry->createTime);
120         nentry.addTime = htonl(tentry->addTime);
121         nentry.removeTime = htonl(tentry->removeTime);
122         nentry.changeTime = htonl(tentry->changeTime);
123 #endif
124         for (i = 0; i < PRSIZE; i++)
125             nentry.entries[i] = htonl(tentry->entries[i]);
126         tentry = &nentry;
127     }
128     code = pr_Write(tt, afd, pos, (char *)tentry, sizeof(struct prentry));
129     return (code);
130 }
131
132 int
133 pr_ReadEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct prentry *tentry)
134 {
135     afs_int32 code;
136     register afs_int32 i;
137     struct prentry nentry;
138     code = ubik_Seek(tt, afd, pos);
139     if (code)
140         return (code);
141     if (ntohl(1) == 1) {        /* no swapping needed */
142         code = ubik_Read(tt, (char *)tentry, sizeof(struct prentry));
143         return (code);
144     }
145     code = ubik_Read(tt, (char *)&nentry, sizeof(struct prentry));
146     if (code)
147         return (code);
148     memset(tentry, 0, sizeof(*tentry)); /* make sure reseved fields are zero */
149     tentry->flags = ntohl(nentry.flags);
150     tentry->id = ntohl(nentry.id);
151     tentry->cellid = ntohl(nentry.cellid);
152     tentry->next = ntohl(nentry.next);
153     tentry->nextID = ntohl(nentry.nextID);
154     tentry->nextName = ntohl(nentry.nextName);
155     tentry->owner = ntohl(nentry.owner);
156     tentry->creator = ntohl(nentry.creator);
157     tentry->ngroups = ntohl(nentry.ngroups);
158     tentry->nusers = ntohl(nentry.nusers);
159     tentry->count = ntohl(nentry.count);
160     tentry->instance = ntohl(nentry.instance);
161     tentry->owned = ntohl(nentry.owned);
162     tentry->nextOwned = ntohl(nentry.nextOwned);
163     tentry->parent = ntohl(nentry.parent);
164     tentry->sibling = ntohl(nentry.sibling);
165     tentry->child = ntohl(nentry.child);
166     strncpy(tentry->name, nentry.name, PR_MAXNAMELEN);
167 #ifdef PR_REMEMBER_TIMES
168     tentry->createTime = ntohl(nentry.createTime);
169     tentry->addTime = ntohl(nentry.addTime);
170     tentry->removeTime = ntohl(nentry.removeTime);
171     tentry->changeTime = ntohl(nentry.changeTime);
172 #endif
173     for (i = 0; i < PRSIZE; i++)
174         tentry->entries[i] = ntohl(nentry.entries[i]);
175     return (code);
176 }
177
178 int
179 pr_WriteCoEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct contentry *tentry)
180 {
181     afs_int32 code;
182     register afs_int32 i;
183     struct contentry nentry;
184
185     if (ntohl(1) != 1) {        /* No need to swap */
186         memset(&nentry, 0, sizeof(nentry));     /* make reseved fields zero */
187         nentry.flags = htonl(tentry->flags);
188         nentry.id = htonl(tentry->id);
189         nentry.cellid = htonl(tentry->cellid);
190         nentry.next = htonl(tentry->next);
191         for (i = 0; i < COSIZE; i++)
192             nentry.entries[i] = htonl(tentry->entries[i]);
193         tentry = &nentry;
194     }
195     code = pr_Write(tt, afd, pos, (char *)tentry, sizeof(struct contentry));
196     return (code);
197 }
198
199 int
200 pr_ReadCoEntry(struct ubik_trans *tt, afs_int32 afd, afs_int32 pos, struct contentry *tentry)
201 {
202     afs_int32 code;
203     register afs_int32 i;
204     struct contentry nentry;
205     code = ubik_Seek(tt, afd, pos);
206     if (code)
207         return (code);
208     if (ntohl(1) == 1) {        /* No swapping needed. */
209         code = ubik_Read(tt, (char *)tentry, sizeof(struct contentry));
210         return (code);
211     }
212     code = ubik_Read(tt, (char *)&nentry, sizeof(struct contentry));
213     if (code)
214         return (code);
215     memset(tentry, 0, sizeof(*tentry)); /* make reseved fields zero */
216     tentry->flags = ntohl(nentry.flags);
217     tentry->id = ntohl(nentry.id);
218     tentry->cellid = ntohl(nentry.cellid);
219     tentry->next = ntohl(nentry.next);
220     for (i = 0; i < COSIZE; i++)
221         tentry->entries[i] = ntohl(nentry.entries[i]);
222     return (code);
223 }
224
225 /* AllocBloc - allocate a free block of storage for entry, returning address of
226  * new entry */
227
228 afs_int32
229 AllocBlock(register struct ubik_trans *at)
230 {
231     register afs_int32 code;
232     afs_int32 temp;
233     struct prentry tentry;
234
235     if (cheader.freePtr) {
236         /* allocate this dude */
237         temp = ntohl(cheader.freePtr);
238         code = pr_ReadEntry(at, 0, temp, &tentry);
239         if (code)
240             return 0;
241         cheader.freePtr = htonl(tentry.next);
242         code =
243             pr_Write(at, 0, 8, (char *)&cheader.freePtr,
244                      sizeof(cheader.freePtr));
245         if (code != 0)
246             return 0;
247         return temp;
248     } else {
249         /* hosed, nothing on free list, grow file */
250         temp = ntohl(cheader.eofPtr);   /* remember this guy */
251         cheader.eofPtr = htonl(temp + ENTRYSIZE);
252         code =
253             pr_Write(at, 0, 12, (char *)&cheader.eofPtr,
254                      sizeof(cheader.eofPtr));
255         if (code != 0)
256             return 0;
257         return temp;
258     }
259 }
260
261 afs_int32
262 FreeBlock(register struct ubik_trans *at, afs_int32 pos)
263 {
264     /* add a block of storage to the free list */
265     register afs_int32 code;
266     struct prentry tentry;
267
268     memset(&tentry, 0, sizeof(tentry));
269     tentry.next = ntohl(cheader.freePtr);
270     tentry.flags |= PRFREE;
271     cheader.freePtr = htonl(pos);
272     code =
273         pr_Write(at, 0, 8, (char *)&cheader.freePtr, sizeof(cheader.freePtr));
274     if (code != 0)
275         return code;
276     code = pr_WriteEntry(at, 0, pos, &tentry);
277     if (code != 0)
278         return code;
279     return PRSUCCESS;
280 }
281
282 afs_int32
283 FindByID(register struct ubik_trans *at, afs_int32 aid)
284 {
285     /* returns address of entry if found, 0 otherwise */
286     register afs_int32 code;
287     afs_int32 i;
288     struct prentry tentry;
289     afs_int32 entry;
290
291     if ((aid == PRBADID) || (aid == 0))
292         return 0;
293     i = IDHash(aid);
294     entry = ntohl(cheader.idHash[i]);
295     if (entry == 0)
296         return entry;
297     memset(&tentry, 0, sizeof(tentry));
298     code = pr_ReadEntry(at, 0, entry, &tentry);
299     if (code != 0)
300         return 0;
301     if (aid == tentry.id)
302         return entry;
303     entry = tentry.nextID;
304     while (entry != 0) {
305         memset(&tentry, 0, sizeof(tentry));
306         code = pr_ReadEntry(at, 0, entry, &tentry);
307         if (code != 0)
308             return 0;
309         if (aid == tentry.id)
310             return entry;
311         entry = tentry.nextID;
312     }
313     return 0;
314 }
315
316 afs_int32
317 FindByName(register struct ubik_trans *at, char aname[PR_MAXNAMELEN], struct prentry *tentryp)
318 {
319     /* ditto */
320     register afs_int32 code;
321     afs_int32 i;
322     afs_int32 entry;
323
324     i = NameHash(aname);
325     entry = ntohl(cheader.nameHash[i]);
326     if (entry == 0)
327         return entry;
328     memset(tentryp, 0, sizeof(struct prentry));
329     code = pr_ReadEntry(at, 0, entry, tentryp);
330     if (code != 0)
331         return 0;
332     if ((strncmp(aname, tentryp->name, PR_MAXNAMELEN)) == 0)
333         return entry;
334     entry = tentryp->nextName;
335     while (entry != 0) {
336         memset(tentryp, 0, sizeof(struct prentry));
337         code = pr_ReadEntry(at, 0, entry, tentryp);
338         if (code != 0)
339             return 0;
340         if ((strncmp(aname, tentryp->name, PR_MAXNAMELEN)) == 0)
341             return entry;
342         entry = tentryp->nextName;
343     }
344     return 0;
345 }
346
347 afs_int32
348 AllocID(register struct ubik_trans *at, afs_int32 flag, afs_int32 *aid)
349 {
350     /* allocs an id from the proper area of address space, based on flag */
351     register afs_int32 code = 1;
352     register afs_int32 i = 0;
353     register maxcount = 50;     /* to prevent infinite loops */
354
355     if (flag & PRGRP) {
356         *aid = ntohl(cheader.maxGroup);
357         while (code && i < maxcount) {
358             --(*aid);
359             code = FindByID(at, *aid);
360             i++;
361         }
362         if (code)
363             return PRNOIDS;
364         cheader.maxGroup = htonl(*aid);
365         code =
366             pr_Write(at, 0, 16, (char *)&cheader.maxGroup,
367                      sizeof(cheader.maxGroup));
368         if (code)
369             return PRDBFAIL;
370         return PRSUCCESS;
371     } else if (flag & PRFOREIGN) {
372         *aid = ntohl(cheader.maxForeign);
373         while (code && i < maxcount) {
374             ++(*aid);
375             code = FindByID(at, *aid);
376             i++;
377         }
378         if (code)
379             return PRNOIDS;
380         cheader.maxForeign = htonl(*aid);
381         code =
382             pr_Write(at, 0, 24, (char *)&cheader.maxForeign,
383                      sizeof(cheader.maxForeign));
384         if (code)
385             return PRDBFAIL;
386         return PRSUCCESS;
387     } else {
388         *aid = ntohl(cheader.maxID);
389         while (code && i < maxcount) {
390             ++(*aid);
391             code = FindByID(at, *aid);
392             i++;
393         }
394         if (code)
395             return PRNOIDS;
396         cheader.maxID = htonl(*aid);
397         code =
398             pr_Write(at, 0, 20, (char *)&cheader.maxID,
399                      sizeof(cheader.maxID));
400         if (code)
401             return PRDBFAIL;
402         return PRSUCCESS;
403     }
404 }
405
406 afs_int32
407 IDToName(register struct ubik_trans *at, afs_int32 aid, char aname[PR_MAXNAMELEN])
408 {
409     afs_int32 temp;
410     struct prentry tentry;
411     register afs_int32 code;
412
413     temp = FindByID(at, aid);
414     if (temp == 0)
415         return PRNOENT;
416     code = pr_Read(at, 0, temp, (char *)&tentry, sizeof(tentry));
417     if (code)
418         return code;
419     strncpy(aname, tentry.name, PR_MAXNAMELEN);
420     return PRSUCCESS;
421 }
422
423 afs_int32
424 NameToID(register struct ubik_trans *at, char aname[PR_MAXNAMELEN], afs_int32 *aid)
425 {
426     afs_int32 temp;
427     struct prentry tentry;
428
429     temp = FindByName(at, aname, &tentry);
430     if (!temp)
431         return PRNOENT;
432     *aid = tentry.id;
433     return PRSUCCESS;
434 }
435
436 int
437 IDCmp(afs_int32 *a, afs_int32 *b)
438 {
439     /* used to sort CPS's so that comparison with acl's is easier */
440     if (*a > *b) {
441         return 1;
442     } else if (*a == *b) {
443         return 0;
444     } else /* (*a < *b) */ {
445         return -1;
446     }
447 }
448
449 afs_int32
450 RemoveFromIDHash(struct ubik_trans *tt, afs_int32 aid, afs_int32 *loc)          /* ??? in case ID hashed twice ??? */
451 {
452     /* remove entry designated by aid from id hash table */
453     register afs_int32 code;
454     afs_int32 current, trail, i;
455     struct prentry tentry;
456     struct prentry bentry;
457
458     if ((aid == PRBADID) || (aid == 0))
459         return PRINCONSISTENT;
460     i = IDHash(aid);
461     current = ntohl(cheader.idHash[i]);
462     memset(&tentry, 0, sizeof(tentry));
463     memset(&bentry, 0, sizeof(bentry));
464     trail = 0;
465     if (current == 0)
466         return PRSUCCESS;       /* already gone */
467     code = pr_ReadEntry(tt, 0, current, &tentry);
468     if (code)
469         return PRDBFAIL;
470     while (aid != tentry.id) {
471         trail = current;
472         current = tentry.nextID;
473         if (current == 0)
474             break;
475         code = pr_ReadEntry(tt, 0, current, &tentry);
476         if (code)
477             return PRDBFAIL;
478     }
479     if (current == 0)
480         return PRSUCCESS;       /* we didn't find him, so he's already gone */
481     if (trail == 0) {
482         /* it's the first entry! */
483         cheader.idHash[i] = htonl(tentry.nextID);
484         code =
485             pr_Write(tt, 0, 72 + HASHSIZE * 4 + i * 4,
486                      (char *)&cheader.idHash[i], sizeof(cheader.idHash[i]));
487         if (code)
488             return PRDBFAIL;
489     } else {
490         code = pr_ReadEntry(tt, 0, trail, &bentry);
491         if (code)
492             return PRDBFAIL;
493         bentry.nextID = tentry.nextID;
494         code = pr_WriteEntry(tt, 0, trail, &bentry);
495     }
496     *loc = current;
497     return PRSUCCESS;
498 }
499
500 afs_int32
501 AddToIDHash(struct ubik_trans *tt, afs_int32 aid, afs_int32 loc)
502 {
503     /* add entry at loc designated by aid to id hash table */
504     register afs_int32 code;
505     afs_int32 i;
506     struct prentry tentry;
507
508     if ((aid == PRBADID) || (aid == 0))
509         return PRINCONSISTENT;
510     i = IDHash(aid);
511     memset(&tentry, 0, sizeof(tentry));
512     code = pr_ReadEntry(tt, 0, loc, &tentry);
513     if (code)
514         return PRDBFAIL;
515     tentry.nextID = ntohl(cheader.idHash[i]);
516     cheader.idHash[i] = htonl(loc);
517     code = pr_WriteEntry(tt, 0, loc, &tentry);
518     if (code)
519         return PRDBFAIL;
520     code =
521         pr_Write(tt, 0, 72 + HASHSIZE * 4 + i * 4, (char *)&cheader.idHash[i],
522                  sizeof(cheader.idHash[i]));
523     if (code)
524         return PRDBFAIL;
525     return PRSUCCESS;
526 }
527
528 afs_int32
529 RemoveFromNameHash(struct ubik_trans *tt, char *aname, afs_int32 *loc)
530 {
531     /* remove from name hash */
532     register afs_int32 code;
533     afs_int32 current, trail, i;
534     struct prentry tentry;
535     struct prentry bentry;
536
537     i = NameHash(aname);
538     current = ntohl(cheader.nameHash[i]);
539     memset(&tentry, 0, sizeof(tentry));
540     memset(&bentry, 0, sizeof(bentry));
541     trail = 0;
542     if (current == 0)
543         return PRSUCCESS;       /* already gone */
544     code = pr_ReadEntry(tt, 0, current, &tentry);
545     if (code)
546         return PRDBFAIL;
547     while (strcmp(aname, tentry.name)) {
548         trail = current;
549         current = tentry.nextName;
550         if (current == 0)
551             break;
552         code = pr_ReadEntry(tt, 0, current, &tentry);
553         if (code)
554             return PRDBFAIL;
555     }
556     if (current == 0)
557         return PRSUCCESS;       /* we didn't find him, already gone */
558     if (trail == 0) {
559         /* it's the first entry! */
560         cheader.nameHash[i] = htonl(tentry.nextName);
561         code =
562             pr_Write(tt, 0, 72 + i * 4, (char *)&cheader.nameHash[i],
563                      sizeof(cheader.nameHash[i]));
564         if (code)
565             return PRDBFAIL;
566     } else {
567         code = pr_ReadEntry(tt, 0, trail, &bentry);
568         if (code)
569             return PRDBFAIL;
570         bentry.nextName = tentry.nextName;
571         code = pr_WriteEntry(tt, 0, trail, &bentry);
572     }
573     *loc = current;
574     return PRSUCCESS;
575 }
576
577 afs_int32
578 AddToNameHash(struct ubik_trans *tt, char *aname, afs_int32 loc)
579 {
580     /* add to name hash */
581     register afs_int32 code;
582     afs_int32 i;
583     struct prentry tentry;
584
585     i = NameHash(aname);
586     memset(&tentry, 0, sizeof(tentry));
587     code = pr_ReadEntry(tt, 0, loc, &tentry);
588     if (code)
589         return PRDBFAIL;
590     tentry.nextName = ntohl(cheader.nameHash[i]);
591     cheader.nameHash[i] = htonl(loc);
592     code = pr_WriteEntry(tt, 0, loc, &tentry);
593     if (code)
594         return PRDBFAIL;
595     code =
596         pr_Write(tt, 0, 72 + i * 4, (char *)&cheader.nameHash[i],
597                  sizeof(cheader.nameHash[i]));
598     if (code)
599         return PRDBFAIL;
600     return PRSUCCESS;
601 }
602
603 afs_int32
604 AddToOwnerChain(struct ubik_trans *at, afs_int32 gid, afs_int32 oid)
605 {
606     /* add entry designated by gid to owner chain of entry designated by oid */
607     register afs_int32 code;
608     afs_int32 loc;
609     struct prentry tentry;
610     struct prentry gentry;
611     afs_int32 gloc;
612
613     loc = FindByID(at, oid);
614     if (!loc)
615         return PRNOENT;
616     code = pr_ReadEntry(at, 0, loc, &tentry);
617     if (code != 0)
618         return PRDBFAIL;
619     if (oid == gid) {           /* added it to its own chain */
620         tentry.nextOwned = tentry.owned;
621         tentry.owned = loc;
622     } else {
623         gloc = FindByID(at, gid);
624         code = pr_ReadEntry(at, 0, gloc, &gentry);
625         if (code != 0)
626             return PRDBFAIL;
627         gentry.nextOwned = tentry.owned;
628         tentry.owned = gloc;
629         code = pr_WriteEntry(at, 0, gloc, &gentry);
630         if (code != 0)
631             return PRDBFAIL;
632     }
633     code = pr_WriteEntry(at, 0, loc, &tentry);
634     if (code != 0)
635         return PRDBFAIL;
636     return PRSUCCESS;
637 }
638
639 /* RemoveFromOwnerChain - remove gid from owner chain for oid */
640
641 afs_int32
642 RemoveFromOwnerChain(struct ubik_trans *at, afs_int32 gid, afs_int32 oid)
643 {
644     register afs_int32 code;
645     afs_int32 nptr;
646     struct prentry thisEntry;
647     struct prentry thatEntry;
648     struct prentry *te;         /* pointer to current (this) entry */
649     struct prentry *le;         /* pointer to previous (last) entry */
650     afs_int32 loc, lastLoc;
651
652     loc = FindByID(at, oid);
653     if (!loc)
654         return PRNOENT;
655     code = pr_ReadEntry(at, 0, loc, &thisEntry);
656     if (code != 0)
657         return PRDBFAIL;
658     le = &thisEntry;
659     lastLoc = 0;
660     nptr = thisEntry.owned;
661     while (nptr != 0) {
662         if (nptr == lastLoc)
663             te = le;
664         else {
665             if (&thisEntry == le)
666                 te = &thatEntry;
667             else
668                 te = &thisEntry;
669             code = pr_ReadEntry(at, 0, nptr, te);
670             if (code != 0)
671                 return PRDBFAIL;
672         }
673         if (te->id == gid) {
674             /* found it */
675             if (lastLoc == 0) { /* modifying first of chain */
676                 le->owned = te->nextOwned;
677                 lastLoc = loc;  /* so we write to correct location */
678             } else
679                 le->nextOwned = te->nextOwned;
680             te->nextOwned = 0;
681             if (te != le) {
682                 code = pr_WriteEntry(at, 0, nptr, te);
683                 if (code != 0)
684                     return PRDBFAIL;
685             }
686             code = pr_WriteEntry(at, 0, lastLoc, le);
687             if (code != 0)
688                 return PRDBFAIL;
689             return PRSUCCESS;
690         }
691         lastLoc = nptr;
692         le = te;
693         nptr = te->nextOwned;
694     }
695     return PRSUCCESS;           /* already removed? */
696 }
697
698 /* AddToOrphan - add gid to orphan list, as it's owner has died */
699
700 afs_int32
701 AddToOrphan(struct ubik_trans *at, afs_int32 gid)
702 {
703     register afs_int32 code;
704     afs_int32 loc;
705     struct prentry tentry;
706
707     loc = FindByID(at, gid);
708     if (!loc)
709         return PRNOENT;
710     code = pr_ReadEntry(at, 0, loc, &tentry);
711     if (code != 0)
712         return PRDBFAIL;
713     tentry.nextOwned = ntohl(cheader.orphan);
714     code = set_header_word(at, orphan, htonl(loc));
715     if (code != 0)
716         return PRDBFAIL;
717     tentry.owner = 0;           /* so there's no confusion later */
718     code = pr_WriteEntry(at, 0, loc, &tentry);
719     if (code != 0)
720         return PRDBFAIL;
721     return PRSUCCESS;
722 }
723
724 afs_int32
725 RemoveFromOrphan(struct ubik_trans *at, afs_int32 gid)
726 {
727     /* remove gid from the orphan list */
728     register afs_int32 code;
729     afs_int32 loc;
730     afs_int32 nptr;
731     struct prentry tentry;
732     struct prentry bentry;
733
734     loc = FindByID(at, gid);
735     if (!loc)
736         return PRNOENT;
737     code = pr_ReadEntry(at, 0, loc, &tentry);
738     if (code != 0)
739         return PRDBFAIL;
740     if (cheader.orphan == htonl(loc)) {
741         cheader.orphan = htonl(tentry.nextOwned);
742         tentry.nextOwned = 0;
743         code =
744             pr_Write(at, 0, 32, (char *)&cheader.orphan,
745                      sizeof(cheader.orphan));
746         if (code != 0)
747             return PRDBFAIL;
748         code = pr_WriteEntry(at, 0, loc, &tentry);
749         if (code != 0)
750             return PRDBFAIL;
751         return PRSUCCESS;
752     }
753     nptr = ntohl(cheader.orphan);
754     memset(&bentry, 0, sizeof(bentry));
755     loc = 0;
756     while (nptr != 0) {
757         code = pr_ReadEntry(at, 0, nptr, &tentry);
758         if (code != 0)
759             return PRDBFAIL;
760         if (gid == tentry.id) {
761             /* found it */
762             bentry.nextOwned = tentry.nextOwned;
763             tentry.nextOwned = 0;
764             code = pr_WriteEntry(at, 0, loc, &bentry);
765             if (code != 0)
766                 return PRDBFAIL;
767             code = pr_WriteEntry(at, 0, nptr, &tentry);
768             if (code != 0)
769                 return PRDBFAIL;
770             return PRSUCCESS;
771         }
772         loc = nptr;
773         nptr = tentry.nextOwned;
774         memcpy(&bentry, &tentry, sizeof(tentry));
775     }
776     return PRSUCCESS;
777 }
778
779 afs_int32
780 IsOwnerOf(struct ubik_trans *at, afs_int32 aid, afs_int32 gid)
781 {
782     /* returns 1 if aid is the owner of gid, 0 otherwise */
783     register afs_int32 code;
784     struct prentry tentry;
785     afs_int32 loc;
786
787     loc = FindByID(at, gid);
788     if (!loc)
789         return 0;
790     code = pr_ReadEntry(at, 0, loc, &tentry);
791     if (code != 0)
792         return 0;
793     if (tentry.owner == aid)
794         return 1;
795     return 0;
796 }
797
798 afs_int32
799 OwnerOf(struct ubik_trans *at, afs_int32 gid)
800 {
801     /* returns the owner of gid */
802     register afs_int32 code;
803     afs_int32 loc;
804     struct prentry tentry;
805
806     loc = FindByID(at, gid);
807     if (!loc)
808         return 0;
809     code = pr_ReadEntry(at, 0, loc, &tentry);
810     if (code != 0)
811         return 0;
812     return tentry.owner;
813 }
814
815
816 afs_int32
817 IsAMemberOf(struct ubik_trans *at, afs_int32 aid, afs_int32 gid)
818 {
819     /* returns true if aid is a member of gid */
820 #if !defined(SUPERGROUPS)
821     struct prentry tentry;
822     struct contentry centry;
823     register afs_int32 code;
824     afs_int32 i;
825     afs_int32 loc;
826 #endif
827
828     /* special case anyuser and authuser */
829     if (gid == ANYUSERID)
830         return 1;
831     if (gid == AUTHUSERID && aid != ANONYMOUSID)
832         return 1;
833     if ((gid == 0) || (aid == 0))
834         return 0;
835 #if defined(SUPERGROUPS)
836     return IsAMemberOfSG(at, aid, gid, depthsg);
837 #else
838     loc = FindByID(at, gid);
839     if (!loc)
840         return 0;
841     memset(&tentry, 0, sizeof(tentry));
842     code = pr_ReadEntry(at, 0, loc, &tentry);
843     if (code)
844         return 0;
845     if (!(tentry.flags & PRGRP))
846         return 0;
847     for (i = 0; i < PRSIZE; i++) {
848         if (tentry.entries[i] == 0)
849             return 0;
850         if (tentry.entries[i] == aid)
851             return 1;
852     }
853     if (tentry.next) {
854         loc = tentry.next;
855         while (loc) {
856             memset(&centry, 0, sizeof(centry));
857             code = pr_ReadCoEntry(at, 0, loc, &centry);
858             if (code)
859                 return 0;
860             for (i = 0; i < COSIZE; i++) {
861                 if (centry.entries[i] == aid)
862                     return 1;
863                 if (centry.entries[i] == 0)
864                     return 0;
865             }
866             loc = centry.next;
867         }
868     }
869     return 0;                   /* actually, should never get here */
870 #endif
871 }
872
873
874 #if defined(SUPERGROUPS)
875 afs_int32
876 IsAMemberOfSG(struct ubik_trans *at, afs_int32 aid, afs_int32 gid, afs_int32 depth) 
877 {
878     /* returns true if aid is a member of gid */
879     struct prentry tentry;
880     struct contentry centry;
881     register afs_int32 code;
882     afs_int32 i;
883     afs_int32 loc;
884
885     if (depth < 1)
886         return 0;
887     loc = FindByID(at, gid);
888     if (!loc)
889         return 0;
890     memset(&tentry, 0, sizeof(tentry));
891     code = pr_ReadEntry(at, 0, loc, &tentry);
892     if (code)
893         return 0;
894     if (!(tentry.flags & PRGRP))
895         return 0;
896     for (i = 0; i < PRSIZE; i++) {
897         gid = tentry.entries[i];
898         if (gid == 0)
899             return 0;
900         if (gid == aid)
901             return 1;
902         if (gid == ANYUSERID)
903             return 1;
904         if (gid == AUTHUSERID && aid != ANONYMOUSID)
905             return 1;
906         if (gid < 0) {
907             IOMGR_Poll();
908             if (IsAMemberOfSG(at, aid, gid, depth - 1))
909                 return 1;
910         }
911     }
912     if (tentry.next) {
913         loc = tentry.next;
914         while (loc) {
915             memset(&centry, 0, sizeof(centry));
916             code = pr_ReadCoEntry(at, 0, loc, &centry);
917             if (code)
918                 return 0;
919             for (i = 0; i < COSIZE; i++) {
920                 gid = centry.entries[i];
921                 if (gid == 0)
922                     return 0;
923                 if (gid == aid)
924                     return 1;
925                 if (gid == ANYUSERID)
926                     return 1;
927                 if (gid == AUTHUSERID && aid != ANONYMOUSID)
928                     return 1;
929                 if (gid < 0) {
930                     IOMGR_Poll();
931                     if (IsAMemberOfSG(at, aid, gid, depth - 1))
932                         return 1;
933                 }
934             }
935             loc = centry.next;
936         }
937     }
938     return 0;                   /* actually, should never get here */
939 }
940 #endif /* SUPERGROUPS */