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