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