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