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