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