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