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