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