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