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