ptserver: Don't ignore ubik_Write failures
[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         if (code)
483             return PRDBFAIL;
484     }
485     *loc = current;
486     return PRSUCCESS;
487 }
488
489 afs_int32
490 AddToIDHash(struct ubik_trans *tt, afs_int32 aid, afs_int32 loc)
491 {
492     /* add entry at loc designated by aid to id hash table */
493     afs_int32 code;
494     afs_int32 i;
495     struct prentry tentry;
496
497     if ((aid == PRBADID) || (aid == 0))
498         return PRINCONSISTENT;
499     i = IDHash(aid);
500     memset(&tentry, 0, sizeof(tentry));
501     code = pr_ReadEntry(tt, 0, loc, &tentry);
502     if (code)
503         return PRDBFAIL;
504     tentry.nextID = ntohl(cheader.idHash[i]);
505     cheader.idHash[i] = htonl(loc);
506     code = pr_WriteEntry(tt, 0, loc, &tentry);
507     if (code)
508         return PRDBFAIL;
509     code =
510         pr_Write(tt, 0, 72 + HASHSIZE * 4 + i * 4, (char *)&cheader.idHash[i],
511                  sizeof(cheader.idHash[i]));
512     if (code)
513         return PRDBFAIL;
514     return PRSUCCESS;
515 }
516
517 afs_int32
518 RemoveFromNameHash(struct ubik_trans *tt, char *aname, afs_int32 *loc)
519 {
520     /* remove from name hash */
521     afs_int32 code;
522     afs_int32 current, trail, i;
523     struct prentry tentry;
524     struct prentry bentry;
525
526     i = NameHash(aname);
527     current = ntohl(cheader.nameHash[i]);
528     memset(&tentry, 0, sizeof(tentry));
529     memset(&bentry, 0, sizeof(bentry));
530     trail = 0;
531     if (current == 0)
532         return PRSUCCESS;       /* already gone */
533     code = pr_ReadEntry(tt, 0, current, &tentry);
534     if (code)
535         return PRDBFAIL;
536     while (strcmp(aname, tentry.name)) {
537         opr_Assert(trail != current);
538         trail = current;
539         current = tentry.nextName;
540         if (current == 0)
541             break;
542         code = pr_ReadEntry(tt, 0, current, &tentry);
543         if (code)
544             return PRDBFAIL;
545     }
546     if (current == 0)
547         return PRSUCCESS;       /* we didn't find him, already gone */
548     if (trail == 0) {
549         /* it's the first entry! */
550         cheader.nameHash[i] = htonl(tentry.nextName);
551         code =
552             pr_Write(tt, 0, 72 + i * 4, (char *)&cheader.nameHash[i],
553                      sizeof(cheader.nameHash[i]));
554         if (code)
555             return PRDBFAIL;
556     } else {
557         code = pr_ReadEntry(tt, 0, trail, &bentry);
558         if (code)
559             return PRDBFAIL;
560         bentry.nextName = tentry.nextName;
561         code = pr_WriteEntry(tt, 0, trail, &bentry);
562         if (code)
563             return PRDBFAIL;
564     }
565     *loc = current;
566     return PRSUCCESS;
567 }
568
569 afs_int32
570 AddToNameHash(struct ubik_trans *tt, char *aname, afs_int32 loc)
571 {
572     /* add to name hash */
573     afs_int32 code;
574     afs_int32 i;
575     struct prentry tentry;
576
577     i = NameHash(aname);
578     memset(&tentry, 0, sizeof(tentry));
579     code = pr_ReadEntry(tt, 0, loc, &tentry);
580     if (code)
581         return PRDBFAIL;
582     tentry.nextName = ntohl(cheader.nameHash[i]);
583     cheader.nameHash[i] = htonl(loc);
584     code = pr_WriteEntry(tt, 0, loc, &tentry);
585     if (code)
586         return PRDBFAIL;
587     code =
588         pr_Write(tt, 0, 72 + i * 4, (char *)&cheader.nameHash[i],
589                  sizeof(cheader.nameHash[i]));
590     if (code)
591         return PRDBFAIL;
592     return PRSUCCESS;
593 }
594
595 afs_int32
596 AddToOwnerChain(struct ubik_trans *at, afs_int32 gid, afs_int32 oid)
597 {
598     /* add entry designated by gid to owner chain of entry designated by oid */
599     afs_int32 code;
600     afs_int32 loc;
601     struct prentry tentry;
602     struct prentry gentry;
603     afs_int32 gloc;
604
605     loc = FindByID(at, oid);
606     if (!loc)
607         return PRNOENT;
608     code = pr_ReadEntry(at, 0, loc, &tentry);
609     if (code != 0)
610         return PRDBFAIL;
611     if (oid == gid) {           /* added it to its own chain */
612         tentry.nextOwned = tentry.owned;
613         tentry.owned = loc;
614     } else {
615         gloc = FindByID(at, gid);
616         code = pr_ReadEntry(at, 0, gloc, &gentry);
617         if (code != 0)
618             return PRDBFAIL;
619         gentry.nextOwned = tentry.owned;
620         tentry.owned = gloc;
621         code = pr_WriteEntry(at, 0, gloc, &gentry);
622         if (code != 0)
623             return PRDBFAIL;
624     }
625     code = pr_WriteEntry(at, 0, loc, &tentry);
626     if (code != 0)
627         return PRDBFAIL;
628     return PRSUCCESS;
629 }
630
631 /* RemoveFromOwnerChain - remove gid from owner chain for oid */
632
633 afs_int32
634 RemoveFromOwnerChain(struct ubik_trans *at, afs_int32 gid, afs_int32 oid)
635 {
636     afs_int32 code;
637     afs_int32 nptr;
638     struct prentry thisEntry;
639     struct prentry thatEntry;
640     struct prentry *te;         /* pointer to current (this) entry */
641     struct prentry *le;         /* pointer to previous (last) entry */
642     afs_int32 loc, lastLoc;
643
644     loc = FindByID(at, oid);
645     if (!loc)
646         return PRNOENT;
647     code = pr_ReadEntry(at, 0, loc, &thisEntry);
648     if (code != 0)
649         return PRDBFAIL;
650     le = &thisEntry;
651     lastLoc = 0;
652     nptr = thisEntry.owned;
653     while (nptr != 0) {
654         if (nptr == lastLoc)
655             te = le;
656         else {
657             if (&thisEntry == le)
658                 te = &thatEntry;
659             else
660                 te = &thisEntry;
661             code = pr_ReadEntry(at, 0, nptr, te);
662             if (code != 0)
663                 return PRDBFAIL;
664         }
665         if (te->id == gid) {
666             /* found it */
667             if (lastLoc == 0) { /* modifying first of chain */
668                 le->owned = te->nextOwned;
669                 lastLoc = loc;  /* so we write to correct location */
670             } else
671                 le->nextOwned = te->nextOwned;
672             te->nextOwned = 0;
673             if (te != le) {
674                 code = pr_WriteEntry(at, 0, nptr, te);
675                 if (code != 0)
676                     return PRDBFAIL;
677             }
678             code = pr_WriteEntry(at, 0, lastLoc, le);
679             if (code != 0)
680                 return PRDBFAIL;
681             return PRSUCCESS;
682         }
683         lastLoc = nptr;
684         le = te;
685         nptr = te->nextOwned;
686     }
687     return PRSUCCESS;           /* already removed? */
688 }
689
690 /* AddToOrphan - add gid to orphan list, as it's owner has died */
691
692 afs_int32
693 AddToOrphan(struct ubik_trans *at, afs_int32 gid)
694 {
695     afs_int32 code;
696     afs_int32 loc;
697     struct prentry tentry;
698
699     loc = FindByID(at, gid);
700     if (!loc)
701         return PRNOENT;
702     code = pr_ReadEntry(at, 0, loc, &tentry);
703     if (code != 0)
704         return PRDBFAIL;
705     tentry.nextOwned = ntohl(cheader.orphan);
706     code = set_header_word(at, orphan, htonl(loc));
707     if (code != 0)
708         return PRDBFAIL;
709     tentry.owner = 0;           /* so there's no confusion later */
710     code = pr_WriteEntry(at, 0, loc, &tentry);
711     if (code != 0)
712         return PRDBFAIL;
713     return PRSUCCESS;
714 }
715
716 afs_int32
717 RemoveFromOrphan(struct ubik_trans *at, afs_int32 gid)
718 {
719     /* remove gid from the orphan list */
720     afs_int32 code;
721     afs_int32 loc;
722     afs_int32 nptr;
723     struct prentry tentry;
724     struct prentry bentry;
725
726     loc = FindByID(at, gid);
727     if (!loc)
728         return PRNOENT;
729     code = pr_ReadEntry(at, 0, loc, &tentry);
730     if (code != 0)
731         return PRDBFAIL;
732     if (cheader.orphan == htonl(loc)) {
733         cheader.orphan = htonl(tentry.nextOwned);
734         tentry.nextOwned = 0;
735         code =
736             pr_Write(at, 0, 32, (char *)&cheader.orphan,
737                      sizeof(cheader.orphan));
738         if (code != 0)
739             return PRDBFAIL;
740         code = pr_WriteEntry(at, 0, loc, &tentry);
741         if (code != 0)
742             return PRDBFAIL;
743         return PRSUCCESS;
744     }
745     nptr = ntohl(cheader.orphan);
746     memset(&bentry, 0, sizeof(bentry));
747     loc = 0;
748     while (nptr != 0) {
749         code = pr_ReadEntry(at, 0, nptr, &tentry);
750         if (code != 0)
751             return PRDBFAIL;
752         if (gid == tentry.id) {
753             /* found it */
754             bentry.nextOwned = tentry.nextOwned;
755             tentry.nextOwned = 0;
756             code = pr_WriteEntry(at, 0, loc, &bentry);
757             if (code != 0)
758                 return PRDBFAIL;
759             code = pr_WriteEntry(at, 0, nptr, &tentry);
760             if (code != 0)
761                 return PRDBFAIL;
762             return PRSUCCESS;
763         }
764         loc = nptr;
765         nptr = tentry.nextOwned;
766         memcpy(&bentry, &tentry, sizeof(tentry));
767     }
768     return PRSUCCESS;
769 }
770
771 afs_int32
772 IsOwnerOf(struct ubik_trans *at, afs_int32 aid, afs_int32 gid)
773 {
774     /* returns 1 if aid is the owner of gid, 0 otherwise */
775     afs_int32 code;
776     struct prentry tentry;
777     afs_int32 loc;
778
779     loc = FindByID(at, gid);
780     if (!loc)
781         return 0;
782     code = pr_ReadEntry(at, 0, loc, &tentry);
783     if (code != 0)
784         return 0;
785     if (tentry.owner == aid)
786         return 1;
787     return 0;
788 }
789
790 afs_int32
791 OwnerOf(struct ubik_trans *at, afs_int32 gid)
792 {
793     /* returns the owner of gid */
794     afs_int32 code;
795     afs_int32 loc;
796     struct prentry tentry;
797
798     loc = FindByID(at, gid);
799     if (!loc)
800         return 0;
801     code = pr_ReadEntry(at, 0, loc, &tentry);
802     if (code != 0)
803         return 0;
804     return tentry.owner;
805 }
806
807
808 afs_int32
809 IsAMemberOf(struct ubik_trans *at, afs_int32 aid, afs_int32 gid)
810 {
811     /* returns true if aid is a member of gid */
812 #if !defined(SUPERGROUPS)
813     struct prentry tentry;
814     struct contentry centry;
815     afs_int32 code;
816     afs_int32 i;
817     afs_int32 loc;
818 #endif
819
820     /* special case anyuser and authuser */
821     if (gid == ANYUSERID)
822         return 1;
823     if (gid == AUTHUSERID && aid != ANONYMOUSID)
824         return 1;
825     /* check -localauth case */
826     if (gid == SYSADMINID && aid == SYSADMINID)
827         return 1;
828     if ((gid == 0) || (aid == 0))
829         return 0;
830 #if defined(SUPERGROUPS)
831     return IsAMemberOfSG(at, aid, gid, depthsg);
832 #else
833     loc = FindByID(at, gid);
834     if (!loc)
835         return 0;
836     memset(&tentry, 0, sizeof(tentry));
837     code = pr_ReadEntry(at, 0, loc, &tentry);
838     if (code)
839         return 0;
840     if (!(tentry.flags & PRGRP))
841         return 0;
842     for (i = 0; i < PRSIZE; i++) {
843         if (tentry.entries[i] == 0)
844             return 0;
845         if (tentry.entries[i] == aid)
846             return 1;
847     }
848     if (tentry.next) {
849         loc = tentry.next;
850         while (loc) {
851             memset(&centry, 0, sizeof(centry));
852             code = pr_ReadCoEntry(at, 0, loc, &centry);
853             if (code)
854                 return 0;
855             for (i = 0; i < COSIZE; i++) {
856                 if (centry.entries[i] == aid)
857                     return 1;
858                 if (centry.entries[i] == 0)
859                     return 0;
860             }
861             loc = centry.next;
862         }
863     }
864     return 0;                   /* actually, should never get here */
865 #endif
866 }
867
868
869 #if defined(SUPERGROUPS)
870 afs_int32
871 IsAMemberOfSG(struct ubik_trans *at, afs_int32 aid, afs_int32 gid, afs_int32 depth)
872 {
873     /* returns true if aid is a member of gid */
874     struct prentry tentry;
875     struct contentry centry;
876     afs_int32 code;
877     afs_int32 i;
878     afs_int32 loc;
879
880     if (depth < 1)
881         return 0;
882     loc = FindByID(at, gid);
883     if (!loc)
884         return 0;
885     memset(&tentry, 0, sizeof(tentry));
886     code = pr_ReadEntry(at, 0, loc, &tentry);
887     if (code)
888         return 0;
889     if (!(tentry.flags & PRGRP))
890         return 0;
891     for (i = 0; i < PRSIZE; i++) {
892         gid = tentry.entries[i];
893         if (gid == 0)
894             return 0;
895         if (gid == aid)
896             return 1;
897         if (gid == ANYUSERID)
898             return 1;
899         if (gid == AUTHUSERID && aid != ANONYMOUSID)
900             return 1;
901         if (gid < 0) {
902 #ifndef AFS_PTHREAD_ENV
903             IOMGR_Poll();
904 #endif
905             if (IsAMemberOfSG(at, aid, gid, depth - 1))
906                 return 1;
907         }
908     }
909     if (tentry.next) {
910         loc = tentry.next;
911         while (loc) {
912             memset(&centry, 0, sizeof(centry));
913             code = pr_ReadCoEntry(at, 0, loc, &centry);
914             if (code)
915                 return 0;
916             for (i = 0; i < COSIZE; i++) {
917                 gid = centry.entries[i];
918                 if (gid == 0)
919                     return 0;
920                 if (gid == aid)
921                     return 1;
922                 if (gid == ANYUSERID)
923                     return 1;
924                 if (gid == AUTHUSERID && aid != ANONYMOUSID)
925                     return 1;
926                 if (gid < 0) {
927 #ifndef AFS_PTHREAD_ENV
928                     IOMGR_Poll();
929 #endif
930                     if (IsAMemberOfSG(at, aid, gid, depth - 1))
931                         return 1;
932                 }
933             }
934             loc = centry.next;
935         }
936     }
937     return 0;                   /* actually, should never get here */
938 }
939 #endif /* SUPERGROUPS */