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