aix51-support-20021008
[openafs.git] / src / afs / UKERNEL / afs_usrops.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 /*
11  * User space client specific interface glue
12  */
13
14 #include <afsconfig.h>
15 #include "../afs/param.h"
16
17 RCSID("$Header$");
18
19
20 #ifdef  UKERNEL
21
22 #include "../afs/sysincludes.h" /* Standard vendor system headers */
23 #include <net/if.h>
24 #include "../afs/afsincludes.h" /* Afs-based standard headers */
25 #include "../afs/afs_usrops.h"
26 #include "../afs/afs_stats.h"
27 #include "../afs/auth.h"
28 #include "../afs/cellconfig.h"
29 #include "../afs/vice.h"
30 #include "../afs/kautils.h"
31 #include "../afs/afsutil.h"
32 #include "../rx/rx_globals.h"
33
34 #define VFS 1
35 #undef  VIRTUE
36 #undef  VICE
37
38 #define CACHEINFOFILE   "cacheinfo"
39 #define AFSLOGFILE      "AFSLog"
40 #define DCACHEFILE      "CacheItems"
41 #define VOLINFOFILE     "VolumeItems"
42 #define MAXIPADDRS 64
43
44 #ifndef MIN
45 #define MIN(A,B)        ((A)<(B)?(A):(B))
46 #endif
47 #ifndef MAX
48 #define MAX(A,B)        ((A)>(B)?(A):(B))
49 #endif
50
51 extern int cacheDiskType;
52
53 char afs_LclCellName[64];
54
55 struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
56 int afs_FileFlags[MAX_OSI_FILES];
57 int afs_FileOffsets[MAX_OSI_FILES];
58
59 #define MAX_CACHE_LOOPS 4
60
61 struct usr_vfs afs_RootVfs;
62 struct usr_vnode *afs_RootVnode = NULL;
63 struct usr_vnode *afs_CurrentDir = NULL;
64
65 afs_int32 cacheBlocks;                  /* Num blocks in cache */
66 afs_int32 cacheFiles = 1000;            /* Num files in workstation cache */
67 afs_int32 cacheStatEntries = 300;               /* Num of stat cache entries */
68 char cacheBaseDir[1024];                /* AFS cache directory */
69 char confDir[1024];                     /* AFS configuration directory */
70 char afs_mountDir[1024];                /* AFS mount point */
71 int afs_mountDirLen;                    /* strlen of AFS mount point */
72 char fullpn_DCacheFile[1024];           /* Full pathname of DCACHEFILE */
73 char fullpn_VolInfoFile[1024];          /* Full pathname of VOLINFOFILE */
74 char fullpn_AFSLogFile[1024];           /* Full pathname of AFSLOGFILE */
75 char fullpn_CacheInfo[1024];            /* Full pathname of CACHEINFO */
76 char fullpn_VFile[1024];                /* Full pathname of data cache files */
77 char *vFileNumber;                      /* Ptr to number in file pathname */
78 char rootVolume[64] = "root.afs";       /* AFS root volume name */
79 afs_int32 isHomeCell;                   /* Is current cell info for home cell */
80 afs_int32 lookingForHomeCell;           /* Are we still looking for home cell */
81 int createAndTrunc = O_CREAT | O_TRUNC; /* Create & truncate on open */
82 int ownerRWmode = 0600;                 /* Read/write OK by owner */
83 static int nDaemons = 2;                /* Number of background daemons */
84 static int chunkSize = 0;               /* 2^chunkSize bytes per chunk */
85 static int dCacheSize = 300;            /* # of dcache entries */
86 static int vCacheSize = 50;             /* # of volume cache entries */
87 static int cacheFlags = 0;              /* Flags to cache manager */
88 static int preallocs = 400;             /* Def # of allocated memory blocks */
89 int afsd_verbose = 0;                   /* Are we being chatty? */
90 int afsd_debug = 0;                     /* Are we printing debugging info? */
91 int afsd_CloseSynch = 0;                /* Are closes synchronous or not? */
92
93 #define AFSD_INO_T afs_uint32
94 char **pathname_for_V;                  /* Array of cache file pathnames */
95 int missing_DCacheFile = 1;             /* Is the DCACHEFILE missing? */
96 int missing_VolInfoFile = 1;            /* Is the VOLINFOFILE missing? */
97 struct afs_cacheParams cparams;         /* params passed to cache manager */
98 struct afsconf_dir *afs_cdir;           /* config dir */
99
100 static int HandleMTab();
101
102 int afs_bufferpages = 100;
103 int usr_udpcksum = 0;
104
105 usr_key_t afs_global_u_key;
106
107 struct usr_proc *afs_global_procp;
108 struct usr_ucred *afs_global_ucredp;
109 struct usr_sysent usr_sysent[200];
110
111 #ifdef AFS_USR_OSF_ENV
112 char V = 'V';
113 #else /* AFS_USR_OSF_ENV */
114 long V = 'V';
115 #endif /* AFS_USR_OSF_ENV */
116
117 struct usr_ucred afs_osi_cred;
118 usr_mutex_t afs_global_lock;
119 usr_thread_t afs_global_owner;
120 usr_mutex_t rx_global_lock;
121 usr_thread_t rx_global_owner;
122 usr_mutex_t osi_inode_lock;
123 usr_mutex_t osi_waitq_lock;
124 usr_mutex_t osi_authenticate_lock;
125 afs_lock_t afs_ftf;
126 afs_lock_t osi_flplock;
127 afs_lock_t osi_fsplock;
128 void *vnodefops;
129
130 #ifndef NETSCAPE_NSAPI
131  
132 /*
133  * Mutex and condition variable used to implement sleep
134  */
135 pthread_mutex_t usr_sleep_mutex;
136 pthread_cond_t usr_sleep_cond;
137
138 #endif /* !NETSCAPE_NSAPI */
139
140 int call_syscall(long, long, long, long, long, long);
141
142
143 /*
144  * Hash table mapping addresses onto wait structures for
145  * osi_Sleep/osi_Wakeup and osi_Wait/osi_Wakeup
146  */
147 typedef struct osi_wait {
148     caddr_t             addr;
149     usr_cond_t          cond;
150     int                 flag;
151     struct osi_wait     *next;
152     struct osi_wait     *prev;
153     time_t              expiration;
154     struct osi_wait     *timedNext;
155     struct osi_wait     *timedPrev;
156 } osi_wait_t;
157
158 /*
159  * Head of the linked list of available waitq structures.
160  */
161 osi_wait_t *osi_waithash_avail;
162
163 /*
164  * List of timed waits, NSAPI does not provide a cond_timed
165  * wait, so we need to keep track of the timed waits ourselves and
166  * periodically check for expirations
167  */
168 osi_wait_t *osi_timedwait_head;
169 osi_wait_t *osi_timedwait_tail;
170
171 struct {
172     osi_wait_t          *head;
173     osi_wait_t          *tail;
174 } osi_waithash_table[OSI_WAITHASH_SIZE];
175
176 /*
177  * Never call afs_brelse
178  */
179 int ufs_brelse(struct usr_vnode *vp, struct usr_buf *bp)
180 {
181     usr_assert(0);
182 }
183
184 /*
185  * I am not sure what to do with these, they assert for now
186  */
187 int iodone(struct usr_buf *bp)
188 {
189     usr_assert(0);
190 }
191
192 struct usr_file *getf(int fd)
193 {
194     usr_assert(0);
195 }
196
197 /*
198  * Every user is a super user
199  */
200 int afs_osi_suser(void *credp)
201 {
202     return 1;
203 }
204
205 int afs_suser(void *credp)
206 {
207     return 1;
208 }
209
210 /*
211  * These are no-ops in user space
212  */
213
214 int afs_osi_SetTime(osi_timeval_t *atv)
215 {
216     return 0;
217 }
218
219 /*
220  * xflock should never fall through, the only files we know
221  * about are AFS files
222  */
223 int usr_flock(void)
224 {
225     usr_assert(0);
226 }
227
228 /*
229  * ioctl should never fall through, the only files we know
230  * about are AFS files
231  */
232 int usr_ioctl(void)
233 {
234     usr_assert(0);
235 }
236
237 /*
238  * We do not support the inode related system calls
239  */
240 int afs_syscall_icreate(void)
241 {
242     usr_assert(0);
243 }
244
245 int afs_syscall_iincdec(void)
246 {
247     usr_assert(0);
248 }
249
250 int afs_syscall_iopen(void)
251 {
252     usr_assert(0);
253 }
254
255 int afs_syscall_ireadwrite(void)
256 {
257     usr_assert(0);
258 }
259
260 /*
261  * these routines are referenced in the vfsops structure, but
262  * should never get called
263  */
264 int vno_close(void)
265 {
266     usr_assert(0);
267 }
268
269 int vno_ioctl(void)
270 {
271     usr_assert(0);
272 }
273
274 int vno_rw(void)
275 {
276     usr_assert(0);
277 }
278
279 int vno_select(void)
280 {
281     usr_assert(0);
282 }
283
284 /*
285  * uiomove copies data between kernel buffers and uio buffers
286  */
287 int usr_uiomove(char *kbuf, int n, int rw, struct usr_uio *uio)
288 {
289     int nio;
290     int len;
291     char *ptr;
292     struct iovec *iovp;
293
294     nio = uio->uio_iovcnt;
295     iovp = uio->uio_iov;
296
297     if (nio <= 0)
298         return EFAULT;
299
300     /*
301      * copy the data
302      */
303     ptr = kbuf;
304     while(nio > 0 && n > 0) {
305         len = MIN(n, iovp->iov_len);
306         if (rw == UIO_READ) {
307             memcpy(iovp->iov_base, ptr, len);
308         } else {
309             memcpy(ptr, iovp->iov_base, len);
310         }
311         n -= len;
312         ptr += len;
313         uio->uio_resid -= len;
314         uio->uio_offset += len;
315         iovp->iov_base = (char *)(iovp->iov_base) + len;
316         iovp->iov_len -= len;
317         iovp++;
318         nio--;
319     }
320
321     if (n > 0)
322         return EFAULT;
323     return 0;
324 }
325
326 /*
327  * routines to manage user credentials
328  */
329 struct usr_ucred *usr_crcopy(struct usr_ucred *credp)
330 {
331     struct usr_ucred *newcredp;
332
333     newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
334     *newcredp = *credp;
335     newcredp->cr_ref = 1;
336     return newcredp;
337 }
338
339 struct usr_ucred *usr_crget(void)
340 {
341     struct usr_ucred *newcredp;
342
343     newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
344     newcredp->cr_ref = 1;
345     return newcredp;
346 }
347
348 int usr_crfree(struct usr_ucred *credp)
349 {
350     credp->cr_ref--;
351     if (credp->cr_ref == 0) {
352         afs_osi_Free((char *)credp, sizeof(struct usr_ucred));
353     }
354 }
355
356 int usr_crhold(struct usr_ucred *credp)
357 {
358     credp->cr_ref++;
359 }
360
361 void usr_vattr_null(struct usr_vattr *vap)
362 {
363     int n;
364     char *cp;
365  
366     n = sizeof(struct usr_vattr);
367     cp = (char *)vap;
368     while (n--) {
369         *cp++ = -1;
370     }
371 }
372
373 /*
374  * Initialize the thread specific data used to simulate the
375  * kernel environment for each thread. The user structure
376  * is stored in the thread specific data.
377  */
378 void uafs_InitThread(void)
379 {
380     int st;
381     struct usr_user *uptr;
382
383     /*
384      * initialize the thread specific user structure. Use malloc to
385      * allocate the data block, so pthread_finish can free the buffer
386      * when this thread terminates.
387      */
388     uptr = (struct usr_user *)malloc(sizeof(struct usr_user) +
389                                      sizeof(struct usr_ucred));
390     usr_assert(uptr != NULL);
391     uptr->u_error = 0;
392     uptr->u_prio = 0;
393     uptr->u_procp = afs_global_procp;
394     uptr->u_cred = (struct usr_ucred *)(uptr+1);
395     *uptr->u_cred = *afs_global_ucredp;
396     st = usr_setspecific(afs_global_u_key, (void *)uptr);
397     usr_assert(st == 0);
398 }
399
400 /*
401  * routine to get the user structure from the thread specific data.
402  * this routine is used to implement the global 'u' structure. Initializes
403  * the thread if needed.
404  */
405 struct usr_user *get_user_struct(void)
406 {
407     struct usr_user *uptr;
408     int st;
409     st = usr_getspecific(afs_global_u_key, (void **)&uptr);
410     usr_assert(st == 0);
411     if(uptr == NULL) {
412         uafs_InitThread();
413         st = usr_getspecific(afs_global_u_key, (void **)&uptr);
414         usr_assert(st == 0);
415         usr_assert(uptr != NULL);
416     }
417     return uptr;
418 }
419
420 /*
421  * Hash an address for the waithash table
422  */
423 #define WAITHASH(X)     \
424         (((long)(X)^((long)(X)>>4)^((long)(X)<<4))&(OSI_WAITHASH_SIZE-1))
425
426 /*
427  * Sleep on an event
428  */
429 void afs_osi_Sleep(void *x)
430 {
431     int index;
432     osi_wait_t *waitp;
433     int rxGlockOwner = ISAFS_RXGLOCK();
434     int glockOwner = ISAFS_GLOCK();
435
436     usr_mutex_lock(&osi_waitq_lock);
437     if (glockOwner) {
438         AFS_GUNLOCK();
439     }
440     if (rxGlockOwner) {
441         AFS_RXGUNLOCK();
442     }
443     index = WAITHASH(x);
444     if (osi_waithash_avail == NULL) {
445         waitp = (osi_wait_t *)afs_osi_Alloc(sizeof(osi_wait_t));
446         usr_cond_init(&waitp->cond);
447     } else {
448         waitp = osi_waithash_avail;
449         osi_waithash_avail = osi_waithash_avail->next;
450     }
451     waitp->addr = x;
452     waitp->flag = 0;
453     DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
454                     osi_waithash_table[index].tail, next, prev);
455     waitp->expiration = 0;
456     waitp->timedNext = NULL;
457     waitp->timedPrev = NULL;
458     while (waitp->flag == 0) {
459         usr_cond_wait(&waitp->cond, &osi_waitq_lock);
460     }
461     DLL_DELETE(waitp, osi_waithash_table[index].head,
462                osi_waithash_table[index].tail, next, prev);
463     waitp->next = osi_waithash_avail;
464     osi_waithash_avail = waitp;
465     usr_mutex_unlock(&osi_waitq_lock);
466     if (glockOwner) {
467         AFS_GLOCK();
468     }
469     if (rxGlockOwner) {
470         AFS_RXGLOCK();
471     }
472 }
473
474 int afs_osi_SleepSig(void *x)
475 {
476     afs_osi_Sleep(x);
477     return 0;
478 }
479
480 int afs_osi_Wakeup(void *x)
481 {
482     int index;
483     osi_wait_t *waitp;
484
485     index = WAITHASH(x);
486     usr_mutex_lock(&osi_waitq_lock);
487     waitp = osi_waithash_table[index].head;
488     while (waitp) {
489         if (waitp->addr == x && waitp->flag == 0) {
490             waitp->flag = 1;
491             usr_cond_signal(&waitp->cond);
492         }
493         waitp = waitp->next;
494     }
495     usr_mutex_unlock(&osi_waitq_lock);
496 }
497
498 int afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
499 {
500     int index;
501     osi_wait_t *waitp;
502     struct timespec tv;
503     int ret;
504     int rxGlockOwner = ISAFS_RXGLOCK();
505     int glockOwner = ISAFS_GLOCK();
506
507     tv.tv_sec = msec / 1000;
508     tv.tv_nsec = (msec % 1000) * 1000000;
509     if (handle == NULL) {
510         if (glockOwner) {
511             AFS_GUNLOCK();
512         }
513         if (rxGlockOwner) {
514             AFS_RXGUNLOCK();
515         }
516         usr_thread_sleep(&tv);
517         ret = 0;
518         if (glockOwner) {
519             AFS_GLOCK();
520         }    
521         if (rxGlockOwner) {
522             AFS_RXGLOCK();
523         }
524     } else {
525         usr_mutex_lock(&osi_waitq_lock);
526         if (glockOwner) {
527             AFS_GUNLOCK();
528         }
529         if (rxGlockOwner) {
530             AFS_RXGUNLOCK();
531         }
532         index = WAITHASH((caddr_t)handle);
533         if (osi_waithash_avail == NULL) {
534             waitp = (osi_wait_t *)afs_osi_Alloc(sizeof(osi_wait_t));
535             usr_cond_init(&waitp->cond);
536         } else {
537             waitp = osi_waithash_avail;
538             osi_waithash_avail = osi_waithash_avail->next;
539         }
540         waitp->addr = (caddr_t)handle;
541         waitp->flag = 0;
542         DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
543                         osi_waithash_table[index].tail, next, prev);
544         tv.tv_sec += time(NULL);
545         waitp->expiration = tv.tv_sec + ((tv.tv_nsec == 0)?0:1);
546         DLL_INSERT_TAIL(waitp, osi_timedwait_head, osi_timedwait_tail,
547                         timedNext, timedPrev);
548         usr_cond_wait(&waitp->cond, &osi_waitq_lock);
549         if (waitp->flag) {
550             ret = 2;
551         } else {
552             ret = 0;
553         }
554         DLL_DELETE(waitp, osi_waithash_table[index].head,
555                    osi_waithash_table[index].tail, next, prev);
556         DLL_DELETE(waitp, osi_timedwait_head, osi_timedwait_tail,
557                    timedNext, timedPrev);
558         waitp->next = osi_waithash_avail;
559         osi_waithash_avail = waitp;
560         usr_mutex_unlock(&osi_waitq_lock);
561         if (glockOwner) {
562             AFS_GLOCK();
563         }
564         if (rxGlockOwner) {
565             AFS_RXGLOCK();
566         }
567     }
568     return ret;
569 }
570
571 void afs_osi_CancelWait(struct afs_osi_WaitHandle *handle)
572 {
573     afs_osi_Wakeup(handle);
574 }
575
576 /*
577  * Netscape NSAPI doesn't have a cond_timed_wait, so we need
578  * to explicitly signal cond_timed_waits when their timers expire
579  */
580 int afs_osi_CheckTimedWaits(void)
581 {
582     time_t curTime;
583     osi_wait_t *waitp;
584
585     curTime = time(NULL);
586     usr_mutex_lock(&osi_waitq_lock);
587     waitp = osi_timedwait_head;
588     while (waitp != NULL) {
589         usr_assert(waitp->expiration != 0);
590         if (waitp->expiration <= curTime) {
591             waitp->flag = 1;
592             usr_cond_signal(&waitp->cond);
593         }
594         waitp = waitp->timedNext;
595     }
596     usr_mutex_unlock(&osi_waitq_lock);
597 }
598
599 /*
600  * I-node numbers are indeces into a table containing a filename
601  * i-node structure and a vnode structure. When we create an i-node,
602  * we copy the name into the array and initialize enough of the fields
603  * in the inode and vnode structures to get the client to work.
604  */
605 typedef struct {
606     struct usr_inode i_node;
607     char *name;
608 } osi_file_table_t;
609 osi_file_table_t *osi_file_table;
610 int n_osi_files = 0;
611 int max_osi_files = 0;
612
613 /*
614  * Allocate a slot in the file table if there is not one there already,
615  * copy in the file name and kludge up the vnode and inode structures
616  */
617 int lookupname(char *fnamep, int segflg, int followlink, 
618         struct usr_vnode **dirvpp, struct usr_vnode **compvpp)
619 {
620     int i;
621     int code;
622     struct usr_inode *ip;
623     struct usr_vnode *vp;
624
625     /*usr_assert(followlink == 0);*/
626     usr_assert(dirvpp == NULL);
627
628     /*
629      * Assume relative pathnames refer to files in AFS
630      */
631     if (*fnamep != '/' || uafs_afsPathName(fnamep) != NULL) {
632         AFS_GLOCK();
633         code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0, 0);
634         AFS_GUNLOCK();
635         return code;
636     }
637
638     usr_mutex_lock(&osi_inode_lock);
639
640     for (i = 0 ; i < n_osi_files ; i++) {
641         if (strcmp(fnamep, osi_file_table[i].name) == 0) {
642             *compvpp = &osi_file_table[i].i_node.i_vnode;
643             (*compvpp)->v_count++;
644             usr_mutex_unlock(&osi_inode_lock);
645             return 0;
646         }
647     }
648
649     if (n_osi_files == max_osi_files) {
650         usr_mutex_unlock(&osi_inode_lock);
651         return ENOSPC;
652     }
653
654     osi_file_table[n_osi_files].name = afs_osi_Alloc(strlen(fnamep)+1);
655     usr_assert(osi_file_table[n_osi_files].name != NULL);
656     strcpy(osi_file_table[n_osi_files].name, fnamep);
657     ip = &osi_file_table[i].i_node;
658     vp = &ip->i_vnode;
659     vp->v_data = (caddr_t)ip;
660     ip->i_dev = -1;
661     n_osi_files++;
662     ip->i_number = n_osi_files;
663     vp->v_count = 2;
664     usr_mutex_unlock(&osi_inode_lock);
665     *compvpp = vp;
666     return 0;
667 }
668
669 /*
670  * open a file given its i-node number
671  */
672 void *osi_UFSOpen(afs_int32 ino)
673 {
674     int rc;
675     struct osi_file *fp;
676     struct stat st;
677
678     AFS_ASSERT_GLOCK();
679
680     if (ino > n_osi_files) {
681         u.u_error = ENOENT;
682         return NULL;
683     }
684
685     AFS_GUNLOCK();
686     fp = (struct osi_file *)afs_osi_Alloc(sizeof(struct osi_file));
687     usr_assert(fp != NULL);
688     fp->fd = open(osi_file_table[ino-1].name, O_RDWR|O_CREAT, 0);
689     if (fp->fd < 0) {
690         u.u_error = errno;
691         afs_osi_Free((char *)fp, sizeof(struct osi_file));
692         AFS_GLOCK();
693         return NULL;
694     }
695     rc = fstat(fp->fd, &st);
696     if (rc < 0) {
697         u.u_error = errno;
698         afs_osi_Free((void *)fp, sizeof(struct osi_file));
699         AFS_GLOCK();
700         return NULL;
701     }
702     fp->size = st.st_size;
703     fp->offset = 0;
704     fp->inum = ino;
705     fp->vnode = (struct usr_vnode *)fp;
706
707     AFS_GLOCK();
708     return fp;
709 }
710
711 int osi_UFSClose(struct osi_file *fp)
712 {
713     int rc;
714
715     AFS_ASSERT_GLOCK();
716
717     AFS_GUNLOCK();
718     rc = close(fp->fd);
719     if (rc < 0) {
720         u.u_error = errno;
721         afs_osi_Free((void *)fp, sizeof(struct osi_file));
722         AFS_GLOCK();
723         return -1;
724     }
725     afs_osi_Free((void *)fp, sizeof(struct osi_file));
726     AFS_GLOCK();
727     return 0;
728 }
729
730 int osi_UFSTruncate(struct osi_file *fp, afs_int32 len)
731 {
732     int rc;
733
734     AFS_ASSERT_GLOCK();
735
736     AFS_GUNLOCK();
737     rc = ftruncate(fp->fd, len);
738     if (rc < 0) {
739         u.u_error = errno;
740         AFS_GLOCK();
741         return -1;
742     }
743     fp->size = len;
744     AFS_GLOCK();
745     return 0;
746 }
747
748 int afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
749 {
750     int rc, ret;
751     int code;
752     struct stat st;
753
754     AFS_ASSERT_GLOCK();
755
756     AFS_GUNLOCK();
757     if (offset >= 0) {
758         rc = lseek(fp->fd, offset, SEEK_SET);
759     } else {
760         rc = lseek(fp->fd, fp->offset, SEEK_SET);
761     }
762     if (rc < 0) {
763         u.u_error = errno;
764         AFS_GLOCK();
765         return -1;
766     }
767     fp->offset = rc;
768     ret = read(fp->fd, buf, len);
769     if (ret < 0) {
770         u.u_error = errno;
771         AFS_GLOCK();
772         return -1;
773     }
774     fp->offset += ret;
775     rc = fstat(fp->fd, &st);
776     if (rc < 0) {
777         u.u_error = errno;
778         AFS_GLOCK();
779         return -1;
780     }
781     fp->size = st.st_size;
782     AFS_GLOCK();
783     return ret;
784 }
785
786 int afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
787 {
788     int rc, ret;
789     int code;
790     struct stat st;
791
792     AFS_ASSERT_GLOCK();
793
794     AFS_GUNLOCK();
795     if (offset >= 0) {
796         rc = lseek(fp->fd, offset, SEEK_SET);
797     } else {
798         rc = lseek(fp->fd, fp->offset, SEEK_SET);
799     }
800     if (rc < 0) {
801         u.u_error = errno;
802         AFS_GLOCK();
803         return -1;
804     }
805     fp->offset = rc;
806     ret = write(fp->fd, buf, len);
807     if (ret < 0) {
808         u.u_error = errno;
809         AFS_GLOCK();
810         return -1;
811     }
812     fp->offset += ret;
813     rc = fstat(fp->fd, &st);
814     if (rc < 0) {
815         u.u_error = errno;
816         AFS_GLOCK();
817         return -1;
818     }
819     fp->size = st.st_size;
820     AFS_GLOCK();
821     return ret;
822 }
823
824 int afs_osi_Stat(struct osi_file *fp, struct osi_stat *stp)
825 {
826     int rc;
827     struct stat st;
828
829     AFS_GUNLOCK();
830     rc = fstat(fp->fd, &st);
831     if (rc < 0) {
832         u.u_error = errno;
833         AFS_GLOCK();
834         return -1;
835     }
836     stp->size = st.st_size;
837     stp->blksize = st.st_blksize;
838     stp->mtime = st.st_mtime;
839     stp->atime = st.st_atime;
840     AFS_GLOCK();
841     return 0;
842 }
843
844 /*
845  * VOP_RDWR routine
846  */
847 int afs_osi_VOP_RDWR(
848     struct usr_vnode *vnodeP,
849     struct usr_uio *uioP,
850     int rw,
851     int flags,
852     struct usr_ucred* credP)
853 {
854     int rc;
855     struct osi_file *fp = (struct osi_file *)vnodeP;
856
857     /*
858      * We don't support readv/writev.
859      */
860     usr_assert(uioP->uio_iovcnt == 1);
861     usr_assert(uioP->uio_resid == uioP->uio_iov[0].iov_len);
862
863     if (rw == UIO_WRITE) {
864         usr_assert(uioP->uio_fmode == FWRITE);
865         rc = afs_osi_Write(fp, uioP->uio_offset,
866                            uioP->uio_iov[0].iov_base,
867                            uioP->uio_iov[0].iov_len);
868     } else {
869         usr_assert(uioP->uio_fmode == FREAD);
870         rc = afs_osi_Read(fp, uioP->uio_offset,
871                           uioP->uio_iov[0].iov_base,
872                           uioP->uio_iov[0].iov_len);
873     }
874     if (rc < 0) {
875         return u.u_error;
876     }
877
878     uioP->uio_resid -= rc;
879     uioP->uio_offset += rc;
880     uioP->uio_iov[0].iov_base = (char *)(uioP->uio_iov[0].iov_base) + rc;
881     uioP->uio_iov[0].iov_len -= rc;
882     return 0;
883 }
884
885 /*
886  * Use malloc/free routines with check patterns before and after each block
887  */
888
889 static char *afs_check_string1 = "UAFS";
890 static char *afs_check_string2 = "AFS_OSI_";
891
892 void *afs_osi_Alloc(size_t size)
893 {
894     return malloc(size);
895 }
896
897 void afs_osi_Free(void *ptr, size_t size)
898 {
899     free(ptr);
900 }
901
902 void afs_osi_FreeStr(char *ptr)
903 {
904     free(ptr);
905 }
906
907 void *osi_AllocLargeSpace(size_t size)
908 {
909     AFS_STATCNT(osi_AllocLargeSpace);
910     return afs_osi_Alloc(size);
911 }
912
913 void osi_FreeLargeSpace(void *ptr)
914 {
915     AFS_STATCNT(osi_FreeLargeSpace);
916     afs_osi_Free(ptr, 0);
917 }
918
919 void *osi_AllocSmallSpace(size_t size)
920 {
921     AFS_STATCNT(osi_AllocSmallSpace);
922     return afs_osi_Alloc(size);
923 }
924
925 void osi_FreeSmallSpace(void *ptr)
926 {
927     AFS_STATCNT(osi_FreeSmallSpace);
928     afs_osi_Free(ptr, 0);
929 }
930
931 void shutdown_osi(void)
932 {
933     AFS_STATCNT(shutdown_osi);
934     return;
935 }
936
937 void shutdown_osinet(void)
938 {
939     AFS_STATCNT(shutdown_osinet);
940     return;
941 }
942
943 void shutdown_osifile(void)
944 {
945     AFS_STATCNT(shutdown_osifile);
946     return;
947 }
948
949 int afs_nfsclient_init(void)
950 {
951     return 0;
952 }
953
954 void shutdown_nfsclnt(void)
955 {
956     return;
957 }
958
959 void afs_osi_Invisible(void)
960 {
961     return;
962 }
963
964 int osi_GetTime(struct timeval *tv)
965 {
966     gettimeofday(tv, NULL);
967     return 0;
968 }
969
970 int osi_SetTime(struct timeval *tv)
971 {
972     return 0;
973 }
974
975 int osi_Active(struct vcache *avc)
976 {
977     AFS_STATCNT(osi_Active);
978     if (avc->opens > 0) return(1);
979     return 0;
980 }
981
982 int afs_osi_MapStrategy(int (*aproc)(), struct usr_buf *bp)
983 {
984     afs_int32 returnCode;
985     returnCode = (*aproc)(bp);
986     return returnCode;
987 }
988
989 void osi_FlushPages(register struct vcache *avc, struct AFS_UCRED *credp)
990 {
991     ObtainSharedLock(&avc->lock,555);
992     if ((hcmp((avc->m.DataVersion), (avc->mapDV)) <= 0) || 
993         ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
994         ReleaseSharedLock(&avc->lock);
995         return;
996     }
997     UpgradeSToWLock(&avc->lock,565);
998     hset(avc->mapDV, avc->m.DataVersion);
999     ReleaseWriteLock(&avc->lock);
1000     return;
1001 }
1002
1003 void osi_FlushText_really(register struct vcache *vp)
1004 {
1005     if (hcmp(vp->m.DataVersion, vp->flushDV) > 0) {
1006         hset(vp->flushDV, vp->m.DataVersion);
1007     }
1008     return;
1009 }
1010
1011 int osi_SyncVM(struct vcache *avc)
1012 {
1013     return 0;
1014 }
1015
1016 void osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
1017 {
1018     return;
1019 }
1020
1021 void osi_Init(void)
1022 {
1023     int i;
1024     int rc;
1025     usr_thread_t tid;
1026
1027     /*
1028      * Allocate the table used to implement psuedo-inodes.
1029      */
1030     max_osi_files = cacheFiles + 100;
1031     osi_file_table = (osi_file_table_t *)
1032                      afs_osi_Alloc(max_osi_files * sizeof(osi_file_table_t));
1033     usr_assert(osi_file_table != NULL);
1034
1035 #ifndef NETSCAPE_NSAPI
1036     /*
1037      * Initialize the mutex and condition variable used to implement
1038      * time sleeps.
1039      */
1040     pthread_mutex_init(&usr_sleep_mutex, NULL);
1041     pthread_cond_init(&usr_sleep_cond, NULL);
1042 #endif /* !NETSCAPE_NSAPI */
1043
1044     /*
1045      * Initialize the hash table used for sleep/wakeup
1046      */
1047     for (i = 0 ; i < OSI_WAITHASH_SIZE ; i++) {
1048         DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1049     }
1050     DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1051     osi_waithash_avail = NULL;
1052
1053     /*
1054      * Initialize the AFS file table
1055      */
1056     for (i = 0 ; i < MAX_OSI_FILES ; i++) {
1057         afs_FileTable[i] = NULL;
1058     }
1059
1060     /*
1061      * Initialize the global locks
1062      */
1063     usr_mutex_init(&afs_global_lock);
1064     usr_mutex_init(&rx_global_lock);
1065     usr_mutex_init(&osi_inode_lock);
1066     usr_mutex_init(&osi_waitq_lock);
1067     usr_mutex_init(&osi_authenticate_lock);
1068
1069     /*
1070      * Initialize the AFS OSI credentials
1071      */
1072     afs_osi_cred = *afs_global_ucredp;
1073 }
1074
1075 /* ParseArgs is now obsolete, being handled by cmd */
1076
1077 /*---------------------------------------------------------------------
1078   * GetVFileNumber
1079   *
1080   * Description:
1081   *     Given the final component of a filename expected to be a data cache file,
1082   *     return the integer corresponding to the file.  Note: we reject names that
1083   *     are not a ``V'' followed by an integer.  We also reject those names having
1084   *     the right format but lying outside the range [0..cacheFiles-1].
1085   *
1086   * Arguments:
1087   *     fname : Char ptr to the filename to parse.
1088   *
1089   * Returns:
1090   *     >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
1091   *     -1      otherwise.
1092   *
1093   * Environment:
1094   *     Nothing interesting.
1095   *
1096   * Side Effects:
1097   *     None.
1098   *------------------------------------------------------------------------*/
1099
1100 int GetVFileNumber(char *fname)
1101 {
1102     int computedVNumber;    /*The computed file number we return*/
1103     int filenameLen;        /*Number of chars in filename*/
1104     int currDigit;          /*Current digit being processed*/
1105
1106     /*
1107      * The filename must have at least two characters, the first of which must be a ``V''
1108      * and the second of which cannot be a zero unless the file is exactly two chars long.
1109      */
1110     filenameLen = strlen(fname);
1111     if (filenameLen < 2)
1112         return(-1);
1113     if (fname[0] != 'V')
1114         return(-1);
1115     if ((filenameLen > 2) && (fname[1] == '0'))
1116         return(-1);
1117
1118     /*
1119      * Scan through the characters in the given filename, failing immediately if a non-digit
1120      * is found.
1121      */
1122     for (currDigit = 1; currDigit < filenameLen; currDigit++)
1123         if (isdigit(fname[currDigit]) == 0)
1124             return(-1);
1125
1126     /*
1127      * All relevant characters are digits.  Pull out the decimal number they represent.
1128      * Reject it if it's out of range, otherwise return it.
1129      */
1130     computedVNumber = atoi(++fname);
1131     if (computedVNumber < cacheFiles)
1132         return(computedVNumber);
1133     else
1134         return(-1);
1135 }
1136
1137 /*---------------------------------------------------------------------
1138   * CreateCacheFile
1139   *
1140   * Description:
1141   *     Given a full pathname for a file we need to create for the workstation AFS
1142   *     cache, go ahead and create the file.
1143   *
1144   * Arguments:
1145   *     fname : Full pathname of file to create.
1146   *
1147   * Returns:
1148   *     0   iff the file was created,
1149   *     -1  otherwise.
1150   *
1151   * Environment:
1152   *     The given cache file has been found to be missing.
1153   *
1154   * Side Effects:
1155   *     As described.
1156   *------------------------------------------------------------------------*/
1157
1158 int CreateCacheFile(char *fname)
1159 {
1160     static char rn[] = "CreateCacheFile";   /*Routine name*/
1161     int cfd;                                /*File descriptor to AFS cache file*/
1162     int closeResult;                        /*Result of close()*/
1163
1164     if (afsd_verbose)
1165         printf("%s: Creating cache file '%s'\n",
1166                rn, fname);
1167     cfd = open(fname, createAndTrunc, ownerRWmode);
1168     if  (cfd <= 0) {
1169         printf("%s: Can't create '%s', error return is %d (%d)\n",
1170                rn, fname, cfd, errno);
1171         return(-1);
1172     }
1173     closeResult = close(cfd);
1174     if  (closeResult) {
1175         printf("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
1176                rn, fname, errno);
1177         return(-1);
1178     }
1179
1180     return(0);
1181 }
1182
1183 /*---------------------------------------------------------------------
1184   * SweepAFSCache
1185   *
1186   * Description:
1187   *     Sweep through the AFS cache directory, recording the inode number for
1188   *     each valid data cache file there.  Also, delete any file that doesn't beint32
1189   *     in the cache directory during this sweep, and remember which of the other
1190   *     residents of this directory were seen.  After the sweep, we create any data
1191   *     cache files that were missing.
1192   *
1193   * Arguments:
1194   *     vFilesFound : Set to the number of data cache files found.
1195   *
1196   * Returns:
1197   *     0   if everything went well,
1198   *     -1 otherwise.
1199   *
1200   * Environment:
1201   *     This routine may be called several times.  If the number of data cache files
1202   *     found is less than the global cacheFiles, then the caller will need to call it
1203   *     again to record the inodes of the missing zero-length data cache files created
1204   *     in the previous call.
1205   *
1206   * Side Effects:
1207   *     Fills up the global pathname_for_V array, may create and/or
1208   *     delete files as explained above.
1209   *------------------------------------------------------------------------*/
1210
1211 int SweepAFSCache(int *vFilesFound)
1212 {
1213     static char rn[] = "SweepAFSCache"; /*Routine name*/
1214     char fullpn_FileToDelete[1024];     /*File to be deleted from cache*/
1215     char *fileToDelete;                 /*Ptr to last component of above*/
1216     DIR *cdirp;                         /*Ptr to cache directory structure*/
1217 #undef dirent
1218     struct dirent *currp;               /*Current directory entry*/
1219     int vFileNum;                       /*Data cache file's associated number*/
1220
1221     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1222         if (afsd_debug)
1223             printf("%s: Memory Cache, no cache sweep done\n", rn);
1224         *vFilesFound = 0;
1225         return 0;
1226     }
1227
1228     if (afsd_debug)
1229         printf("%s: Opening cache directory '%s'\n",
1230                rn, cacheBaseDir);
1231
1232     if (chmod(cacheBaseDir, 0700)) {            /* force it to be 700 */
1233         printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n",
1234                rn, cacheBaseDir);
1235         return (-1);
1236     }
1237     cdirp = opendir(cacheBaseDir);
1238     if (cdirp == (DIR *)0) {
1239         printf("%s: Can't open AFS cache directory, '%s'.\n",
1240                rn, cacheBaseDir);
1241         return(-1);
1242     }
1243
1244     /*
1245      * Scan the directory entries, remembering data cache file inodes and the existance
1246      * of other important residents.  Delete all files that don't belong here.
1247      */
1248     *vFilesFound = 0;
1249     sprintf(fullpn_FileToDelete, "%s/", cacheBaseDir);
1250     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
1251
1252     for (currp = readdir(cdirp); currp; currp = readdir(cdirp))
1253         {
1254         if (afsd_debug) {
1255             printf("%s: Current directory entry:\n",
1256                    rn);
1257             printf("\tinode=%d, reclen=%d, name='%s'\n",
1258                    currp->d_ino, currp->d_reclen, currp->d_name);
1259         }
1260
1261         /*
1262          * Guess current entry is for a data cache file.
1263          */
1264         vFileNum = GetVFileNumber(currp->d_name);
1265         if (vFileNum >= 0) {
1266             /*
1267              * Found a valid data cache filename.  Remember this file's name
1268              * and bump the number of files found.
1269              */
1270             pathname_for_V[vFileNum] = afs_osi_Alloc(strlen(currp->d_name) +
1271                                                      strlen(cacheBaseDir) + 2);
1272             usr_assert(pathname_for_V[vFileNum] != NULL);
1273             sprintf(pathname_for_V[vFileNum], "%s/%s",
1274                     cacheBaseDir, currp->d_name);
1275             (*vFilesFound)++;
1276         }
1277         else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
1278             /*
1279              * Found the file holding the dcache entries.
1280              */
1281             missing_DCacheFile = 0;
1282         }
1283         else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
1284             /*
1285              * Found the file holding the volume info.
1286              */
1287             missing_VolInfoFile = 0;
1288         }
1289         else  if ((strcmp(currp->d_name,          ".") == 0) ||
1290                   (strcmp(currp->d_name,         "..") == 0) ||
1291                   (strcmp(currp->d_name, "lost+found") == 0)) {
1292             /*
1293              * Don't do anything - this file is legit, and is to be left alone.
1294              */
1295         }
1296         else {
1297             /*
1298              * This file doesn't belong in the cache.  Nuke it.
1299              */
1300             sprintf(fileToDelete, "%s", currp->d_name);
1301             if (afsd_verbose)
1302                 printf("%s: Deleting '%s'\n",
1303                        rn, fullpn_FileToDelete);
1304             if (unlink(fullpn_FileToDelete)) {
1305                 printf("%s: Can't unlink '%s', errno is %d\n",
1306                        rn, fullpn_FileToDelete, errno);
1307             }
1308         }
1309     }
1310
1311     /*
1312      * Create all the cache files that are missing.
1313      */
1314     if (missing_DCacheFile) {
1315         if (afsd_verbose)
1316             printf("%s: Creating '%s'\n",
1317                    rn, fullpn_DCacheFile);
1318         if (CreateCacheFile(fullpn_DCacheFile))
1319             printf("%s: Can't create '%s'\n",
1320                    rn, fullpn_DCacheFile);
1321     }
1322     if (missing_VolInfoFile) {
1323         if (afsd_verbose)
1324             printf("%s: Creating '%s'\n",
1325                    rn, fullpn_VolInfoFile);
1326         if (CreateCacheFile(fullpn_VolInfoFile))
1327             printf("%s: Can't create '%s'\n",
1328                    rn, fullpn_VolInfoFile);
1329     }
1330
1331     if (*vFilesFound < cacheFiles) {
1332         /*
1333          * We came up short on the number of data cache files found.  Scan through the inode
1334          * list and create all missing files.
1335          */
1336         for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
1337             if (pathname_for_V[vFileNum] == (AFSD_INO_T)0) {
1338                 sprintf(vFileNumber, "%d", vFileNum);
1339                 if (afsd_verbose)
1340                     printf("%s: Creating '%s'\n",
1341                            rn, fullpn_VFile);
1342                 if (CreateCacheFile(fullpn_VFile))
1343                     printf("%s: Can't create '%s'\n",
1344                            rn, fullpn_VFile);
1345             }
1346     }
1347
1348     /*
1349      * Close the directory, return success.
1350      */
1351     if (afsd_debug)
1352         printf("%s: Closing cache directory.\n",
1353                rn);
1354     closedir(cdirp);
1355     return(0);
1356 }
1357
1358 static ConfigCell(register struct afsconf_cell *aci, char *arock, struct afsconf_dir *adir)
1359 {
1360     register int isHomeCell;
1361     register int i;
1362     afs_int32 cellFlags;
1363     afs_int32 hosts[MAXHOSTSPERCELL];
1364
1365     /* figure out if this is the home cell */
1366     isHomeCell = (strcmp(aci->name, afs_LclCellName) == 0);
1367     if (isHomeCell) {
1368         lookingForHomeCell = 0;
1369         cellFlags = 1;      /* home cell, suid is ok */
1370     }
1371     else {
1372         cellFlags = 2;      /* not home, suid is forbidden */
1373     }
1374
1375     /* build address list */
1376     for(i=0;i<MAXHOSTSPERCELL;i++)
1377         memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
1378
1379     if (aci->linkedCell) cellFlags |= 4; /* Flag that linkedCell arg exists,
1380                                             for upwards compatibility */
1381
1382     /* configure one cell */
1383     call_syscall(AFSCALL_CALL, AFSOP_ADDCELL2,
1384              (long)hosts,               /* server addresses */
1385              (long)aci->name,           /* cell name */
1386              (long)cellFlags,           /* is this the home cell? */
1387              (long)aci->linkedCell);    /* Linked cell, if any */
1388     return 0;
1389 }
1390
1391 /*
1392  * Set the UDP port number RX uses for UDP datagrams
1393  */
1394 void uafs_SetRxPort(int port)
1395 {
1396     usr_assert(usr_rx_port == 0);
1397     usr_rx_port = port;
1398 }
1399
1400
1401 /*
1402  * Initialize the user space client.
1403  */
1404 void uafs_Init(
1405     char *rn,
1406     char *mountDirParam,
1407     char *confDirParam,
1408     char *cacheBaseDirParam,
1409     int cacheBlocksParam,
1410     int cacheFilesParam,
1411     int cacheStatEntriesParam,
1412     int dCacheSizeParam,
1413     int vCacheSizeParam,
1414     int chunkSizeParam,
1415     int closeSynchParam,
1416     int debugParam,
1417     int nDaemonsParam,
1418     int cacheFlagsParam,
1419     char *logFile)
1420 {
1421     int st;
1422     struct usr_proc *procp;
1423     struct usr_ucred *ucredp;
1424     int i;
1425     int rc;
1426     int currVFile;                  /* Current AFS cache file number */
1427     int lookupResult;               /* Result of GetLocalCellName() */
1428     int cacheIteration;             /* cache verification loop counter */
1429     int vFilesFound;                /* Num data cache files found in sweep */
1430     FILE *logfd;
1431     afs_int32 vfs1_type = -1;
1432     struct afs_ioctl iob;
1433     char tbuffer[1024];
1434     char *p;
1435     char lastchar;
1436     afs_int32 buffer[MAXIPADDRS];
1437     afs_int32 maskbuffer[MAXIPADDRS];
1438     afs_int32 mtubuffer[MAXIPADDRS];
1439
1440     /*
1441      * Use the thread specific data to implement the user structure
1442      */
1443     usr_keycreate(&afs_global_u_key, free);
1444
1445     /*
1446      * Initialize the global ucred structure
1447      */
1448     afs_global_ucredp = (struct usr_ucred *)
1449                         afs_osi_Alloc(sizeof(struct usr_ucred));
1450     usr_assert(afs_global_ucredp != NULL);
1451     afs_global_ucredp->cr_ref = 1;
1452     afs_global_ucredp->cr_uid = geteuid();
1453     afs_global_ucredp->cr_gid = getegid();
1454     afs_global_ucredp->cr_ruid = getuid();
1455     afs_global_ucredp->cr_rgid = getgid();
1456     afs_global_ucredp->cr_suid = afs_global_ucredp->cr_ruid;
1457     afs_global_ucredp->cr_sgid = afs_global_ucredp->cr_rgid;
1458     st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1459     usr_assert(st >= 0);
1460     afs_global_ucredp->cr_ngroups = (unsigned long)st;
1461     for (i = st ; i < NGROUPS ; i++) {
1462         afs_global_ucredp->cr_groups[i] = NOGROUP;
1463     }
1464
1465     /*
1466      * Initialize the global process structure
1467      */
1468     afs_global_procp = (struct usr_proc *)
1469                        afs_osi_Alloc(sizeof(struct usr_proc));
1470     usr_assert(afs_global_procp != NULL);
1471     afs_global_procp->p_pid = getpid();
1472     afs_global_procp->p_ppid = (pid_t)1;
1473     afs_global_procp->p_ucred = afs_global_ucredp;
1474
1475     /*
1476      * Initialize the AFS mount point, default is '/afs'.
1477      * Strip duplicate/trailing slashes from mount point string.
1478      * afs_mountDirLen is set to strlen(afs_mountDir).
1479      */
1480     if (mountDirParam) {
1481         sprintf(tbuffer, "%s", mountDirParam);
1482     } else {
1483         sprintf(tbuffer, "afs");
1484     }
1485     afs_mountDir[0] = '/';
1486     afs_mountDirLen = 1;
1487     for (lastchar = '/', p = &tbuffer[0] ; *p != '\0' ; p++) {
1488         if (lastchar != '/' || *p != '/') {
1489             afs_mountDir[afs_mountDirLen++] = lastchar = *p;
1490         }
1491     }
1492     if (lastchar == '/' && afs_mountDirLen > 1)
1493         afs_mountDirLen--;
1494     afs_mountDir[afs_mountDirLen] = '\0';
1495     usr_assert(afs_mountDirLen > 1);
1496
1497     /*
1498      * Initialize cache parameters using the input arguments
1499      */
1500
1501     cacheBlocks = cacheBlocksParam;
1502     if (cacheFilesParam != 0) {
1503         cacheFiles = cacheFilesParam;
1504     } else {
1505         cacheFiles = cacheBlocks/10;
1506     }
1507     if (cacheStatEntriesParam != 0) {
1508         cacheStatEntries = cacheStatEntriesParam;
1509     }
1510     strcpy(cacheBaseDir, cacheBaseDirParam);
1511     if (nDaemons != 0) {
1512         nDaemons = nDaemonsParam;
1513     } else {
1514         nDaemons = 3;
1515     }
1516     afsd_verbose = debugParam;
1517     afsd_debug = debugParam;
1518     chunkSize = chunkSizeParam;
1519     if (dCacheSizeParam != 0) {
1520         dCacheSize = dCacheSizeParam;
1521     } else {
1522         dCacheSize = cacheFiles/2;
1523     }
1524     if (vCacheSizeParam != 0) {
1525         vCacheSize = vCacheSizeParam;
1526     }
1527     strcpy(confDir, confDirParam);
1528     afsd_CloseSynch = closeSynchParam;
1529     if (cacheFlagsParam >= 0) {
1530         cacheFlags = cacheFlagsParam;
1531     }
1532     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1533          cacheFiles = dCacheSize; 
1534     }
1535
1536     sprintf(fullpn_CacheInfo,  "%s/%s", confDir, CACHEINFOFILE);
1537     if (logFile == NULL) {
1538         sprintf(fullpn_AFSLogFile,  "%s/%s", confDir, AFSLOGFILE);
1539     } else {
1540         strcpy(fullpn_AFSLogFile, logFile);
1541     }
1542
1543     printf("\n%s: Initializing user space AFS client\n\n", rn);
1544     printf("    mountDir:           %s\n", afs_mountDir);
1545     printf("    confDir:            %s\n", confDir);
1546     printf("    cacheBaseDir:       %s\n", cacheBaseDir);
1547     printf("    cacheBlocks:        %d\n", cacheBlocks);
1548     printf("    cacheFiles:         %d\n", cacheFiles);
1549     printf("    cacheStatEntries:   %d\n", cacheStatEntries);
1550     printf("    dCacheSize:         %d\n", dCacheSize);
1551     printf("    vCacheSize:         %d\n", vCacheSize);
1552     printf("    chunkSize:          %d\n", chunkSize);
1553     printf("    afsd_CloseSynch:    %d\n", afsd_CloseSynch);
1554     printf("    afsd_debug/verbose: %d/%d\n", afsd_debug, afsd_verbose);
1555     printf("    nDaemons:           %d\n", nDaemons);
1556     printf("    cacheFlags:         %d\n", cacheFlags);
1557     printf("    logFile:            %s\n", fullpn_AFSLogFile);
1558     printf("\n");
1559     fflush(stdout);
1560
1561     /*
1562      * Initialize the AFS client
1563      */
1564     osi_Init();
1565
1566     /*
1567      * Pull out all the configuration info for the workstation's AFS cache and
1568      * the cellular community we're willing to let our users see.
1569      */
1570     afs_cdir = afsconf_Open(confDir);
1571     if (!afs_cdir) {
1572         printf("afsd: some file missing or bad in %s\n", confDir);
1573         exit(1);
1574     }
1575
1576     lookupResult = afsconf_GetLocalCell(afs_cdir, afs_LclCellName,
1577                                         sizeof(afs_LclCellName));
1578     if (lookupResult) {
1579         printf("%s: Can't get my home cell name!  [Error is %d]\n",
1580                rn, lookupResult);
1581     }
1582     else {
1583         if (afsd_verbose)
1584             printf("%s: My home cell is '%s'\n",
1585                    rn, afs_LclCellName);
1586     }
1587
1588     if ((logfd = fopen(fullpn_AFSLogFile,"r+")) == 0) {
1589         if (afsd_verbose)  printf("%s: Creating '%s'\n",  rn, fullpn_AFSLogFile);
1590         if (CreateCacheFile(fullpn_AFSLogFile)) {
1591             printf("%s: Can't create '%s' (You may want to use the -logfile option)\n",  rn, fullpn_AFSLogFile);
1592             exit(1);
1593         }
1594     } else
1595         fclose(logfd);
1596
1597     /*
1598      * Create and zero the pathname table for the desired cache files.
1599      */
1600     pathname_for_V = (char **)afs_osi_Alloc(cacheFiles * sizeof(char *));
1601     if (pathname_for_V == NULL) {
1602         printf("%s: malloc() failed for cache file table with %d entries.\n",
1603                rn, cacheFiles);
1604         exit(1);
1605     }
1606     memset(pathname_for_V, 0, (cacheFiles * sizeof(char *)));
1607     if (afsd_debug)
1608         printf("%s: %d pathname_for_V entries at 0x%x, %d bytes\n",
1609                rn, cacheFiles, pathname_for_V, (cacheFiles * sizeof(AFSD_INO_T)));
1610
1611     /*
1612      * Set up all the pathnames we'll need for later.
1613      */
1614     sprintf(fullpn_DCacheFile,  "%s/%s", cacheBaseDir, DCACHEFILE);
1615     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
1616     sprintf(fullpn_VFile,       "%s/V",  cacheBaseDir);
1617     vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
1618
1619     /*
1620      * Start the RX listener.
1621      */
1622     if (afsd_debug)
1623          printf("%s: Calling AFSOP_RXLISTENER_DAEMON\n", rn);
1624     fork_syscall(AFSCALL_CALL, AFSOP_RXLISTENER_DAEMON, FALSE);
1625
1626     /*
1627      * Start the RX event handler.
1628      */
1629     if (afsd_debug)
1630          printf("%s: Calling AFSOP_RXEVENT_DAEMON\n", rn);
1631     fork_syscall(AFSCALL_CALL, AFSOP_RXEVENT_DAEMON, FALSE);
1632
1633     /*
1634      * Set up all the kernel processes needed for AFS.
1635      */
1636
1637     /* initialize AFS callback interface */
1638     {
1639       /* parse multihomed address files */
1640       char reason[1024];
1641       st=parseNetFiles(buffer,maskbuffer,mtubuffer,MAXIPADDRS,reason,
1642                     AFSDIR_CLIENT_NETINFO_FILEPATH,
1643                     AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
1644       if(st>0) 
1645         call_syscall(AFSCALL_CALL, AFSOP_ADVISEADDR, st, (long) (&buffer[0]), 
1646                      (long) (&maskbuffer[0]), (long) (&mtubuffer[0]));
1647       else {
1648         printf("ADVISEADDR: Error in specifying interface addresses:%s\n",reason);
1649         exit(1);
1650       }
1651     }
1652
1653     if (afsd_verbose)
1654         printf("%s: Forking rx callback listener.\n", rn);
1655     /* Child */
1656     if (preallocs < cacheStatEntries+50)
1657         preallocs = cacheStatEntries+50;
1658     fork_syscall(AFSCALL_CALL, AFSOP_START_RXCALLBACK, preallocs);
1659
1660     if (afsd_verbose)
1661         printf("%s: Forking AFS daemon.\n", rn);
1662     fork_syscall(AFSCALL_CALL, AFSOP_START_AFS);
1663
1664     if (afsd_verbose)
1665         printf("%s: Forking check server daemon.\n", rn);
1666     fork_syscall(AFSCALL_CALL, AFSOP_START_CS);
1667
1668     if (afsd_verbose)
1669         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
1670     for (i=0;i<nDaemons;i++) {
1671         fork_syscall(AFSCALL_CALL, AFSOP_START_BKG);
1672     }
1673
1674     /*
1675      * Tell the kernel about each cell in the configuration.
1676      */
1677     lookingForHomeCell = 1;
1678
1679     afsconf_CellApply(afs_cdir, ConfigCell, NULL);
1680
1681     /*
1682      * If we're still looking for the home cell after the whole cell
1683      * configuration database has been parsed, there's something wrong.
1684      */
1685     if (lookingForHomeCell) {
1686         printf("%s: Can't find home cell '%s' in cell database!\n",
1687                rn, afs_LclCellName);
1688     }
1689
1690     if (afsd_verbose)
1691         printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n",
1692                rn, rootVolume);
1693     call_syscall(AFSCALL_CALL, AFSOP_ROOTVOLUME, (long)rootVolume, 0, 0, 0);
1694
1695     /*
1696      * Tell the kernel some basic information about the workstation's cache.
1697      */
1698     if (afsd_verbose)
1699         printf("%s: Calling AFSOP_CACHEINIT: %d stat cache entries,"
1700                " %d optimum cache files, %d blocks in the cache,"
1701                " flags = 0x%x, dcache entries %d\n",
1702                rn, cacheStatEntries, cacheFiles, cacheBlocks, cacheFlags,
1703                dCacheSize);
1704     memset(&cparams, 0, sizeof(cparams));
1705     cparams.cacheScaches = cacheStatEntries;
1706     cparams.cacheFiles = cacheFiles;
1707     cparams.cacheBlocks = cacheBlocks;
1708     cparams.cacheDcaches = dCacheSize;
1709     cparams.cacheVolumes = vCacheSize;
1710     cparams.chunkSize = chunkSize;
1711     cparams.setTimeFlag = FALSE;
1712     cparams.memCacheFlag = cacheFlags;
1713     call_syscall(AFSCALL_CALL, AFSOP_CACHEINIT, (long)&cparams, 0, 0, 0);
1714     if (afsd_CloseSynch) 
1715       call_syscall(AFSCALL_CALL, AFSOP_CLOSEWAIT, 0, 0, 0, 0);
1716
1717     /*
1718      * Sweep the workstation AFS cache directory, remembering the inodes of
1719      * valid files and deleting extraneous files.  Keep sweeping until we
1720      * have the right number of data cache files or we've swept too many
1721      * times.
1722      */
1723     if (afsd_verbose)
1724         printf("%s: Sweeping workstation's AFS cache directory.\n",
1725                rn);
1726     cacheIteration = 0;
1727     /* Memory-cache based system doesn't need any of this */
1728     if(!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
1729         do {
1730             cacheIteration++;
1731             if (SweepAFSCache(&vFilesFound)) {
1732                 printf("%s: Error on sweep %d of workstation AFS cache \
1733                        directory.\n", rn, cacheIteration);
1734                 exit(1);
1735             }
1736             if (afsd_verbose)
1737                 printf("%s: %d out of %d data cache files found in sweep %d.\n",
1738                        rn, vFilesFound, cacheFiles, cacheIteration);
1739         } while ((vFilesFound < cacheFiles) &&
1740                  (cacheIteration < MAX_CACHE_LOOPS));
1741     } else if(afsd_verbose)
1742         printf("%s: Using memory cache, not swept\n", rn);
1743
1744     /*
1745      * Pass the kernel the name of the workstation cache file holding the 
1746      * dcache entries.
1747      */
1748     if (afsd_debug)
1749         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n",
1750                rn, fullpn_DCacheFile);
1751     /* once again, meaningless for a memory-based cache. */
1752     if(!(cacheFlags & AFSCALL_INIT_MEMCACHE))
1753         call_syscall(AFSCALL_CALL, AFSOP_CACHEINFO, (long)fullpn_DCacheFile,
1754                      0, 0, 0);
1755
1756
1757     /*
1758      * Pass the kernel the name of the workstation cache file holding the
1759      * volume information.
1760      */
1761     if (afsd_debug)
1762         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n",
1763                rn, fullpn_VolInfoFile);
1764     call_syscall(AFSCALL_CALL, AFSOP_VOLUMEINFO,(long)fullpn_VolInfoFile,
1765                  0, 0, 0);
1766
1767     /*
1768      * Pass the kernel the name of the afs logging file holding the volume
1769      * information.
1770      */
1771     if (afsd_debug)
1772         printf("%s: Calling AFSOP_AFSLOG: volume info file is '%s'\n",
1773                rn, fullpn_AFSLogFile);
1774     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... nor this ... */
1775         call_syscall(AFSCALL_CALL, AFSOP_AFSLOG,(long)fullpn_AFSLogFile,
1776                      0, 0, 0);
1777
1778     /*
1779      * Give the kernel the names of the AFS files cached on the workstation's
1780      * disk.
1781      */
1782     if (afsd_debug)
1783         printf("%s: Calling AFSOP_CACHEFILES for each of the %d files in '%s'\n",
1784                rn, cacheFiles, cacheBaseDir);
1785     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... and again ... */
1786         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
1787             call_syscall(AFSCALL_CALL, AFSOP_CACHEFILE,
1788                          (long)pathname_for_V[currVFile], 0, 0, 0);
1789         } /*end for*/
1790
1791 #ifndef NETSCAPE_NSAPI
1792     /*
1793      * Copy our tokens from the kernel to the user space client
1794      */
1795     for(i = 0 ; i < 200 ; i++) {
1796         /*
1797          * Get the i'th token from the kernel
1798          */
1799         memset((void *)&tbuffer[0], 0, sizeof(tbuffer));
1800         memcpy((void *)&tbuffer[0], (void *)&i, sizeof(int));
1801         iob.in = tbuffer;
1802         iob.in_size = sizeof(int);
1803         iob.out = tbuffer;
1804         iob.out_size = sizeof(tbuffer);
1805
1806 #if defined(AFS_USR_SUN5_ENV) || defined(AFS_USR_OSF_ENV) || defined(AFS_USR_HPUX_ENV) || defined(AFS_USR_LINUX22_ENV) || defined(AFS_USR_DARWIN_ENV) || defined(AFS_USR_FBSD_ENV)
1807         rc = syscall(AFS_SYSCALL, AFSCALL_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1808 #elif defined(AFS_USR_SGI_ENV)
1809         rc = syscall(AFS_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1810 #else /* AFS_USR_AIX_ENV */
1811         rc = lpioctl(0, _VICEIOCTL(8), &iob, 0);
1812 #endif
1813         if (rc < 0) {
1814             usr_assert(errno == EDOM);
1815             break;
1816         }
1817
1818         /*
1819          * Now pass the token into the user space kernel
1820          */
1821         rc = uafs_SetTokens(tbuffer, iob.out_size);
1822         usr_assert(rc == 0);
1823     }
1824 #endif /* !NETSCAPE_NSAPI */
1825
1826     /*
1827      * All the necessary info has been passed into the kernel to run an AFS
1828      * system.  Give the kernel our go-ahead.
1829      */
1830     if (afsd_debug)
1831          printf("%s: Calling AFSOP_GO\n", rn);
1832      call_syscall(AFSCALL_CALL, AFSOP_GO, FALSE, 0, 0, 0);
1833
1834     /*
1835      * At this point, we have finished passing the kernel all the info 
1836      * it needs to set up the AFS.  Mount the AFS root.
1837      */
1838     printf("%s: All AFS daemons started.\n", rn);
1839
1840     if (afsd_verbose)
1841         printf("%s: Forking trunc-cache daemon.\n", rn);
1842     fork_syscall(AFSCALL_CALL, AFSOP_START_TRUNCDAEMON);
1843
1844     /*
1845      * Mount the AFS filesystem
1846      */
1847     AFS_GLOCK();
1848     rc = afs_mount(&afs_RootVfs, NULL, NULL);
1849     usr_assert(rc == 0);
1850     rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1851     usr_assert(rc == 0);
1852     AFS_GUNLOCK();
1853
1854     /*
1855      * initialize the current directory to the AFS root
1856      */
1857     afs_CurrentDir = afs_RootVnode;
1858     VN_HOLD(afs_CurrentDir);
1859
1860     return;
1861 }
1862
1863 void uafs_Shutdown(void)
1864 {
1865     int rc;
1866
1867     printf("\n");
1868
1869     AFS_GLOCK();
1870     VN_RELE(afs_CurrentDir);
1871     rc = afs_unmount(&afs_RootVfs);
1872     usr_assert(rc == 0);
1873     AFS_GUNLOCK();
1874
1875     printf("\n");
1876 }
1877
1878 /*
1879  * Donate the current thread to the RX server pool.
1880  */
1881 void uafs_RxServerProc(void)
1882 {
1883     osi_socket sock;
1884     int threadID;
1885     struct rx_call *newcall = NULL;
1886
1887     rxi_MorePackets(2); /* alloc more packets */
1888     threadID = rxi_availProcs++;
1889
1890     while(1) {
1891         sock = OSI_NULLSOCKET;
1892         rxi_ServerProc(threadID, newcall, &sock);
1893         if (sock == OSI_NULLSOCKET) {
1894             break;
1895         }
1896         newcall = NULL;
1897         threadID = -1;
1898         rxi_ListenerProc(sock, &threadID, &newcall);
1899         /* assert(threadID != -1); */
1900         /* assert(newcall != NULL); */
1901     }
1902 }
1903
1904 struct syscallThreadArgs {
1905     long syscall;
1906     long afscall;
1907     long param1;
1908     long param2;
1909     long param3;
1910     long param4;
1911 };
1912
1913 #ifdef NETSCAPE_NSAPI
1914 void syscallThread(void *argp)
1915 #else /* NETSCAPE_NSAPI */
1916 void *syscallThread(void *argp)
1917 #endif /* NETSCAPE_NSAPI */
1918 {
1919     int i;
1920     struct usr_ucred *crp;
1921     struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1922
1923     /*
1924      * AFS daemons run authenticated
1925      */
1926     u.u_viceid = getuid();
1927     crp = u.u_cred;
1928     crp->cr_uid = getuid();
1929     crp->cr_ruid = getuid();
1930     crp->cr_suid = getuid();
1931     crp->cr_groups[0] = getgid();
1932     crp->cr_ngroups = 1;
1933     for (i = 1 ; i < NGROUPS ; i++) {
1934         crp->cr_groups[i] = NOGROUP;
1935     }
1936
1937     call_syscall(sysArgsP->syscall, sysArgsP->afscall,
1938                  sysArgsP->param1, sysArgsP->param2,
1939                  sysArgsP->param3, sysArgsP->param4);
1940
1941     afs_osi_Free(argp, -1);
1942 }
1943
1944 fork_syscall(syscall, afscall, param1, param2, param3, param4)
1945 long syscall, afscall, param1, param2, param3, param4;
1946 {
1947     usr_thread_t tid;
1948     struct syscallThreadArgs *sysArgsP;
1949
1950     sysArgsP = (struct syscallThreadArgs *)
1951                afs_osi_Alloc(sizeof(struct syscallThreadArgs));
1952     usr_assert(sysArgsP != NULL);
1953     sysArgsP->syscall = syscall;
1954     sysArgsP->afscall = afscall;
1955     sysArgsP->param1 = param1;
1956     sysArgsP->param2 = param2;
1957     sysArgsP->param3 = param3;
1958     sysArgsP->param4 = param4;
1959
1960     usr_thread_create(&tid, syscallThread, sysArgsP);
1961     usr_thread_detach(tid);
1962 }
1963
1964 call_syscall(syscall, afscall, param1, param2, param3, param4)
1965 long syscall, afscall, param1, param2, param3, param4;
1966 {
1967     int code = 0;
1968     struct a {
1969         long syscall;
1970         long afscall;
1971         long parm1;
1972         long parm2;
1973         long parm3;
1974         long parm4;
1975     } a;
1976
1977     a.syscall = syscall;
1978     a.afscall = afscall;
1979     a.parm1 = param1;
1980     a.parm2 = param2;
1981     a.parm3 = param3;
1982     a.parm4 = param4;
1983
1984     u.u_error = 0;
1985     u.u_ap = (char *)&a;
1986
1987     code = Afs_syscall();
1988     return code;
1989 }
1990
1991 int uafs_SetTokens(char *tbuffer, int tlen)
1992 {
1993     int rc;
1994     struct afs_ioctl iob;
1995     char outbuf[1024];
1996
1997     iob.in = tbuffer;
1998     iob.in_size = tlen;
1999     iob.out = &outbuf[0];
2000     iob.out_size = sizeof(outbuf);
2001     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
2002     if (rc != 0) {
2003         errno = rc;
2004         return -1;
2005     }
2006     return 0;
2007 }
2008
2009 int uafs_RPCStatsEnableProc(void)
2010 {
2011     int rc;
2012     struct afs_ioctl iob;
2013     afs_int32 flag;
2014
2015     flag = AFSCALL_RXSTATS_ENABLE;
2016     iob.in = (char *)&flag;
2017     iob.in_size = sizeof(afs_int32);
2018     iob.out = NULL;
2019     iob.out_size = 0;
2020     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2021     if (rc != 0) {
2022         errno = rc;
2023         return -1;
2024     }
2025     return rc;
2026 }
2027
2028 int uafs_RPCStatsDisableProc(void)
2029 {
2030     int rc;
2031     struct afs_ioctl iob;
2032     afs_int32 flag;
2033
2034     flag = AFSCALL_RXSTATS_DISABLE;
2035     iob.in = (char *)&flag;
2036     iob.in_size = sizeof(afs_int32);
2037     iob.out = NULL;
2038     iob.out_size = 0;
2039     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2040     if (rc != 0) {
2041         errno = rc;
2042         return -1;
2043     }
2044     return rc;
2045 }
2046
2047 int uafs_RPCStatsClearProc(void)
2048 {
2049     int rc;
2050     struct afs_ioctl iob;
2051     afs_int32 flag;
2052
2053     flag = AFSCALL_RXSTATS_CLEAR;
2054     iob.in = (char *)&flag;
2055     iob.in_size = sizeof(afs_int32);
2056     iob.out = NULL;
2057     iob.out_size = 0;
2058     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2059     if (rc != 0) {
2060         errno = rc;
2061         return -1;
2062     }
2063     return rc;
2064 }
2065
2066 int uafs_RPCStatsEnablePeer(void)
2067 {
2068     int rc;
2069     struct afs_ioctl iob;
2070     afs_int32 flag;
2071
2072     flag = AFSCALL_RXSTATS_ENABLE;
2073     iob.in = (char *)&flag;
2074     iob.in_size = sizeof(afs_int32);
2075     iob.out = NULL;
2076     iob.out_size = 0;
2077     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2078     if (rc != 0) {
2079         errno = rc;
2080         return -1;
2081     }
2082     return rc;
2083 }
2084
2085 int uafs_RPCStatsDisablePeer(void)
2086 {
2087     int rc;
2088     struct afs_ioctl iob;
2089     afs_int32 flag;
2090
2091     flag = AFSCALL_RXSTATS_DISABLE;
2092     iob.in = (char *)&flag;
2093     iob.in_size = sizeof(afs_int32);
2094     iob.out = NULL;
2095     iob.out_size = 0;
2096     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2097     if (rc != 0) {
2098         errno = rc;
2099         return -1;
2100     }
2101     return rc;
2102 }
2103
2104 int uafs_RPCStatsClearPeer(void)
2105 {
2106     int rc;
2107     struct afs_ioctl iob;
2108     afs_int32 flag;
2109
2110     flag = AFSCALL_RXSTATS_CLEAR;
2111     iob.in = (char *)&flag;
2112     iob.in_size = sizeof(afs_int32);
2113     iob.out = NULL;
2114     iob.out_size = 0;
2115     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2116     if (rc != 0) {
2117         errno = rc;
2118         return -1;
2119     }
2120     return rc;
2121 }
2122
2123 /*
2124  * Lookup a file or directory given its path.
2125  * Call VN_HOLD on the output vnode if successful.
2126  * Returns zero on success, error code on failure.
2127  *
2128  * Note: Caller must hold the AFS global lock.
2129  */
2130 int uafs_LookupName(
2131     char *path,
2132     struct usr_vnode *parentVp,
2133     struct usr_vnode **vpp,
2134     int follow,
2135     int no_eval_mtpt)
2136 {
2137     int code;
2138     int linkCount;
2139     struct usr_vnode *vp;
2140     struct usr_vnode *nextVp;
2141     struct usr_vnode *linkVp;
2142     char *tmpPath;
2143     char *pathP;
2144     char *nextPathP;
2145
2146     AFS_ASSERT_GLOCK();
2147
2148     /*
2149      * Absolute paths must start with the AFS mount point.
2150      */
2151     if (path[0] != '/') {
2152         vp = parentVp;
2153     } else {
2154         path = uafs_afsPathName(path);
2155         if (path == NULL) {
2156             return ENOENT;
2157         }
2158         vp = afs_RootVnode;
2159     }
2160
2161     /*
2162      * Loop through the path looking for the new directory
2163      */
2164     tmpPath = afs_osi_Alloc(strlen(path)+1);
2165     usr_assert(tmpPath != NULL);
2166     strcpy(tmpPath, path);
2167     VN_HOLD(vp);
2168     pathP = tmpPath;
2169     while (pathP != NULL && *pathP != '\0') {
2170         usr_assert(*pathP != '/');
2171
2172         /*
2173          * terminate the current component and skip over slashes
2174          */
2175         nextPathP = strchr(pathP, '/');
2176         if (nextPathP != NULL) {
2177             while (*nextPathP == '/') {
2178                 *(nextPathP++) = '\0';
2179             }
2180         }
2181
2182         /*
2183          * Don't call afs_lookup on non-directories
2184          */
2185         if (vp->v_type != VDIR) {
2186             VN_RELE(vp);
2187             afs_osi_Free(tmpPath, strlen(path)+1);
2188             return ENOTDIR;
2189         }
2190
2191         if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
2192             /*
2193              * The AFS root is its own parent
2194              */
2195             nextVp = afs_RootVnode;
2196         } else {
2197             /*
2198              * We need execute permission to search a directory
2199              */
2200             code = afs_access(vp, VEXEC, u.u_cred);
2201             if (code != 0) {
2202                 VN_RELE(vp);
2203                 afs_osi_Free(tmpPath, strlen(path)+1);
2204                 return code;
2205             }
2206
2207             /*
2208              * lookup the next component in the path, we can release the
2209              * subdirectory since we hold the global lock
2210              */
2211             nextVp = NULL;
2212 #ifdef AFS_WEB_ENHANCEMENTS
2213             if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
2214               code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
2215             else
2216               code = afs_lookup(vp, pathP, &nextVp, u.u_cred, AFS_LOOKUP_NOEVAL);
2217 #else
2218             code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
2219 #endif /* AFS_WEB_ENHANCEMENTS */
2220             if (code != 0) {
2221                 VN_RELE(vp);
2222                 afs_osi_Free(tmpPath, strlen(path)+1);
2223                 return code;
2224             }
2225         }
2226
2227         /*
2228          * Follow symbolic links for parent directories and
2229          * for leaves when the follow flag is set.
2230          */
2231         if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
2232             linkCount = 0;
2233             while(nextVp->v_type == VLNK) {
2234                 if (++linkCount > MAX_OSI_LINKS) {
2235                     VN_RELE(vp);
2236                     VN_RELE(nextVp);
2237                     afs_osi_Free(tmpPath, strlen(path)+1);
2238                     return code;
2239                 }
2240                 code = uafs_LookupLink(nextVp, vp, &linkVp);
2241                 if (code) {
2242                     VN_RELE(vp);
2243                     VN_RELE(nextVp);
2244                     afs_osi_Free(tmpPath, strlen(path)+1);
2245                     return code;
2246                 }
2247                 VN_RELE(nextVp);
2248                 nextVp = linkVp;
2249             }
2250         }
2251
2252         VN_RELE(vp);
2253         vp = nextVp;
2254         pathP = nextPathP;
2255     }
2256
2257     /*
2258      * Special case, nextPathP is non-null if pathname ends in slash
2259      */
2260     if (nextPathP != NULL && vp->v_type != VDIR) {
2261         VN_RELE(vp);
2262         afs_osi_Free(tmpPath, strlen(path)+1);
2263         return ENOTDIR;
2264     }
2265
2266     afs_osi_Free(tmpPath, strlen(path)+1);
2267     *vpp = vp;
2268     return 0;
2269 }
2270
2271 /*
2272  * Lookup the target of a symbolic link
2273  * Call VN_HOLD on the output vnode if successful.
2274  * Returns zero on success, error code on failure.
2275  *
2276  * Note: Caller must hold the AFS global lock.
2277  */
2278 int uafs_LookupLink(
2279     struct usr_vnode *vp,
2280     struct usr_vnode *parentVp,
2281     struct usr_vnode **vpp)
2282 {
2283     int code;
2284     int len;
2285     char *pathP;
2286     struct usr_vnode *linkVp;
2287     struct usr_uio uio;
2288     struct iovec iov[1];
2289
2290     AFS_ASSERT_GLOCK();
2291
2292     pathP = afs_osi_Alloc(MAX_OSI_PATH+1);
2293     usr_assert(pathP != NULL);
2294
2295     /*
2296      * set up the uio buffer
2297      */
2298     iov[0].iov_base = pathP;
2299     iov[0].iov_len = MAX_OSI_PATH+1;
2300     uio.uio_iov = &iov[0];
2301     uio.uio_iovcnt = 1;
2302     uio.uio_offset = 0;
2303     uio.uio_segflg = 0;
2304     uio.uio_fmode = FREAD;
2305     uio.uio_resid = MAX_OSI_PATH+1;
2306
2307     /*
2308      * Read the link data
2309      */
2310     code = afs_readlink(vp, &uio, u.u_cred);
2311     if (code) {
2312         afs_osi_Free(pathP, MAX_OSI_PATH+1);
2313         return code;
2314     }
2315     len = MAX_OSI_PATH + 1 - uio.uio_resid;
2316     pathP[len] = '\0';
2317
2318     /*
2319      * Find the target of the symbolic link
2320      */
2321     code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
2322     if (code) {
2323         afs_osi_Free(pathP, MAX_OSI_PATH+1);
2324         return code;
2325     }
2326
2327     afs_osi_Free(pathP, MAX_OSI_PATH+1);
2328     *vpp = linkVp;
2329     return 0;
2330 }
2331
2332 /*
2333  * Lookup the parent of a file or directory given its path
2334  * Call VN_HOLD on the output vnode if successful.
2335  * Returns zero on success, error code on failure.
2336  *
2337  * Note: Caller must hold the AFS global lock.
2338  */
2339 int uafs_LookupParent(
2340     char *path,
2341     struct usr_vnode **vpp)
2342 {
2343     int len;
2344     int code;
2345     char *pathP;
2346     struct usr_vnode *parentP;
2347
2348     AFS_ASSERT_GLOCK();
2349
2350     /*
2351      * Absolute path names must start with the AFS mount point.
2352      */
2353     if (*path == '/') {
2354         pathP = uafs_afsPathName(path);
2355         if (pathP == NULL) {
2356             return ENOENT;
2357         }
2358     }
2359
2360     /*
2361      * Find the length of the parent path
2362      */
2363     len = strlen(path);
2364     while(len > 0 && path[len-1] == '/') {
2365         len--;
2366     }
2367     if (len == 0) {
2368         return EINVAL;
2369     }
2370     while(len > 0 && path[len-1] != '/') {
2371         len--;
2372     }
2373     if (len == 0) {
2374         return EINVAL;
2375     }
2376
2377     pathP = afs_osi_Alloc(len);
2378     usr_assert(pathP != NULL);
2379     memcpy(pathP, path, len-1);
2380     pathP[len-1] = '\0';
2381
2382     /*
2383      * look up the parent
2384      */
2385     code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
2386     afs_osi_Free(pathP, len);
2387     if (code != 0) {
2388         return code;
2389     }
2390     if (parentP->v_type != VDIR) {
2391         VN_RELE(parentP);
2392         return ENOTDIR;
2393     }
2394
2395     *vpp = parentP;
2396     return 0;
2397 }
2398
2399 /*
2400  * Return a pointer to the first character in the last component
2401  * of a pathname
2402  */
2403 char *uafs_LastPath(char *path)
2404 {
2405     int len;
2406
2407     len = strlen(path);
2408     while (len > 0 && path[len-1] == '/') {
2409         len--;
2410     }
2411     while (len > 0 && path[len-1] != '/') {
2412         len--;
2413     }
2414     if (len == 0) {
2415         return NULL;
2416     }
2417     return path + len;
2418 }
2419
2420 /*
2421  * Set the working directory.
2422  */
2423 int uafs_chdir(char *path)
2424 {
2425     int retval;
2426     AFS_GLOCK();
2427     retval = uafs_chdir_r(path);
2428     AFS_GUNLOCK();
2429     return retval;
2430 }
2431
2432 int uafs_chdir_r(char *path)
2433 {
2434     int code;
2435     struct vnode *dirP;
2436
2437     code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
2438     if (code != 0) {
2439         errno = code;
2440         return -1;
2441     }
2442     if (dirP->v_type != VDIR) {
2443         VN_RELE(dirP);
2444         errno = ENOTDIR;
2445         return -1;
2446     }
2447     VN_RELE(afs_CurrentDir);
2448     afs_CurrentDir = dirP;
2449     return 0;
2450 }
2451
2452 /*
2453  * Create a directory.
2454  */
2455 int uafs_mkdir(char *path, int mode)
2456 {
2457     int retval;
2458     AFS_GLOCK();
2459     retval = uafs_mkdir_r(path, mode);
2460     AFS_GUNLOCK();
2461     return retval;
2462 }
2463
2464 int uafs_mkdir_r(char *path, int mode)
2465 {
2466     int code;
2467     char *nameP;
2468     struct vnode *parentP;
2469     struct vnode *dirP;
2470     struct usr_vattr attrs;
2471
2472     if (uafs_IsRoot(path)) {
2473         return EACCES;
2474     }
2475
2476     /*
2477      * Look up the parent directory.
2478      */
2479     nameP = uafs_LastPath(path);
2480     if (nameP != NULL) {
2481         code = uafs_LookupParent(path, &parentP);
2482         if (code != 0) {
2483             errno = code;
2484             return -1;
2485         }
2486     } else {
2487         parentP = afs_CurrentDir;
2488         nameP = path;
2489         VN_HOLD(parentP);
2490     }
2491
2492     /*
2493      * Make sure the directory has at least one character
2494      */
2495     if (*nameP == '\0') {
2496         VN_RELE(parentP);
2497         errno = EINVAL;
2498         return -1;
2499     }
2500
2501     /*
2502      * Create the directory
2503      */
2504     usr_vattr_null(&attrs);
2505     attrs.va_type = VREG;
2506     attrs.va_mode = mode;
2507     attrs.va_uid = u.u_cred->cr_uid;
2508     attrs.va_gid = u.u_cred->cr_gid;
2509     dirP = NULL;
2510     code = afs_mkdir(parentP, nameP, &attrs, &dirP, u.u_cred);
2511     VN_RELE(parentP);
2512     if (code != 0) {
2513         errno = code;
2514         return -1;
2515     }
2516     VN_RELE(dirP);
2517     return 0;
2518 }
2519
2520 /*
2521  * Return 1 if path is the AFS root, otherwise return 0
2522  */
2523 int uafs_IsRoot(char *path)
2524 {
2525     while(*path == '/' && *(path+1) == '/') {
2526         path++;
2527     }
2528     if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2529         return 0;
2530     }
2531     path += afs_mountDirLen;
2532     while (*path == '/') {
2533         path++;
2534     }
2535     if (*path != '\0') {
2536         return 0;
2537     }
2538     return 1;
2539 }
2540
2541 /*
2542  * Open a file
2543  * Note: file name may not end in a slash.
2544  */
2545 int uafs_open(char *path, int flags, int mode)
2546 {
2547     int retval;
2548     AFS_GLOCK();
2549     retval = uafs_open_r(path, flags, mode);
2550     AFS_GUNLOCK();
2551     return retval;
2552 }
2553
2554 int uafs_open_r(char *path, int flags, int mode)
2555 {
2556     int fd;
2557     int code;
2558     int openFlags;
2559     int fileMode;
2560     struct usr_vnode *fileP;
2561     struct usr_vnode *dirP;
2562     struct usr_vattr attrs;
2563     char *nameP;
2564
2565     if (uafs_IsRoot(path)) {
2566         fileP = afs_RootVnode;
2567         VN_HOLD(fileP);
2568     } else {
2569         /*
2570          * Look up the parent directory.
2571          */
2572         nameP = uafs_LastPath(path);
2573         if (nameP != NULL) {
2574             code = uafs_LookupParent(path, &dirP);
2575             if (code != 0) {
2576                 errno = code;
2577                 return -1;
2578             }
2579         } else {
2580             dirP = afs_CurrentDir;
2581             nameP = path;
2582             VN_HOLD(dirP);
2583         }
2584
2585         /*
2586          * Make sure the filename has at least one character
2587          */
2588         if (*nameP == '\0') {
2589             VN_RELE(dirP);
2590             errno = EINVAL;
2591             return -1;
2592         }
2593
2594         /*
2595          * Get the VNODE for this file
2596          */
2597         if (flags & O_CREAT) {
2598             usr_vattr_null(&attrs);
2599             attrs.va_type = VREG;
2600             attrs.va_mode = mode;
2601             attrs.va_uid = u.u_cred->cr_uid;
2602             attrs.va_gid = u.u_cred->cr_gid;
2603             if (flags & O_TRUNC) {
2604                 attrs.va_size = 0;
2605             }
2606             fileP = NULL;
2607             code = afs_create(dirP, nameP, &attrs,
2608                               (flags & O_EXCL)?usr_EXCL:usr_NONEXCL,
2609                               mode, &fileP, u.u_cred);
2610             VN_RELE(dirP);
2611             if (code != 0) {
2612                 errno = code;
2613                 return -1;
2614             }
2615         } else {
2616             fileP = NULL;
2617             code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2618             VN_RELE(dirP);
2619             if (code != 0) {
2620                 errno = code;
2621                 return -1;
2622             }
2623
2624             /*
2625              * Check whether we have access to this file
2626              */
2627             fileMode = 0;
2628             if (flags & (O_RDONLY|O_RDWR)) {
2629                 fileMode |= VREAD;
2630             }
2631             if (flags & (O_WRONLY|O_RDWR)) {
2632                 fileMode |= VWRITE;
2633             }
2634             if (!fileMode) fileMode = VREAD;  /* since O_RDONLY is 0 */
2635             code = afs_access(fileP, fileMode, u.u_cred);
2636             if (code != 0) {
2637                 VN_RELE(fileP);
2638                 errno = code;
2639                 return -1;
2640             }
2641
2642             /*
2643              * Get the file attributes, all we need is the size
2644              */
2645             code = afs_getattr(fileP, &attrs, u.u_cred);
2646             if (code != 0) {
2647                 VN_RELE(fileP);
2648                 errno = code;
2649                 return -1;
2650             }
2651         }
2652     }
2653
2654     /*
2655      * Setup the open flags
2656      */
2657     openFlags = 0;
2658     if (flags & O_TRUNC) {
2659         openFlags |= FTRUNC;
2660     }
2661     if (flags & O_APPEND) {
2662         openFlags |= FAPPEND;
2663     }
2664     if (flags & O_SYNC) {
2665         openFlags |= FSYNC;
2666     }
2667     if (flags & O_SYNC) {
2668         openFlags |= FSYNC;
2669     }
2670     if (flags & (O_RDONLY|O_RDWR)) {
2671         openFlags |= FREAD;
2672     }
2673     if (flags & (O_WRONLY|O_RDWR)) {
2674         openFlags |= FWRITE;
2675     }
2676
2677     /*
2678      * Truncate if necessary
2679      */
2680     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2681         usr_vattr_null(&attrs);
2682         attrs.va_size = 0;
2683         code = afs_setattr(fileP, &attrs, u.u_cred);
2684         if (code != 0) {
2685             VN_RELE(fileP);
2686             errno = code;
2687             return -1;
2688         }
2689     }
2690
2691     /*
2692      * do the open
2693      */
2694     code = afs_open(&fileP, openFlags, u.u_cred);
2695     if (code != 0) {
2696         VN_RELE(fileP);
2697         errno = code;
2698         return -1;
2699     }
2700
2701     /*
2702      * Put the vnode pointer into the file table
2703      */
2704     for (fd = 0 ; fd < MAX_OSI_FILES ; fd++) {
2705         if (afs_FileTable[fd] == NULL) {
2706             afs_FileTable[fd] = fileP;
2707             afs_FileFlags[fd] = openFlags;
2708             if (flags & O_APPEND) {
2709                 afs_FileOffsets[fd] = attrs.va_size;
2710             } else {
2711                 afs_FileOffsets[fd] = 0;
2712             }
2713             break;
2714         }
2715     }
2716     if (fd == MAX_OSI_FILES) {
2717         VN_RELE(fileP);
2718         errno = ENFILE;
2719         return -1;
2720     }
2721
2722     return fd;
2723 }
2724
2725 /*
2726  * Create a file
2727  */
2728 int uafs_creat(char *path, int mode)
2729 {
2730     int rc;
2731     rc = uafs_open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
2732     return rc;
2733 }
2734
2735 int uafs_creat_r(char *path, int mode)
2736 {
2737     int rc;
2738     rc = uafs_open_r(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
2739     return rc;
2740 }
2741
2742 /*
2743  * Write to a file
2744  */
2745 int uafs_write(int fd, char *buf, int len)
2746 {
2747     int retval;
2748     AFS_GLOCK();
2749     retval = uafs_write_r(fd, buf, len);
2750     AFS_GUNLOCK();
2751     return retval;
2752 }
2753
2754 int uafs_write_r(int fd, char *buf, int len)
2755 {
2756     int code;
2757     struct usr_uio uio;
2758     struct iovec iov[1];
2759     struct usr_vnode *fileP;
2760
2761     /*
2762      * Make sure this is an open file
2763      */
2764     fileP = afs_FileTable[fd];
2765     if (fileP == NULL) {
2766         errno = EBADF;
2767         return -1;
2768     }
2769
2770     /*
2771      * set up the uio buffer
2772      */
2773     iov[0].iov_base = buf;
2774     iov[0].iov_len = len;
2775     uio.uio_iov = &iov[0];
2776     uio.uio_iovcnt = 1;
2777     uio.uio_offset = afs_FileOffsets[fd];
2778     uio.uio_segflg = 0;
2779     uio.uio_fmode = FWRITE;
2780     uio.uio_resid = len;
2781
2782     /*
2783      * do the write
2784      */
2785
2786     code = afs_write(fileP, &uio, afs_FileFlags[fd], u.u_cred, 0);
2787     if (code) {
2788         errno = code;
2789         return -1;
2790     }
2791
2792     afs_FileOffsets[fd] = uio.uio_offset;
2793     return(len - uio.uio_resid);
2794 }
2795
2796 /*
2797  * Read from a file
2798  */
2799 int uafs_read(int fd, char *buf, int len)
2800 {
2801     int retval;
2802     AFS_GLOCK();
2803     retval = uafs_read_r(fd, buf, len);
2804     AFS_GUNLOCK();
2805     return retval;
2806 }
2807
2808 int uafs_read_r(int fd, char *buf, int len)
2809 {
2810     int code;
2811     struct usr_uio uio;
2812     struct iovec iov[1];
2813     struct usr_vnode *fileP;
2814     struct usr_buf *bufP;
2815
2816     /*
2817      * Make sure this is an open file
2818      */
2819     fileP = afs_FileTable[fd];
2820     if (fileP == NULL) {
2821         errno = EBADF;
2822         return -1;
2823     }
2824
2825     /*
2826      * set up the uio buffer
2827      */
2828     iov[0].iov_base = buf;
2829     iov[0].iov_len = len;
2830     uio.uio_iov = &iov[0];
2831     uio.uio_iovcnt = 1;
2832     uio.uio_offset = afs_FileOffsets[fd];
2833     uio.uio_segflg = 0;
2834     uio.uio_fmode = FREAD;
2835     uio.uio_resid = len;
2836
2837     /*
2838      * do the read
2839      */
2840     code = afs_read(fileP, &uio, u.u_cred, 0, &bufP, 0);
2841     if (code) {
2842         errno = code;
2843         return -1;
2844     }
2845
2846     afs_FileOffsets[fd] = uio.uio_offset;
2847     return(len - uio.uio_resid);
2848 }
2849
2850 /*
2851  * Copy the attributes of a file into a stat structure.
2852  *
2853  * NOTE: Caller must hold the global AFS lock.
2854  */
2855 int uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2856 {
2857     int code;
2858     struct usr_vattr attrs;
2859
2860     AFS_ASSERT_GLOCK();
2861
2862     /*
2863      * Get the attributes
2864      */
2865     code = afs_getattr(vp, &attrs, u.u_cred);
2866     if (code != 0) {
2867         return code;
2868     }
2869
2870     /*
2871      * Copy the attributes, zero fields that aren't set
2872      */
2873     memset((void *)stats, 0, sizeof(struct stat));
2874     stats->st_dev = -1;
2875     stats->st_ino = attrs.va_nodeid;
2876     stats->st_mode = attrs.va_mode;
2877     stats->st_nlink = attrs.va_nlink;
2878     stats->st_uid = attrs.va_uid;
2879     stats->st_gid = attrs.va_gid;
2880     stats->st_rdev = attrs.va_rdev;
2881     stats->st_size = attrs.va_size;
2882     stats->st_atime = attrs.va_atime.tv_sec;
2883     stats->st_mtime = attrs.va_mtime.tv_sec;
2884     stats->st_ctime = attrs.va_ctime.tv_sec;
2885     stats->st_blksize = attrs.va_blocksize;
2886     stats->st_blocks = attrs.va_blocks;
2887
2888     return 0;
2889 }
2890
2891 /*
2892  * Get the attributes of a file, do follow links
2893  */
2894 int uafs_stat(
2895     char *path,
2896     struct stat *buf)
2897 {
2898     int retval;
2899     AFS_GLOCK();
2900     retval = uafs_stat_r(path, buf);
2901     AFS_GUNLOCK();
2902     return retval;
2903 }
2904
2905 int uafs_stat_r(
2906     char *path,
2907     struct stat *buf)
2908 {
2909     int code;
2910     struct vnode *vp;
2911
2912     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2913     if (code != 0) {
2914         errno = code;
2915         return -1;
2916     }
2917     code = uafs_GetAttr(vp, buf);
2918     VN_RELE(vp);
2919     if (code) {
2920         errno = code;
2921         return -1;
2922     }
2923     return 0;
2924 }
2925
2926 /*
2927  * Get the attributes of a file, don't follow links
2928  */
2929 int uafs_lstat(
2930     char *path,
2931     struct stat *buf)
2932 {
2933     int retval;
2934     AFS_GLOCK();
2935     retval = uafs_lstat_r(path, buf);
2936     AFS_GUNLOCK();
2937     return retval;
2938 }
2939
2940 int uafs_lstat_r(
2941     char *path,
2942     struct stat *buf)
2943 {
2944     int code;
2945     struct vnode *vp;
2946
2947     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2948     if (code != 0) {
2949         errno = code;
2950         return -1;
2951     }
2952     code = uafs_GetAttr(vp, buf);
2953     VN_RELE(vp);
2954     if (code) {
2955         errno = code;
2956         return -1;
2957     }
2958     return 0;
2959 }
2960
2961 /*
2962  * Get the attributes of an open file
2963  */
2964 int uafs_fstat(
2965     int fd,
2966     struct stat *buf)
2967 {
2968     int retval;
2969     AFS_GLOCK();
2970     retval = uafs_fstat_r(fd, buf);
2971     AFS_GUNLOCK();
2972     return retval;
2973 }
2974
2975 int uafs_fstat_r(
2976     int fd,
2977     struct stat *buf)
2978 {
2979     int code;
2980     struct vnode *vp;
2981
2982     vp = afs_FileTable[fd];
2983     if (vp == NULL) {
2984         errno = EBADF;
2985         return -1;
2986     }
2987     code = uafs_GetAttr(vp, buf);
2988     VN_RELE(vp);
2989     if (code) {
2990         errno = code;
2991         return -1;
2992     }
2993     return 0;
2994 }
2995
2996 /*
2997  * change the permissions on a file
2998  */
2999 int uafs_chmod(
3000     char *path,
3001     int mode)
3002 {
3003     int retval;
3004     AFS_GLOCK();
3005     retval = uafs_chmod_r(path, mode);
3006     AFS_GUNLOCK();
3007     return retval;
3008 }
3009
3010 int uafs_chmod_r(
3011     char *path,
3012     int mode)
3013 {
3014     int code;
3015     struct vnode *vp;
3016     struct usr_vattr attrs;
3017
3018     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3019     if (code != 0) {
3020         errno = code;
3021         return -1;
3022     }
3023     usr_vattr_null(&attrs);
3024     attrs.va_mode = mode;
3025     code = afs_setattr(vp, &attrs, u.u_cred);
3026     VN_RELE(vp);
3027     if (code != 0) {
3028         errno = code;
3029         return -1;
3030     }
3031     return 0;
3032 }
3033
3034 /*
3035  * change the permissions on an open file
3036  */
3037 int uafs_fchmod(
3038     int fd,
3039     int mode)
3040 {
3041     int retval;
3042     AFS_GLOCK();
3043     retval = uafs_fchmod_r(fd, mode);
3044     AFS_GUNLOCK();
3045     return retval;
3046 }
3047
3048 int uafs_fchmod_r(
3049     int fd,
3050     int mode)
3051 {
3052     int code;
3053     struct vnode *vp;
3054     struct usr_vattr attrs;
3055
3056     vp = afs_FileTable[fd];
3057     if (vp == NULL) {
3058         errno = EBADF;
3059         return -1;
3060     }
3061     usr_vattr_null(&attrs);
3062     attrs.va_mode = mode;
3063     code = afs_setattr(vp, &attrs, u.u_cred);
3064     if (code != 0) {
3065         errno = code;
3066         return -1;
3067     }
3068     return 0;
3069 }
3070
3071 /*
3072  * truncate a file
3073  */
3074 int uafs_truncate(
3075     char *path,
3076     int length)
3077 {
3078     int retval;
3079     AFS_GLOCK();
3080     retval = uafs_truncate_r(path, length);
3081     AFS_GUNLOCK();
3082     return retval;
3083 }
3084
3085 int uafs_truncate_r(
3086     char *path,
3087     int length)
3088 {
3089     int code;
3090     struct vnode *vp;
3091     struct usr_vattr attrs;
3092
3093     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3094     if (code != 0) {
3095         errno = code;
3096         return -1;
3097     }
3098     usr_vattr_null(&attrs);
3099     attrs.va_size = length;
3100     code = afs_setattr(vp, &attrs, u.u_cred);
3101     VN_RELE(vp);
3102     if (code != 0) {
3103         errno = code;
3104         return -1;
3105     }
3106     return 0;
3107 }
3108
3109 /*
3110  * truncate an open file
3111  */
3112 int uafs_ftruncate(
3113     int fd,
3114     int length)
3115 {
3116     int retval;
3117     AFS_GLOCK();
3118     retval = uafs_ftruncate_r(fd, length);
3119     AFS_GUNLOCK();
3120     return retval;
3121 }
3122
3123 int uafs_ftruncate_r(
3124     int fd,
3125     int length)
3126 {
3127     int code;
3128     struct vnode *vp;
3129     struct usr_vattr attrs;
3130
3131     vp = afs_FileTable[fd];
3132     if (vp == NULL) {
3133         errno = EBADF;
3134         return -1;
3135     }
3136     usr_vattr_null(&attrs);
3137     attrs.va_size = length;
3138     code = afs_setattr(vp, &attrs, u.u_cred);
3139     if (code != 0) {
3140         errno = code;
3141         return -1;
3142     }
3143     return 0;
3144 }
3145
3146 /*
3147  * set the read/write file pointer of an open file
3148  */
3149 int uafs_lseek(
3150     int fd,
3151     int offset,
3152     int whence)
3153 {
3154     int retval;
3155     AFS_GLOCK();
3156     retval = uafs_lseek_r(fd, offset, whence);
3157     AFS_GUNLOCK();
3158     return retval;
3159 }
3160
3161 int uafs_lseek_r(
3162     int fd,
3163     int offset,
3164     int whence)
3165 {
3166     int code;
3167     int newpos;
3168     struct usr_vattr attrs;
3169     struct usr_vnode *vp;
3170
3171     vp = afs_FileTable[fd];
3172     if (vp == NULL) {
3173         errno = EBADF;
3174         return -1;
3175     }
3176     switch (whence) {
3177       case SEEK_CUR:
3178         newpos = afs_FileOffsets[fd] + offset;
3179         break;
3180       case SEEK_SET:
3181         newpos = offset;
3182         break;
3183       case SEEK_END:
3184         code = afs_getattr(vp, &attrs, u.u_cred);
3185         if (code != 0) {
3186             errno = code;
3187             return -1;
3188         }
3189         newpos = attrs.va_size + offset;
3190         break;
3191       default:
3192         errno = EINVAL;
3193         return -1;
3194     }
3195     if (newpos < 0) {
3196         errno = EINVAL;
3197         return -1;
3198     }
3199     afs_FileOffsets[fd] = newpos;
3200     return newpos;
3201 }
3202
3203 /*
3204  * sync a file
3205  */
3206 int uafs_fsync(
3207     int fd)
3208 {
3209     int retval;
3210     AFS_GLOCK();
3211     retval = uafs_fsync_r(fd);
3212     AFS_GUNLOCK();
3213     return retval;
3214 }
3215
3216 int uafs_fsync_r(
3217     int fd)
3218 {
3219     int code;
3220     struct usr_vnode *fileP;
3221
3222
3223     fileP = afs_FileTable[fd];
3224     if (fileP == NULL) {
3225         errno = EBADF;
3226         return -1;
3227     }
3228
3229     code = afs_fsync(fileP, u.u_cred);
3230     if (code != 0) {
3231         errno = code;
3232         return -1;
3233     }
3234
3235     return 0; 
3236 }
3237
3238 /*
3239  * Close a file
3240  */
3241 int uafs_close(
3242     int fd)
3243 {
3244     int retval;
3245     AFS_GLOCK();
3246     retval = uafs_close_r(fd);
3247     AFS_GUNLOCK();
3248     return retval;
3249 }
3250
3251 int uafs_close_r(
3252     int fd)
3253 {
3254     int code;
3255     struct usr_vnode *fileP;
3256
3257     fileP = afs_FileTable[fd];
3258     if (fileP == NULL) {
3259         errno = EBADF;
3260         return -1;
3261     }
3262     afs_FileTable[fd] = NULL;
3263
3264     code = afs_close(fileP, afs_FileFlags[fd], u.u_cred);
3265     VN_RELE(fileP);
3266     if (code != 0) {
3267         errno = code;
3268         return -1;
3269     }
3270
3271     return 0; 
3272 }
3273
3274 /*
3275  * Create a hard link from the source to the target
3276  * Note: file names may not end in a slash.
3277  */
3278 int uafs_link(
3279     char *existing,
3280     char *new)
3281 {
3282     int retval;
3283     AFS_GLOCK();
3284     retval = uafs_link_r(existing, new);
3285     AFS_GUNLOCK();
3286     return retval;
3287 }
3288
3289 int uafs_link_r(
3290     char *existing,
3291     char *new)
3292 {
3293     int code;
3294     struct usr_vnode *existP;
3295     struct usr_vnode *dirP;
3296     char *nameP;
3297
3298     if (uafs_IsRoot(new)) {
3299         return EACCES;
3300     }
3301
3302     /*
3303      * Look up the existing node.
3304      */
3305     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
3306     if (code != 0) {
3307         errno = code;
3308         return -1;
3309     }
3310
3311     /*
3312      * Look up the parent directory.
3313      */
3314     nameP = uafs_LastPath(new);
3315     if (nameP != NULL) {
3316         code = uafs_LookupParent(new, &dirP);
3317         if (code != 0) {
3318             VN_RELE(existP);
3319             errno = code;
3320             return -1;
3321         }
3322     } else {
3323         dirP = afs_CurrentDir;
3324         nameP = new;
3325         VN_HOLD(dirP);
3326     }
3327
3328     /*
3329      * Make sure the filename has at least one character
3330      */
3331     if (*nameP == '\0') {
3332         VN_RELE(existP);
3333         VN_RELE(dirP);
3334         errno = EINVAL;
3335         return -1;
3336     }
3337
3338     /*
3339      * Create the link
3340      */
3341     code = afs_link(existP, dirP, nameP, u.u_cred);
3342     VN_RELE(existP);
3343     VN_RELE(dirP);
3344     if (code != 0) {
3345         errno = code;
3346         return -1;
3347     }
3348     return 0;
3349 }
3350
3351 /*
3352  * Create a symbolic link from the source to the target
3353  * Note: file names may not end in a slash.
3354  */
3355 int uafs_symlink(
3356     char *target,
3357     char *source)
3358 {
3359     int retval;
3360     AFS_GLOCK();
3361     retval = uafs_symlink_r(target, source);
3362     AFS_GUNLOCK();
3363     return retval;
3364 }
3365
3366 int uafs_symlink_r(
3367     char *target,
3368     char *source)
3369 {
3370     int code;
3371     struct usr_vnode *dirP;
3372     struct usr_vattr attrs;
3373     char *nameP;
3374
3375     if (uafs_IsRoot(source)) {
3376         return EACCES;
3377     }
3378
3379     /*
3380      * Look up the parent directory.
3381      */
3382     nameP = uafs_LastPath(source);
3383     if (nameP != NULL) {
3384         code = uafs_LookupParent(source, &dirP);
3385         if (code != 0) {
3386             errno = code;
3387             return -1;
3388         }
3389     } else {
3390         dirP = afs_CurrentDir;
3391         nameP = source;
3392         VN_HOLD(dirP);
3393     }
3394
3395     /*
3396      * Make sure the filename has at least one character
3397      */
3398     if (*nameP == '\0') {
3399         VN_RELE(dirP);
3400         errno = EINVAL;
3401         return -1;
3402     }
3403
3404     /*
3405      * Create the link
3406      */
3407     usr_vattr_null(&attrs);
3408     attrs.va_type = VLNK;
3409     attrs.va_mode = 0777;
3410     attrs.va_uid = u.u_cred->cr_uid;
3411     attrs.va_gid = u.u_cred->cr_gid;
3412     code = afs_symlink(dirP, nameP, &attrs, target, u.u_cred);
3413     VN_RELE(dirP);
3414     if (code != 0) {
3415         errno = code;
3416         return -1;
3417     }
3418     return 0;
3419 }
3420
3421 /*
3422  * Read a symbolic link into the buffer
3423  */
3424 int uafs_readlink(
3425     char *path,
3426     char *buf,
3427     int len)
3428 {
3429     int retval;
3430     AFS_GLOCK();
3431     retval = uafs_readlink_r(path, buf, len);
3432     AFS_GUNLOCK();
3433     return retval;
3434 }
3435
3436 int uafs_readlink_r(
3437     char *path,
3438     char *buf,
3439     int len)
3440 {
3441     int code;
3442     struct usr_vnode *vp;
3443     struct usr_uio uio;
3444     struct iovec iov[1];
3445
3446     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3447     if (code != 0) {
3448         errno = code;
3449         return -1;
3450     }
3451
3452     if (vp->v_type != VLNK) {
3453         VN_RELE(vp);
3454         errno = EINVAL;
3455         return -1;
3456     }
3457
3458     /*
3459      * set up the uio buffer
3460      */
3461     iov[0].iov_base = buf;
3462     iov[0].iov_len = len;
3463     uio.uio_iov = &iov[0];
3464     uio.uio_iovcnt = 1;
3465     uio.uio_offset = 0;
3466     uio.uio_segflg = 0;
3467     uio.uio_fmode = FREAD;
3468     uio.uio_resid = len;
3469
3470     /*
3471      * Read the the link
3472      */
3473     code = afs_readlink(vp, &uio, u.u_cred);
3474     VN_RELE(vp);
3475     if (code) {
3476         errno = code;
3477         return -1;
3478     }
3479
3480     /*
3481      * return the number of bytes read
3482      */
3483     return (len - uio.uio_resid);
3484 }
3485
3486 /*
3487  * Remove a file (or directory)
3488  * Note: file name may not end in a slash.
3489  */
3490 int uafs_unlink(
3491     char *path)
3492 {
3493     int retval;
3494     AFS_GLOCK();
3495     retval = uafs_unlink_r(path);
3496     AFS_GUNLOCK();
3497     return retval;
3498 }
3499
3500 int uafs_unlink_r(
3501     char *path)
3502 {
3503     int code;
3504     int openFlags;
3505     struct usr_vnode *fileP;
3506     struct usr_vnode *dirP;
3507     char *nameP;
3508
3509     if (uafs_IsRoot(path)) {
3510         return EACCES;
3511     }
3512
3513     /*
3514      * Look up the parent directory.
3515      */
3516     nameP = uafs_LastPath(path);
3517     if (nameP != NULL) {
3518         code = uafs_LookupParent(path, &dirP);
3519         if (code != 0) {
3520             errno = code;
3521             return -1;
3522         }
3523     } else {
3524         dirP = afs_CurrentDir;
3525         nameP = path;
3526         VN_HOLD(dirP);
3527     }
3528
3529     /*
3530      * Make sure the filename has at least one character
3531      */
3532     if (*nameP == '\0') {
3533         VN_RELE(dirP);
3534         errno = EINVAL;
3535         return -1;
3536     }
3537
3538     /*
3539      * Remove the file
3540      */
3541     code = afs_remove(dirP, nameP, u.u_cred);
3542     VN_RELE(dirP);
3543     if (code != 0) {
3544         errno = code;
3545         return -1;
3546     }
3547
3548     return 0;
3549 }
3550
3551 /*
3552  * Rename a file (or directory)
3553  */
3554 int uafs_rename(
3555     char *old,
3556     char *new)
3557 {
3558     int retval;
3559     AFS_GLOCK();
3560     retval = uafs_rename_r(old, new);
3561     AFS_GUNLOCK();
3562     return retval;
3563 }
3564
3565 int uafs_rename_r(
3566     char *old,
3567     char *new)
3568 {
3569     int code;
3570     char *onameP;
3571     char *nnameP;
3572     struct usr_vnode *odirP;
3573     struct usr_vnode *ndirP;
3574
3575     if (uafs_IsRoot(new)) {
3576         return EACCES;
3577     }
3578
3579     /*
3580      * Look up the parent directories.
3581      */
3582     onameP = uafs_LastPath(old);
3583     if (onameP != NULL) {
3584         code = uafs_LookupParent(old, &odirP);
3585         if (code != 0) {
3586             errno = code;
3587             return -1;
3588         }
3589     } else {
3590         odirP = afs_CurrentDir;
3591         onameP = old;
3592         VN_HOLD(odirP);
3593     }
3594     nnameP = uafs_LastPath(new);
3595     if (nnameP != NULL) {
3596         code = uafs_LookupParent(new, &ndirP);
3597         if (code != 0) {
3598             errno = code;
3599             return -1;
3600         }
3601     } else {
3602         ndirP = afs_CurrentDir;
3603         nnameP = new;
3604         VN_HOLD(ndirP);
3605     }
3606
3607     /*
3608      * Make sure the filename has at least one character
3609      */
3610     if (*onameP == '\0' || *nnameP == '\0') {
3611         VN_RELE(odirP);
3612         VN_RELE(ndirP);
3613         errno = EINVAL;
3614         return -1;
3615     }
3616
3617     /*
3618      * Rename the file
3619      */
3620     code = afs_rename(odirP, onameP, ndirP, nnameP, u.u_cred);
3621     VN_RELE(odirP);
3622     VN_RELE(ndirP);
3623     if (code != 0) {
3624         errno = code;
3625         return -1;
3626     }
3627
3628     return 0;
3629 }
3630
3631 /*
3632  * Remove a or directory
3633  * Note: file name may not end in a slash.
3634  */
3635 int uafs_rmdir(
3636     char *path)
3637 {
3638     int retval;
3639     AFS_GLOCK();
3640     retval = uafs_rmdir_r(path);
3641     AFS_GUNLOCK();
3642     return retval;
3643 }
3644
3645 int uafs_rmdir_r(
3646     char *path)
3647 {
3648     int code;
3649     int openFlags;
3650     struct usr_vnode *fileP;
3651     struct usr_vnode *dirP;
3652     char *nameP;
3653
3654     if (uafs_IsRoot(path)) {
3655         return EACCES;
3656     }
3657
3658     /*
3659      * Look up the parent directory.
3660      */
3661     nameP = uafs_LastPath(path);
3662     if (nameP != NULL) {
3663         code = uafs_LookupParent(path, &dirP);
3664         if (code != 0) {
3665             errno = code;
3666             return -1;
3667         }
3668     } else {
3669         dirP = afs_CurrentDir;
3670         nameP = path;
3671         VN_HOLD(dirP);
3672     }
3673
3674     /*
3675      * Make sure the directory name has at least one character
3676      */
3677     if (*nameP == '\0') {
3678         VN_RELE(dirP);
3679         errno = EINVAL;
3680         return -1;
3681     }
3682
3683     /*
3684      * Remove the directory
3685      */
3686     code = afs_rmdir(dirP, nameP, u.u_cred);
3687     VN_RELE(dirP);
3688     if (code != 0) {
3689         errno = code;
3690         return -1;
3691     }
3692
3693     return 0;
3694 }
3695
3696 /*
3697  * Flush a file from the AFS cache
3698  */
3699 int uafs_FlushFile(
3700      char *path)
3701 {
3702     int code;
3703     struct afs_ioctl iob;
3704
3705     iob.in = NULL;
3706     iob.in_size = 0;
3707     iob.out = NULL;
3708     iob.out_size = 0;
3709
3710     code = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6),
3711                         (long)&iob, 0, 0);
3712     if (code != 0) {
3713         errno = code;
3714         return -1;
3715     }
3716
3717     return 0;
3718 }
3719 int uafs_FlushFile_r(
3720      char *path)
3721 {
3722     int retval;
3723     AFS_GUNLOCK();
3724     retval = uafs_FlushFile(path);
3725     AFS_GLOCK();
3726     return retval;
3727 }
3728
3729 /*
3730  * open a directory
3731  */
3732 usr_DIR *uafs_opendir(
3733     char *path)
3734 {
3735     usr_DIR *retval;
3736     AFS_GLOCK();
3737     retval = uafs_opendir_r(path);
3738     AFS_GUNLOCK();
3739     return retval;
3740 }
3741
3742 usr_DIR *uafs_opendir_r(
3743     char *path)
3744 {
3745     usr_DIR *dirp;
3746     struct usr_vnode *fileP;
3747     int fd;
3748
3749     /*
3750      * Open the directory for reading
3751      */
3752     fd = uafs_open_r(path, O_RDONLY, 0);
3753     if (fd < 0) {
3754         return NULL;
3755     }
3756
3757     fileP = afs_FileTable[fd];
3758     if (fileP == NULL) {
3759      return NULL;
3760     }
3761
3762     if (fileP->v_type != VDIR) {
3763       uafs_close_r(fd);
3764       errno = ENOTDIR;
3765       return NULL;
3766     }
3767
3768     /*
3769      * Set up the directory structures
3770      */
3771     dirp = (usr_DIR *)afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3772                                     sizeof(struct usr_dirent));
3773     usr_assert(dirp != NULL);
3774     dirp->dd_buf = (char *)(dirp+1);
3775     dirp->dd_fd = fd;
3776     dirp->dd_loc = 0;
3777     dirp->dd_size = 0;
3778
3779     errno = 0;
3780     return dirp;
3781 }
3782
3783 /*
3784  * Read directory entries into a file system independent format.
3785  * This routine was developed to support AFS cache consistency testing.
3786  * You should use uafs_readdir instead.
3787  */
3788 int uafs_getdents(
3789     int fd,
3790     struct min_direct *buf,
3791     int len)
3792 {
3793     int retval;
3794     AFS_GLOCK();
3795     retval = uafs_getdents_r(fd, buf, len);
3796     AFS_GUNLOCK();
3797     return retval;
3798 }
3799
3800 int uafs_getdents_r(
3801     int fd,
3802     struct min_direct *buf,
3803     int len)
3804 {
3805     int code;
3806     struct usr_uio uio;
3807     struct usr_vnode *vp;
3808     struct iovec iov[1];
3809
3810     /*
3811      * Make sure this is an open file
3812      */
3813     vp = afs_FileTable[fd];
3814     if (vp == NULL) {
3815         AFS_GUNLOCK();
3816         errno = EBADF;
3817         return -1;
3818     }
3819
3820     /*
3821      * set up the uio buffer
3822      */
3823     iov[0].iov_base = (char *)buf;
3824     iov[0].iov_len = len;
3825     uio.uio_iov = &iov[0];
3826     uio.uio_iovcnt = 1;
3827     uio.uio_offset = afs_FileOffsets[fd];
3828     uio.uio_segflg = 0;
3829     uio.uio_fmode = FREAD;
3830     uio.uio_resid = len;
3831
3832     /*
3833      * read the next chunk from the directory
3834      */
3835     code = afs_readdir(vp, &uio, u.u_cred);
3836     if (code != 0) {
3837         errno = code;
3838         return -1;
3839     }
3840
3841     afs_FileOffsets[fd] = uio.uio_offset;
3842     return(len - uio.uio_resid);
3843 }
3844
3845 /*
3846  * read from a directory (names only)
3847  */
3848 struct usr_dirent *uafs_readdir(
3849     usr_DIR *dirp)
3850 {
3851     struct usr_dirent *retval;
3852     AFS_GLOCK();
3853     retval = uafs_readdir_r(dirp);
3854     AFS_GUNLOCK();
3855     return retval;
3856 }
3857
3858 struct usr_dirent *uafs_readdir_r(
3859     usr_DIR *dirp)
3860 {
3861     int rc;
3862     int code;
3863     int len;
3864     struct usr_uio uio;
3865     struct usr_vnode *vp;
3866     struct iovec iov[1];
3867     struct usr_dirent *direntP;
3868     struct min_direct *directP;
3869
3870     /*
3871      * Make sure this is an open file
3872      */
3873     vp = afs_FileTable[dirp->dd_fd];
3874     if (vp == NULL) {
3875         errno = EBADF;
3876         return NULL;
3877     }
3878
3879     /*
3880      * If there are no entries in the stream buffer
3881      * then read another chunk
3882      */
3883     directP = (struct min_direct *)(dirp->dd_buf+dirp->dd_loc);
3884     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3885         /*
3886          * set up the uio buffer
3887          */
3888         iov[0].iov_base = dirp->dd_buf;
3889         iov[0].iov_len = USR_DIRSIZE;
3890         uio.uio_iov = &iov[0];
3891         uio.uio_iovcnt = 1;
3892         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3893         uio.uio_segflg = 0;
3894         uio.uio_fmode = FREAD;
3895         uio.uio_resid = USR_DIRSIZE;
3896
3897         /*
3898          * read the next chunk from the directory
3899          */
3900         code = afs_readdir(vp, &uio, u.u_cred);
3901         if (code != 0) {
3902             errno = code;
3903             return NULL;
3904         }
3905         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3906
3907         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3908         dirp->dd_loc = 0;
3909         directP = (struct min_direct *)(dirp->dd_buf+dirp->dd_loc);
3910     }
3911
3912     /*
3913      * Check for end of file
3914      */
3915     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3916         errno = 0;
3917         return NULL;
3918     }
3919     len = ((sizeof(struct min_direct)+directP->d_namlen+4) & (~3));
3920     usr_assert(len <= dirp->dd_size);
3921
3922     /*
3923      * Copy the next entry into the usr_dirent structure and advance
3924      */
3925     direntP = (struct usr_dirent *)(dirp->dd_buf+USR_DIRSIZE);
3926     direntP->d_ino = directP->d_fileno;
3927     direntP->d_off = direntP->d_reclen;
3928     direntP->d_reclen = sizeof(struct usr_dirent) - MAXNAMLEN +
3929                                directP->d_namlen + 1;
3930     memcpy(&direntP->d_name[0], (void *)(directP+1), directP->d_namlen);
3931     direntP->d_name[directP->d_namlen] = '\0';
3932     dirp->dd_loc += len;
3933     dirp->dd_size -= len;
3934
3935     return direntP;
3936 }
3937
3938 /*
3939  * Close a directory
3940  */
3941 int uafs_closedir(
3942     usr_DIR *dirp)
3943 {
3944     int retval;
3945     AFS_GLOCK();
3946     retval = uafs_closedir_r(dirp);
3947     AFS_GUNLOCK();
3948     return retval;
3949 }
3950
3951 int uafs_closedir_r(
3952     usr_DIR *dirp)
3953 {
3954     int fd;
3955     int rc;
3956
3957     fd = dirp->dd_fd;
3958     afs_osi_Free((char *)dirp,
3959                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3960     rc = uafs_close_r(fd);
3961     return rc;
3962 }
3963
3964 /*
3965  * Do AFS authentication
3966  */
3967 int uafs_klog(
3968     char *user,
3969     char *cell,
3970     char *passwd,
3971     char **reason)
3972 {
3973     int code;
3974     afs_int32 password_expires = -1;
3975
3976     usr_mutex_lock(&osi_authenticate_lock);
3977     code = ka_UserAuthenticateGeneral(
3978                 KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG2, user,
3979                 NULL, cell, passwd, 0, &password_expires,
3980                 0, reason);
3981     usr_mutex_unlock(&osi_authenticate_lock);
3982     return code;
3983 }
3984
3985 int uafs_klog_r(
3986     char *user,
3987     char *cell,
3988     char *passwd,
3989     char **reason)
3990 {
3991     int retval;
3992     AFS_GUNLOCK();
3993     retval = uafs_klog(user, cell, passwd, reason);
3994     AFS_GLOCK();
3995     return retval;
3996 }
3997
3998 /*
3999  * Destroy AFS credentials from the kernel cache
4000  */
4001 int uafs_unlog(void)
4002 {
4003     int code;
4004
4005     usr_mutex_lock(&osi_authenticate_lock);
4006     code = ktc_ForgetAllTokens();
4007     usr_mutex_unlock(&osi_authenticate_lock);
4008     return code;
4009 }
4010
4011 int uafs_unlog_r(void)
4012 {
4013     int retval;
4014     AFS_GUNLOCK();
4015     retval = uafs_unlog();
4016     AFS_GLOCK();
4017     return retval;
4018 }
4019
4020 /*
4021  * Strip the AFS mount point from a pathname string. Return
4022  * NULL if the path is a relative pathname or if the path
4023  * doesn't start with the AFS mount point string.
4024  */
4025 char *uafs_afsPathName(char *path)
4026 {
4027     char *p;
4028     char lastchar;
4029     int i;
4030
4031     if (path[0] != '/')
4032         return NULL;
4033     lastchar = '/';
4034     for (i = 1, p = path+1; *p != '\0' ; p++) {
4035         /* Ignore duplicate slashes */
4036         if (*p == '/' && lastchar == '/')
4037             continue;
4038         /* Is this a subdirectory of the AFS mount point? */
4039         if (afs_mountDir[i] == '\0' && *p == '/') {
4040             /* strip leading slashes */
4041             while (*(++p) == '/');
4042             return p;
4043         }
4044         /* Reject paths that are not within AFS */
4045         if (*p != afs_mountDir[i])
4046             return NULL;
4047         lastchar = *p;
4048         i++;
4049     }
4050     /* Is this the AFS mount point? */
4051     if (afs_mountDir[i] == '\0') {
4052         usr_assert(*p == '\0');
4053         return p;
4054     }
4055     return NULL;
4056 }
4057
4058 #ifdef AFS_WEB_ENHANCEMENTS
4059 /*
4060  * uafs_klog_nopag
4061  * klog but don't allocate a new pag
4062  */
4063 int uafs_klog_nopag(
4064     char *user,
4065     char *cell,
4066     char *passwd,
4067     char **reason)
4068 {
4069     int code;
4070     afs_int32 password_expires = -1;
4071
4072     usr_mutex_lock(&osi_authenticate_lock);
4073     code = ka_UserAuthenticateGeneral(
4074       KA_USERAUTH_VERSION  /*+KA_USERAUTH_DOSETPAG2*/, user,
4075           NULL, cell, passwd, 0, &password_expires,
4076           0, reason);
4077     usr_mutex_unlock(&osi_authenticate_lock);
4078     return code;
4079 }
4080
4081 /*
4082  * uafs_getcellstatus
4083  * get the cell status
4084  */
4085 int uafs_getcellstatus(char *cell, afs_int32 *status)
4086 {
4087   int rc;
4088   struct afs_ioctl iob;
4089
4090   iob.in = cell;
4091   iob.in_size = strlen(cell)+1;
4092   iob.out = 0;
4093   iob.out_size = 0;
4094
4095   rc = call_syscall(AFSCALL_PIOCTL, /*path*/0, _VICEIOCTL(35),
4096                       (long)&iob, 0, 0);
4097
4098   if (rc < 0) {
4099     errno = rc;
4100     return -1;
4101   }
4102
4103   *status = (afs_int32) iob.out;
4104   return 0;
4105 }
4106
4107 /*
4108  * uafs_getvolquota
4109  * Get quota of volume associated with path
4110  */
4111 int uafs_getvolquota(char *path, afs_int32 *BlocksInUse, afs_int32 *MaxQuota)
4112 {
4113   int rc;
4114   struct afs_ioctl iob;
4115   VolumeStatus *status;
4116   char buf[1024];
4117
4118   iob.in = 0;
4119   iob.in_size = 0;
4120   iob.out = buf;
4121   iob.out_size = 1024;
4122
4123   rc = call_syscall(AFSCALL_PIOCTL, (long) path, _VICEIOCTL(4),
4124                       (long)&iob, 0, 0);
4125
4126   if (rc != 0) {
4127     errno = rc;
4128     return -1;
4129   }
4130
4131   status = (VolumeStatus *) buf;
4132   *BlocksInUse = status->BlocksInUse;
4133   *MaxQuota = status->MaxQuota;
4134   return 0;
4135 }
4136
4137 /*
4138  * uafs_setvolquota
4139  * Set quota of volume associated with path
4140  */
4141 int uafs_setvolquota(char *path, afs_int32 MaxQuota)
4142 {
4143   int rc;
4144   struct afs_ioctl iob;
4145   VolumeStatus *status;
4146   char buf[1024];
4147
4148   iob.in = buf;
4149   iob.in_size = 1024;
4150   iob.out = 0;
4151   iob.out_size = 0;
4152
4153   memset(buf, 0, sizeof(VolumeStatus));
4154   status = (VolumeStatus *) buf;
4155   status->MaxQuota = MaxQuota;
4156   status->MinQuota = -1;
4157
4158   rc = call_syscall(AFSCALL_PIOCTL, (long) path, _VICEIOCTL(5),
4159                       (long)&iob, 0, 0);
4160
4161   if (rc != 0) {
4162     errno = rc;
4163     return -1;
4164   }
4165
4166   return 0;
4167 }
4168
4169 /*
4170  * uafs_statmountpoint
4171  * Determine whether a dir. is a mount point or not
4172  * return 1 if mount point, 0 if not
4173  */
4174 int uafs_statmountpoint(char *path)
4175 {
4176     int retval;
4177     int code;
4178     char buf[256];
4179
4180     AFS_GLOCK();
4181     retval = uafs_statmountpoint_r(path);
4182     AFS_GUNLOCK();
4183     return retval;
4184 }
4185
4186 int uafs_statmountpoint_r(char *path)
4187 {
4188     int code;
4189     struct vnode *vp;
4190     struct vcache *avc;
4191     struct vrequest treq;
4192     int r;
4193
4194     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
4195     if (code != 0) {
4196      errno = code;
4197      return -1;
4198     }
4199
4200     avc = VTOAFS(vp);
4201
4202     r = avc->mvstat;
4203     VN_RELE(vp);
4204     return r;
4205 }
4206
4207 /*
4208  * uafs_getRights
4209  * Get a list of rights for the current user on path.
4210  */
4211 int uafs_getRights(char *path)
4212 {
4213     int code, rc;
4214     struct vnode *vp;
4215     int afs_rights;
4216
4217     AFS_GLOCK();
4218     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
4219     if (code != 0) {
4220      errno = code;
4221      AFS_GUNLOCK();
4222      return -1;
4223     }
4224
4225     afs_rights = PRSFS_READ |
4226       PRSFS_WRITE |
4227       PRSFS_INSERT |
4228       PRSFS_LOOKUP |
4229       PRSFS_DELETE |
4230       PRSFS_LOCK |
4231       PRSFS_ADMINISTER;
4232
4233     afs_rights = afs_getRights (vp, afs_rights, u.u_cred);
4234
4235     AFS_GUNLOCK();
4236     return afs_rights;
4237 }
4238 #endif /* AFS_WEB_ENHANCEMENTS */
4239
4240 #endif /* UKERNEL */