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