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