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