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