UKERNEL: remove dead code osi_SetTime
[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(afs_ucred_t *credp)
170 {
171     return 1;
172 }
173
174 int
175 afs_suser(afs_ucred_t *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_Active(struct vcache *avc)
947 {
948     AFS_STATCNT(osi_Active);
949     if (avc->opens > 0)
950         return (1);
951     return 0;
952 }
953
954 int
955 afs_osi_MapStrategy(int (*aproc) (struct usr_buf *), struct usr_buf *bp)
956 {
957     afs_int32 returnCode;
958     returnCode = (*aproc) (bp);
959     return returnCode;
960 }
961
962 void
963 osi_FlushPages(struct vcache *avc, afs_ucred_t *credp)
964 {
965     ObtainSharedLock(&avc->lock, 555);
966     if ((hcmp((avc->f.m.DataVersion), (avc->mapDV)) <= 0)
967         || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
968         ReleaseSharedLock(&avc->lock);
969         return;
970     }
971     UpgradeSToWLock(&avc->lock, 565);
972     hset(avc->mapDV, avc->f.m.DataVersion);
973     ReleaseWriteLock(&avc->lock);
974     return;
975 }
976
977 void
978 osi_FlushText_really(struct vcache *vp)
979 {
980     if (hcmp(vp->f.m.DataVersion, vp->flushDV) > 0) {
981         hset(vp->flushDV, vp->f.m.DataVersion);
982     }
983     return;
984 }
985
986 int
987 osi_SyncVM(struct vcache *avc)
988 {
989     return 0;
990 }
991
992 void
993 osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
994 {
995     return;
996 }
997
998 void
999 osi_Init(void)
1000 {
1001     int i;
1002     int st;
1003
1004     /*
1005      * Use the thread specific data to implement the user structure
1006      */
1007     usr_keycreate(&afs_global_u_key, free);
1008
1009     /*
1010      * Initialize the global ucred structure
1011      */
1012     afs_global_ucredp = (struct usr_ucred *)
1013         afs_osi_Alloc(sizeof(struct usr_ucred));
1014     usr_assert(afs_global_ucredp != NULL);
1015     afs_global_ucredp->cr_ref = 1;
1016     afs_set_cr_uid(afs_global_ucredp, geteuid());
1017     afs_set_cr_gid(afs_global_ucredp, getegid());
1018     afs_set_cr_ruid(afs_global_ucredp, getuid());
1019     afs_set_cr_rgid(afs_global_ucredp, getgid());
1020     afs_global_ucredp->cr_suid = afs_cr_ruid(afs_global_ucredp);
1021     afs_global_ucredp->cr_sgid = afs_cr_rgid(afs_global_ucredp);
1022     st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1023     usr_assert(st >= 0);
1024     afs_global_ucredp->cr_ngroups = (unsigned long)st;
1025     for (i = st; i < NGROUPS; i++) {
1026         afs_global_ucredp->cr_groups[i] = NOGROUP;
1027     }
1028
1029     /*
1030      * Initialize the global process structure
1031      */
1032     afs_global_procp = (struct usr_proc *)
1033         afs_osi_Alloc(sizeof(struct usr_proc));
1034     usr_assert(afs_global_procp != NULL);
1035     afs_global_procp->p_pid = osi_getpid();
1036     afs_global_procp->p_ppid = (pid_t) 1;
1037     afs_global_procp->p_ucred = afs_global_ucredp;
1038
1039     /*
1040      * Initialize the mutex and condition variable used to implement
1041      * time sleeps.
1042      */
1043     pthread_mutex_init(&usr_sleep_mutex, NULL);
1044     pthread_cond_init(&usr_sleep_cond, NULL);
1045
1046     /*
1047      * Initialize the hash table used for sleep/wakeup
1048      */
1049     for (i = 0; i < OSI_WAITHASH_SIZE; i++) {
1050         DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1051     }
1052     DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1053     osi_waithash_avail = NULL;
1054
1055     /*
1056      * Initialize the AFS file table
1057      */
1058     for (i = 0; i < MAX_OSI_FILES; i++) {
1059         afs_FileTable[i] = NULL;
1060     }
1061
1062     /*
1063      * Initialize the global locks
1064      */
1065     usr_mutex_init(&afs_global_lock);
1066     usr_mutex_init(&rx_global_lock);
1067     usr_mutex_init(&osi_dummy_lock);
1068     usr_mutex_init(&osi_waitq_lock);
1069     usr_mutex_init(&osi_authenticate_lock);
1070
1071     /*
1072      * Initialize the AFS OSI credentials
1073      */
1074     afs_osi_cred = *afs_global_ucredp;
1075     afs_osi_credp = &afs_osi_cred;
1076
1077     init_et_to_sys_error();
1078 }
1079
1080 /*
1081  * Set the UDP port number RX uses for UDP datagrams
1082  */
1083 void
1084 uafs_SetRxPort(int port)
1085 {
1086     usr_assert(usr_rx_port == 0);
1087     usr_rx_port = port;
1088 }
1089
1090 /*
1091  * uafs_Init is for backwards compatibility only! Do not use it; use
1092  * uafs_Setup, uafs_ParseArgs, and uafs_Run instead.
1093  */
1094 void
1095 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
1096           char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
1097           int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
1098           int chunkSizeParam, int closeSynchParam, int debugParam,
1099           int nDaemonsParam, int cacheFlagsParam, char *logFile)
1100 {
1101     int code;
1102     int argc = 0;
1103     char *argv[32];
1104     int freeargc = 0;
1105     void *freeargv[32];
1106     char buf[1024];
1107     int i;
1108
1109     code = uafs_Setup(mountDirParam);
1110     usr_assert(code == 0);
1111
1112     argv[argc++] = rn;
1113     if (mountDirParam) {
1114         argv[argc++] = "-mountdir";
1115         argv[argc++] = mountDirParam;
1116     }
1117     if (confDirParam) {
1118         argv[argc++] = "-confdir";
1119         argv[argc++] = confDirParam;
1120     }
1121     if (cacheBaseDirParam) {
1122         argv[argc++] = "-cachedir";
1123         argv[argc++] = cacheBaseDirParam;
1124     }
1125     if (cacheBlocksParam) {
1126         snprintf(buf, sizeof(buf), "%d", cacheBlocksParam);
1127
1128         argv[argc++] = "-blocks";
1129         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1130     }
1131     if (cacheFilesParam) {
1132         snprintf(buf, sizeof(buf), "%d", cacheFilesParam);
1133
1134         argv[argc++] = "-files";
1135         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1136     }
1137     if (cacheStatEntriesParam) {
1138         snprintf(buf, sizeof(buf), "%d", cacheStatEntriesParam);
1139
1140         argv[argc++] = "-stat";
1141         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1142     }
1143     if (dCacheSizeParam) {
1144         snprintf(buf, sizeof(buf), "%d", dCacheSizeParam);
1145
1146         argv[argc++] = "-dcache";
1147         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1148     }
1149     if (vCacheSizeParam) {
1150         snprintf(buf, sizeof(buf), "%d", vCacheSizeParam);
1151
1152         argv[argc++] = "-volumes";
1153         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1154     }
1155     if (chunkSizeParam) {
1156         snprintf(buf, sizeof(buf), "%d", chunkSizeParam);
1157
1158         argv[argc++] = "-chunksize";
1159         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1160     }
1161     if (closeSynchParam) {
1162         argv[argc++] = "-waitclose";
1163     }
1164     if (debugParam) {
1165         argv[argc++] = "-debug";
1166     }
1167     if (nDaemonsParam) {
1168         snprintf(buf, sizeof(buf), "%d", nDaemonsParam);
1169
1170         argv[argc++] = "-daemons";
1171         argv[argc++] = freeargv[freeargc++] = strdup(buf);
1172     }
1173     if (cacheFlagsParam) {
1174         if (cacheFlagsParam & AFSCALL_INIT_MEMCACHE) {
1175             argv[argc++] = "-memcache";
1176         }
1177     }
1178     if (logFile) {
1179         argv[argc++] = "-logfile";
1180         argv[argc++] = logFile;
1181     }
1182
1183     argv[argc] = NULL;
1184
1185     code = uafs_ParseArgs(argc, argv);
1186     usr_assert(code == 0);
1187
1188     for (i = 0; i < freeargc; i++) {
1189         free(freeargv[i]);
1190     }
1191
1192     code = uafs_Run();
1193     usr_assert(code == 0);
1194 }
1195
1196 /**
1197  * Calculate the cacheMountDir used for a specified dir.
1198  *
1199  * @param[in]  dir      Desired mount dir
1200  * @param[out] mountdir On success, contains the literal string that should
1201  *                      be used as the cache mount dir.
1202  * @param[in]  size     The number of bytes allocated in mountdir
1203  *
1204  * @post On success, mountdir begins with a slash, and does not contain two
1205  * slashes adjacent to each other
1206  *
1207  * @return operation status
1208  *  @retval 0 success
1209  *  @retval ENAMETOOLONG the specified dir is too long to fix in the given
1210  *                       mountdir buffer
1211  *  @retval EINVAL the specified dir does not actually specify any meaningful
1212  *                 mount directory
1213  */
1214 static int
1215 calcMountDir(const char *dir, char *mountdir, size_t size)
1216 {
1217     char buf[1024];
1218     char lastchar;
1219     char *p;
1220     int len;
1221
1222     if (dir && strlen(dir) > size-1) {
1223         return ENAMETOOLONG;
1224     }
1225
1226     /*
1227      * Initialize the AFS mount point, default is '/afs'.
1228      * Strip duplicate/trailing slashes from mount point string.
1229      * afs_mountDirLen is set to strlen(afs_mountDir).
1230      */
1231     if (!dir) {
1232         dir = "afs";
1233     }
1234     sprintf(buf, "%s", dir);
1235
1236     mountdir[0] = '/';
1237     len = 1;
1238     for (lastchar = '/', p = &buf[0]; *p != '\0'; p++) {
1239         if (lastchar != '/' || *p != '/') {
1240             mountdir[len++] = lastchar = *p;
1241         }
1242     }
1243     if (lastchar == '/' && len > 1)
1244         len--;
1245     mountdir[len] = '\0';
1246     if (len <= 1) {
1247         return EINVAL;
1248     }
1249
1250     return 0;
1251 }
1252
1253 void
1254 uafs_mount(void) {
1255     int rc;
1256
1257     /*
1258      * Mount the AFS filesystem
1259      */
1260     AFS_GLOCK();
1261     rc = afs_mount(&afs_RootVfs, NULL, NULL);
1262     usr_assert(rc == 0);
1263     rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1264     usr_assert(rc == 0);
1265     AFS_GUNLOCK();
1266
1267     /*
1268      * initialize the current directory to the AFS root
1269      */
1270     afs_CurrentDir = afs_RootVnode;
1271     VN_HOLD(afs_CurrentDir);
1272
1273     return;
1274 }
1275
1276 void
1277 uafs_setMountDir(const char *dir)
1278 {
1279     if (dir) {
1280         int rc;
1281         char tmp_mountDir[1024];
1282
1283         rc = calcMountDir(dir, tmp_mountDir, sizeof(tmp_mountDir));
1284         if (rc) {
1285             afs_warn("Invalid mount dir specification (error %d): %s\n", rc, dir);
1286         } else {
1287             if (strcmp(tmp_mountDir, afs_mountDir) != 0) {
1288                 /* mount dir changed */
1289                 strcpy(afs_mountDir, tmp_mountDir);
1290                 afs_mountDirLen = strlen(afs_mountDir);
1291             }
1292         }
1293     }
1294 }
1295
1296 int
1297 uafs_statvfs(struct statvfs *buf)
1298 {
1299     int rc;
1300
1301     AFS_GLOCK();
1302
1303     rc = afs_statvfs(&afs_RootVfs, buf);
1304
1305     AFS_GUNLOCK();
1306
1307     if (rc) {
1308         errno = rc;
1309         return -1;
1310     }
1311
1312     return 0;
1313 }
1314
1315 void
1316 uafs_Shutdown(void)
1317 {
1318     int rc;
1319
1320     printf("\n");
1321
1322     AFS_GLOCK();
1323     if (afs_CurrentDir) {
1324         VN_RELE(afs_CurrentDir);
1325     }
1326     rc = afs_unmount(&afs_RootVfs);
1327     usr_assert(rc == 0);
1328     AFS_GUNLOCK();
1329
1330     printf("\n");
1331 }
1332
1333 /*
1334  * Donate the current thread to the RX server pool.
1335  */
1336 void
1337 uafs_RxServerProc(void)
1338 {
1339     osi_socket sock;
1340     int threadID;
1341     struct rx_call *newcall = NULL;
1342
1343     rxi_MorePackets(2);         /* alloc more packets */
1344     threadID = rxi_availProcs++;
1345
1346     while (1) {
1347         sock = OSI_NULLSOCKET;
1348         rxi_ServerProc(threadID, newcall, &sock);
1349         if (sock == OSI_NULLSOCKET) {
1350             break;
1351         }
1352         newcall = NULL;
1353         threadID = -1;
1354         rxi_ListenerProc(sock, &threadID, &newcall);
1355         /* assert(threadID != -1); */
1356         /* assert(newcall != NULL); */
1357     }
1358 }
1359
1360 struct syscallThreadArgs {
1361     long syscall;
1362     long afscall;
1363     long param1;
1364     long param2;
1365     long param3;
1366     long param4;
1367 };
1368
1369 void *
1370 syscallThread(void *argp)
1371 {
1372     int i;
1373     struct usr_ucred *crp;
1374     struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1375
1376     /*
1377      * AFS daemons run authenticated
1378      */
1379     get_user_struct()->u_viceid = getuid();
1380     crp = get_user_struct()->u_cred;
1381     afs_set_cr_uid(crp, getuid());
1382     afs_set_cr_ruid(crp, getuid());
1383     crp->cr_suid = getuid();
1384     crp->cr_groups[0] = getgid();
1385     crp->cr_ngroups = 1;
1386     for (i = 1; i < NGROUPS; i++) {
1387         crp->cr_groups[i] = NOGROUP;
1388     }
1389
1390     call_syscall(sysArgsP->syscall, sysArgsP->afscall, sysArgsP->param1,
1391                  sysArgsP->param2, sysArgsP->param3, sysArgsP->param4);
1392
1393     afs_osi_Free(argp, -1);
1394     return 0;
1395 }
1396
1397 int
1398 fork_syscall(long syscall, long afscall, long param1, long param2,
1399              long param3, long param4)
1400 {
1401     usr_thread_t tid;
1402     struct syscallThreadArgs *sysArgsP;
1403
1404     sysArgsP = (struct syscallThreadArgs *)
1405         afs_osi_Alloc(sizeof(struct syscallThreadArgs));
1406     usr_assert(sysArgsP != NULL);
1407     sysArgsP->syscall = syscall;
1408     sysArgsP->afscall = afscall;
1409     sysArgsP->param1 = param1;
1410     sysArgsP->param2 = param2;
1411     sysArgsP->param3 = param3;
1412     sysArgsP->param4 = param4;
1413
1414     usr_thread_create(&tid, syscallThread, sysArgsP);
1415     usr_thread_detach(tid);
1416     return 0;
1417 }
1418
1419 int
1420 call_syscall(long syscall, long afscall, long param1, long param2,
1421              long param3, long param4)
1422 {
1423     int code = 0;
1424     struct a {
1425         long syscall;
1426         long afscall;
1427         long parm1;
1428         long parm2;
1429         long parm3;
1430         long parm4;
1431     } a;
1432
1433     a.syscall = syscall;
1434     a.afscall = afscall;
1435     a.parm1 = param1;
1436     a.parm2 = param2;
1437     a.parm3 = param3;
1438     a.parm4 = param4;
1439
1440     get_user_struct()->u_error = 0;
1441     get_user_struct()->u_ap = (char *)&a;
1442
1443     code = Afs_syscall();
1444     return code;
1445 }
1446
1447 int
1448 uafs_Setup(const char *mount)
1449 {
1450     int rc;
1451     static int inited = 0;
1452
1453     if (inited) {
1454         return EEXIST;
1455     }
1456     inited = 1;
1457
1458     rc = calcMountDir(mount, afs_mountDir, sizeof(afs_mountDir));
1459     if (rc) {
1460         return rc;
1461     }
1462     afs_mountDirLen = strlen(afs_mountDir);
1463
1464     /* initialize global vars and such */
1465     osi_Init();
1466
1467     /* initialize cache manager foo */
1468     afsd_init();
1469
1470     return 0;
1471 }
1472
1473 int
1474 uafs_ParseArgs(int argc, char **argv)
1475 {
1476     return afsd_parse(argc, argv);
1477 }
1478
1479 int
1480 uafs_Run(void)
1481 {
1482     return afsd_run();
1483 }
1484
1485 const char *
1486 uafs_MountDir(void)
1487 {
1488     return afsd_cacheMountDir;
1489 }
1490
1491 int
1492 uafs_SetTokens(char *tbuffer, int tlen)
1493 {
1494     int rc;
1495     struct afs_ioctl iob;
1496     char outbuf[1024];
1497
1498     iob.in = tbuffer;
1499     iob.in_size = tlen;
1500     iob.out = &outbuf[0];
1501     iob.out_size = sizeof(outbuf);
1502
1503     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
1504     if (rc != 0) {
1505         errno = rc;
1506         return -1;
1507     }
1508     return 0;
1509 }
1510
1511 int
1512 uafs_RPCStatsEnableProc(void)
1513 {
1514     int rc;
1515     struct afs_ioctl iob;
1516     afs_int32 flag;
1517
1518     flag = AFSCALL_RXSTATS_ENABLE;
1519     iob.in = (char *)&flag;
1520     iob.in_size = sizeof(afs_int32);
1521     iob.out = NULL;
1522     iob.out_size = 0;
1523     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1524     if (rc != 0) {
1525         errno = rc;
1526         return -1;
1527     }
1528     return rc;
1529 }
1530
1531 int
1532 uafs_RPCStatsDisableProc(void)
1533 {
1534     int rc;
1535     struct afs_ioctl iob;
1536     afs_int32 flag;
1537
1538     flag = AFSCALL_RXSTATS_DISABLE;
1539     iob.in = (char *)&flag;
1540     iob.in_size = sizeof(afs_int32);
1541     iob.out = NULL;
1542     iob.out_size = 0;
1543     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1544     if (rc != 0) {
1545         errno = rc;
1546         return -1;
1547     }
1548     return rc;
1549 }
1550
1551 int
1552 uafs_RPCStatsClearProc(void)
1553 {
1554     int rc;
1555     struct afs_ioctl iob;
1556     afs_int32 flag;
1557
1558     flag = AFSCALL_RXSTATS_CLEAR;
1559     iob.in = (char *)&flag;
1560     iob.in_size = sizeof(afs_int32);
1561     iob.out = NULL;
1562     iob.out_size = 0;
1563     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1564     if (rc != 0) {
1565         errno = rc;
1566         return -1;
1567     }
1568     return rc;
1569 }
1570
1571 int
1572 uafs_RPCStatsEnablePeer(void)
1573 {
1574     int rc;
1575     struct afs_ioctl iob;
1576     afs_int32 flag;
1577
1578     flag = AFSCALL_RXSTATS_ENABLE;
1579     iob.in = (char *)&flag;
1580     iob.in_size = sizeof(afs_int32);
1581     iob.out = NULL;
1582     iob.out_size = 0;
1583     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1584     if (rc != 0) {
1585         errno = rc;
1586         return -1;
1587     }
1588     return rc;
1589 }
1590
1591 int
1592 uafs_RPCStatsDisablePeer(void)
1593 {
1594     int rc;
1595     struct afs_ioctl iob;
1596     afs_int32 flag;
1597
1598     flag = AFSCALL_RXSTATS_DISABLE;
1599     iob.in = (char *)&flag;
1600     iob.in_size = sizeof(afs_int32);
1601     iob.out = NULL;
1602     iob.out_size = 0;
1603     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1604     if (rc != 0) {
1605         errno = rc;
1606         return -1;
1607     }
1608     return rc;
1609 }
1610
1611 int
1612 uafs_RPCStatsClearPeer(void)
1613 {
1614     int rc;
1615     struct afs_ioctl iob;
1616     afs_int32 flag;
1617
1618     flag = AFSCALL_RXSTATS_CLEAR;
1619     iob.in = (char *)&flag;
1620     iob.in_size = sizeof(afs_int32);
1621     iob.out = NULL;
1622     iob.out_size = 0;
1623     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1624     if (rc != 0) {
1625         errno = rc;
1626         return -1;
1627     }
1628     return rc;
1629 }
1630
1631 /*
1632  * Lookup the target of a symbolic link
1633  * Call VN_HOLD on the output vnode if successful.
1634  * Returns zero on success, error code on failure.
1635  * If provided, use a path for confirming we are not linked to ourself.
1636  *
1637  * Note: Caller must hold the AFS global lock.
1638  */
1639 static int
1640 uafs_LookupLinkPath(struct usr_vnode *vp, struct usr_vnode *parentVp,
1641                     char *ppathP, struct usr_vnode **vpp)
1642 {
1643     int code;
1644     int len;
1645     char *pathP;
1646     struct usr_vnode *linkVp;
1647     struct usr_uio uio;
1648     struct iovec iov[1];
1649
1650     AFS_ASSERT_GLOCK();
1651
1652     pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
1653     usr_assert(pathP != NULL);
1654
1655     /*
1656      * set up the uio buffer
1657      */
1658     iov[0].iov_base = pathP;
1659     iov[0].iov_len = MAX_OSI_PATH + 1;
1660     uio.uio_iov = &iov[0];
1661     uio.uio_iovcnt = 1;
1662     uio.uio_offset = 0;
1663     uio.uio_segflg = 0;
1664     uio.uio_fmode = FREAD;
1665     uio.uio_resid = MAX_OSI_PATH + 1;
1666
1667     /*
1668      * Read the link data
1669      */
1670     code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
1671     if (code) {
1672         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1673         return code;
1674     }
1675     len = MAX_OSI_PATH + 1 - uio.uio_resid;
1676     pathP[len] = '\0';
1677
1678     /* are we linked to ourname or ./ourname? ELOOP */
1679     if (ppathP) {
1680         if ((strcmp(pathP, ppathP) == 0) ||
1681             ((pathP[0] == '.') &&
1682              (pathP[1] == '/') &&
1683              (strcmp(&(pathP[2]), ppathP) == 0))) {
1684             return ELOOP;
1685         }
1686     }
1687
1688     /*
1689      * Find the target of the symbolic link
1690      */
1691     code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
1692     if (code) {
1693         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1694         return code;
1695     }
1696
1697     afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1698     *vpp = linkVp;
1699     return 0;
1700 }
1701
1702 /*
1703  * Lookup a file or directory given its path.
1704  * Call VN_HOLD on the output vnode if successful.
1705  * Returns zero on success, error code on failure.
1706  *
1707  * Note: Caller must hold the AFS global lock.
1708  */
1709 int
1710 uafs_LookupName(char *path, struct usr_vnode *parentVp,
1711                 struct usr_vnode **vpp, int follow, int no_eval_mtpt)
1712 {
1713     int code = 0;
1714     int linkCount;
1715     struct usr_vnode *vp;
1716     struct usr_vnode *nextVp;
1717     struct usr_vnode *linkVp;
1718     struct vcache *nextVc;
1719     char *tmpPath;
1720     char *pathP;
1721     char *nextPathP = NULL;
1722
1723     AFS_ASSERT_GLOCK();
1724
1725     /*
1726      * Absolute paths must start with the AFS mount point.
1727      */
1728     if (path[0] != '/') {
1729         vp = parentVp;
1730     } else {
1731         path = uafs_afsPathName(path);
1732         if (path == NULL) {
1733             return ENOENT;
1734         }
1735         vp = afs_RootVnode;
1736     }
1737
1738     /*
1739      * Loop through the path looking for the new directory
1740      */
1741     tmpPath = afs_osi_Alloc(strlen(path) + 1);
1742     usr_assert(tmpPath != NULL);
1743     strcpy(tmpPath, path);
1744     VN_HOLD(vp);
1745     pathP = tmpPath;
1746     while (pathP != NULL && *pathP != '\0') {
1747         usr_assert(*pathP != '/');
1748
1749         /*
1750          * terminate the current component and skip over slashes
1751          */
1752         nextPathP = afs_strchr(pathP, '/');
1753         if (nextPathP != NULL) {
1754             while (*nextPathP == '/') {
1755                 *(nextPathP++) = '\0';
1756             }
1757         }
1758
1759         /*
1760          * Don't call afs_lookup on non-directories
1761          */
1762         if (vp->v_type != VDIR) {
1763             VN_RELE(vp);
1764             afs_osi_Free(tmpPath, strlen(path) + 1);
1765             return ENOTDIR;
1766         }
1767
1768         if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
1769             /*
1770              * The AFS root is its own parent
1771              */
1772             nextVp = afs_RootVnode;
1773         } else {
1774             /*
1775              * We need execute permission to search a directory
1776              */
1777             code = afs_access(VTOAFS(vp), VEXEC, get_user_struct()->u_cred);
1778             if (code != 0) {
1779                 VN_RELE(vp);
1780                 afs_osi_Free(tmpPath, strlen(path) + 1);
1781                 return code;
1782             }
1783
1784             /*
1785              * lookup the next component in the path, we can release the
1786              * subdirectory since we hold the global lock
1787              */
1788             nextVc = NULL;
1789             nextVp = NULL;
1790             if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
1791                 code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
1792             else
1793                 code =
1794                     afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred,
1795                                AFS_LOOKUP_NOEVAL);
1796             if (nextVc)
1797                 nextVp=AFSTOV(nextVc);
1798             if (code != 0) {
1799                 VN_RELE(vp);
1800                 afs_osi_Free(tmpPath, strlen(path) + 1);
1801                 return code;
1802             }
1803         }
1804
1805         /*
1806          * Follow symbolic links for parent directories and
1807          * for leaves when the follow flag is set.
1808          */
1809         if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
1810             linkCount = 0;
1811             while (nextVp->v_type == VLNK) {
1812                 if (++linkCount > MAX_OSI_LINKS) {
1813                     VN_RELE(vp);
1814                     VN_RELE(nextVp);
1815                     afs_osi_Free(tmpPath, strlen(path) + 1);
1816                     return code;
1817                 }
1818                 code = uafs_LookupLinkPath(nextVp, vp, NULL, &linkVp);
1819                 if (code) {
1820                     VN_RELE(vp);
1821                     VN_RELE(nextVp);
1822                     afs_osi_Free(tmpPath, strlen(path) + 1);
1823                     return code;
1824                 }
1825                 VN_RELE(nextVp);
1826                 nextVp = linkVp;
1827             }
1828         }
1829
1830         VN_RELE(vp);
1831         vp = nextVp;
1832         pathP = nextPathP;
1833     }
1834
1835     /*
1836      * Special case, nextPathP is non-null if pathname ends in slash
1837      */
1838     if (nextPathP != NULL && vp->v_type != VDIR) {
1839         VN_RELE(vp);
1840         afs_osi_Free(tmpPath, strlen(path) + 1);
1841         return ENOTDIR;
1842     }
1843
1844     afs_osi_Free(tmpPath, strlen(path) + 1);
1845     *vpp = vp;
1846     return 0;
1847 }
1848
1849 int
1850 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
1851                 struct usr_vnode **vpp)
1852 {
1853     return uafs_LookupLinkPath(vp, parentVp, NULL, vpp);
1854 }
1855
1856 /*
1857  * Lookup the parent of a file or directory given its path
1858  * Call VN_HOLD on the output vnode if successful.
1859  * Returns zero on success, error code on failure.
1860  *
1861  * Note: Caller must hold the AFS global lock.
1862  */
1863 int
1864 uafs_LookupParent(char *path, struct usr_vnode **vpp)
1865 {
1866     int len;
1867     int code;
1868     char *pathP;
1869     struct usr_vnode *parentP;
1870
1871     AFS_ASSERT_GLOCK();
1872
1873     /*
1874      * Absolute path names must start with the AFS mount point.
1875      */
1876     if (*path == '/') {
1877         pathP = uafs_afsPathName(path);
1878         if (pathP == NULL) {
1879             return ENOENT;
1880         }
1881     }
1882
1883     /*
1884      * Find the length of the parent path
1885      */
1886     len = strlen(path);
1887     while (len > 0 && path[len - 1] == '/') {
1888         len--;
1889     }
1890     if (len == 0) {
1891         return EINVAL;
1892     }
1893     while (len > 0 && path[len - 1] != '/') {
1894         len--;
1895     }
1896     if (len == 0) {
1897         return EINVAL;
1898     }
1899
1900     pathP = afs_osi_Alloc(len);
1901     usr_assert(pathP != NULL);
1902     memcpy(pathP, path, len - 1);
1903     pathP[len - 1] = '\0';
1904
1905     /*
1906      * look up the parent
1907      */
1908     code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
1909     afs_osi_Free(pathP, len);
1910     if (code != 0) {
1911         return code;
1912     }
1913     if (parentP->v_type != VDIR) {
1914         VN_RELE(parentP);
1915         return ENOTDIR;
1916     }
1917
1918     *vpp = parentP;
1919     return 0;
1920 }
1921
1922 /*
1923  * Return a pointer to the first character in the last component
1924  * of a pathname
1925  */
1926 char *
1927 uafs_LastPath(char *path)
1928 {
1929     int len;
1930
1931     len = strlen(path);
1932     while (len > 0 && path[len - 1] == '/') {
1933         len--;
1934     }
1935     while (len > 0 && path[len - 1] != '/') {
1936         len--;
1937     }
1938     if (len == 0) {
1939         return NULL;
1940     }
1941     return path + len;
1942 }
1943
1944 /*
1945  * Set the working directory.
1946  */
1947 int
1948 uafs_chdir(char *path)
1949 {
1950     int retval;
1951     AFS_GLOCK();
1952     retval = uafs_chdir_r(path);
1953     AFS_GUNLOCK();
1954     return retval;
1955 }
1956
1957 int
1958 uafs_chdir_r(char *path)
1959 {
1960     int code;
1961     struct vnode *dirP;
1962
1963     code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
1964     if (code != 0) {
1965         errno = code;
1966         return -1;
1967     }
1968     if (dirP->v_type != VDIR) {
1969         VN_RELE(dirP);
1970         errno = ENOTDIR;
1971         return -1;
1972     }
1973     VN_RELE(afs_CurrentDir);
1974     afs_CurrentDir = dirP;
1975     return 0;
1976 }
1977
1978 /*
1979  * Create a directory.
1980  */
1981 int
1982 uafs_mkdir(char *path, int mode)
1983 {
1984     int retval;
1985     AFS_GLOCK();
1986     retval = uafs_mkdir_r(path, mode);
1987     AFS_GUNLOCK();
1988     return retval;
1989 }
1990
1991 int
1992 uafs_mkdir_r(char *path, int mode)
1993 {
1994     int code;
1995     char *nameP;
1996     struct vnode *parentP;
1997     struct vcache *dirP;
1998     struct usr_vattr attrs;
1999
2000     if (uafs_IsRoot(path)) {
2001         return EACCES;
2002     }
2003
2004     /*
2005      * Look up the parent directory.
2006      */
2007     nameP = uafs_LastPath(path);
2008     if (nameP != NULL) {
2009         code = uafs_LookupParent(path, &parentP);
2010         if (code != 0) {
2011             errno = code;
2012             return -1;
2013         }
2014     } else {
2015         parentP = afs_CurrentDir;
2016         nameP = path;
2017         VN_HOLD(parentP);
2018     }
2019
2020     /*
2021      * Make sure the directory has at least one character
2022      */
2023     if (*nameP == '\0') {
2024         VN_RELE(parentP);
2025         errno = EINVAL;
2026         return -1;
2027     }
2028
2029     /*
2030      * Create the directory
2031      */
2032     usr_vattr_null(&attrs);
2033     attrs.va_type = VREG;
2034     attrs.va_mode = mode;
2035     attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2036     attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2037     dirP = NULL;
2038     code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, get_user_struct()->u_cred);
2039     VN_RELE(parentP);
2040     if (code != 0) {
2041         errno = code;
2042         return -1;
2043     }
2044     VN_RELE(AFSTOV(dirP));
2045     return 0;
2046 }
2047
2048 /*
2049  * Return 1 if path is the AFS root, otherwise return 0
2050  */
2051 int
2052 uafs_IsRoot(char *path)
2053 {
2054     while (*path == '/' && *(path + 1) == '/') {
2055         path++;
2056     }
2057     if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2058         return 0;
2059     }
2060     path += afs_mountDirLen;
2061     while (*path == '/') {
2062         path++;
2063     }
2064     if (*path != '\0') {
2065         return 0;
2066     }
2067     return 1;
2068 }
2069
2070 /*
2071  * Open a file
2072  * Note: file name may not end in a slash.
2073  */
2074 int
2075 uafs_open(char *path, int flags, int mode)
2076 {
2077     int retval;
2078     AFS_GLOCK();
2079     retval = uafs_open_r(path, flags, mode);
2080     AFS_GUNLOCK();
2081     return retval;
2082 }
2083
2084 int
2085 uafs_open_r(char *path, int flags, int mode)
2086 {
2087     int fd;
2088     int code;
2089     int openFlags;
2090     int fileMode;
2091     struct usr_vnode *fileP;
2092     struct usr_vnode *dirP;
2093     struct usr_vattr attrs;
2094     char *nameP;
2095
2096     struct vcache* vc;
2097
2098     if (uafs_IsRoot(path)) {
2099         fileP = afs_RootVnode;
2100         VN_HOLD(fileP);
2101     } else {
2102         /*
2103          * Look up the parent directory.
2104          */
2105         nameP = uafs_LastPath(path);
2106         if (nameP != NULL) {
2107             code = uafs_LookupParent(path, &dirP);
2108             if (code != 0) {
2109                 errno = code;
2110                 return -1;
2111             }
2112         } else {
2113             dirP = afs_CurrentDir;
2114             nameP = path;
2115             VN_HOLD(dirP);
2116         }
2117
2118         /*
2119          * Make sure the filename has at least one character
2120          */
2121         if (*nameP == '\0') {
2122             VN_RELE(dirP);
2123             errno = EINVAL;
2124             return -1;
2125         }
2126
2127         /*
2128          * Get the VNODE for this file
2129          */
2130         if (flags & O_CREAT) {
2131             usr_vattr_null(&attrs);
2132             attrs.va_type = VREG;
2133             attrs.va_mode = mode;
2134             attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2135             attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2136             if (flags & O_TRUNC) {
2137                 attrs.va_size = 0;
2138             }
2139             fileP = NULL;
2140             vc=VTOAFS(fileP);
2141             code =
2142                 afs_create(VTOAFS(dirP), nameP, &attrs,
2143                            (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2144                            &vc, get_user_struct()->u_cred);
2145             VN_RELE(dirP);
2146             if (code != 0) {
2147                 errno = code;
2148                 return -1;
2149             }
2150             fileP = AFSTOV(vc);
2151         } else {
2152             fileP = NULL;
2153             code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2154             VN_RELE(dirP);
2155             if (code != 0) {
2156                 errno = code;
2157                 return -1;
2158             }
2159
2160             /*
2161              * Check whether we have access to this file
2162              */
2163             fileMode = 0;
2164             if (flags & (O_RDONLY | O_RDWR)) {
2165                 fileMode |= VREAD;
2166             }
2167             if (flags & (O_WRONLY | O_RDWR)) {
2168                 fileMode |= VWRITE;
2169             }
2170             if (!fileMode)
2171                 fileMode = VREAD;       /* since O_RDONLY is 0 */
2172             code = afs_access(VTOAFS(fileP), fileMode, get_user_struct()->u_cred);
2173             if (code != 0) {
2174                 VN_RELE(fileP);
2175                 errno = code;
2176                 return -1;
2177             }
2178
2179             /*
2180              * Get the file attributes, all we need is the size
2181              */
2182             code = afs_getattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2183             if (code != 0) {
2184                 VN_RELE(fileP);
2185                 errno = code;
2186                 return -1;
2187             }
2188         }
2189     }
2190
2191     /*
2192      * Setup the open flags
2193      */
2194     openFlags = 0;
2195     if (flags & O_TRUNC) {
2196         openFlags |= FTRUNC;
2197     }
2198     if (flags & O_APPEND) {
2199         openFlags |= FAPPEND;
2200     }
2201     if (flags & O_SYNC) {
2202         openFlags |= FSYNC;
2203     }
2204     if (flags & O_SYNC) {
2205         openFlags |= FSYNC;
2206     }
2207     if (flags & (O_RDONLY | O_RDWR)) {
2208         openFlags |= FREAD;
2209     }
2210     if (flags & (O_WRONLY | O_RDWR)) {
2211         openFlags |= FWRITE;
2212     }
2213     if ((openFlags & (FREAD | FWRITE)) == 0) {
2214         /* O_RDONLY is 0, so ... */
2215         openFlags |= FREAD;
2216     }
2217
2218     /*
2219      * Truncate if necessary
2220      */
2221     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2222         usr_vattr_null(&attrs);
2223         attrs.va_mask = ATTR_SIZE;
2224         attrs.va_size = 0;
2225         code = afs_setattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2226         if (code != 0) {
2227             VN_RELE(fileP);
2228             errno = code;
2229             return -1;
2230         }
2231     }
2232
2233     vc=VTOAFS(fileP);   
2234     /*
2235      * do the open
2236      */
2237     code = afs_open(&vc, openFlags, get_user_struct()->u_cred);
2238     if (code != 0) {
2239         VN_RELE(fileP);
2240         errno = code;
2241         return -1;
2242     }
2243
2244     /*
2245      * Put the vnode pointer into the file table
2246      */
2247     for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2248         if (afs_FileTable[fd] == NULL) {
2249             afs_FileTable[fd] = fileP;
2250             afs_FileFlags[fd] = openFlags;
2251             if (flags & O_APPEND) {
2252                 afs_FileOffsets[fd] = attrs.va_size;
2253             } else {
2254                 afs_FileOffsets[fd] = 0;
2255             }
2256             break;
2257         }
2258     }
2259     if (fd == MAX_OSI_FILES) {
2260         VN_RELE(fileP);
2261         errno = ENFILE;
2262         return -1;
2263     }
2264
2265     return fd;
2266 }
2267
2268 /*
2269  * Create a file
2270  */
2271 int
2272 uafs_creat(char *path, int mode)
2273 {
2274     int rc;
2275     rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2276     return rc;
2277 }
2278
2279 int
2280 uafs_creat_r(char *path, int mode)
2281 {
2282     int rc;
2283     rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2284     return rc;
2285 }
2286
2287 /*
2288  * Write to a file
2289  */
2290 int
2291 uafs_write(int fd, char *buf, int len)
2292 {
2293     int retval;
2294     AFS_GLOCK();
2295     retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
2296     AFS_GUNLOCK();
2297     return retval;
2298 }
2299
2300 int
2301 uafs_pwrite(int fd, char *buf, int len, off_t offset)
2302 {
2303     int retval;
2304     AFS_GLOCK();
2305     retval = uafs_pwrite_r(fd, buf, len, offset);
2306     AFS_GUNLOCK();
2307     return retval;
2308 }
2309
2310 int
2311 uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
2312 {
2313     int code;
2314     struct usr_uio uio;
2315     struct iovec iov[1];
2316     struct usr_vnode *fileP;
2317
2318     /*
2319      * Make sure this is an open file
2320      */
2321     fileP = afs_FileTable[fd];
2322     if (fileP == NULL) {
2323         errno = EBADF;
2324         return -1;
2325     }
2326
2327     /*
2328      * set up the uio buffer
2329      */
2330     iov[0].iov_base = buf;
2331     iov[0].iov_len = len;
2332     uio.uio_iov = &iov[0];
2333     uio.uio_iovcnt = 1;
2334     uio.uio_offset = offset;
2335     uio.uio_segflg = 0;
2336     uio.uio_fmode = FWRITE;
2337     uio.uio_resid = len;
2338
2339     /*
2340      * do the write
2341      */
2342
2343     code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], get_user_struct()->u_cred, 0);
2344     if (code) {
2345         errno = code;
2346         return -1;
2347     }
2348
2349     afs_FileOffsets[fd] = uio.uio_offset;
2350     return (len - uio.uio_resid);
2351 }
2352
2353 /*
2354  * Read from a file
2355  */
2356 int
2357 uafs_read(int fd, char *buf, int len)
2358 {
2359     int retval;
2360     AFS_GLOCK();
2361     retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
2362     AFS_GUNLOCK();
2363     return retval;
2364 }
2365
2366 int
2367 uafs_pread_nocache(int fd, char *buf, int len, off_t offset)
2368 {
2369     int retval;
2370     AFS_GLOCK();
2371     retval = uafs_pread_nocache_r(fd, buf, len, offset);
2372     AFS_GUNLOCK();
2373     return retval;
2374 }
2375
2376 int
2377 uafs_pread_nocache_r(int fd, char *buf, int len, off_t offset)
2378 {
2379     int code;
2380     struct iovec iov[1];
2381     struct usr_vnode *fileP;
2382     struct nocache_read_request *bparms;
2383     struct usr_uio uio;
2384
2385     /*
2386      * Make sure this is an open file
2387      */
2388     fileP = afs_FileTable[fd];
2389     if (fileP == NULL) {
2390         errno = EBADF;
2391         return -1;
2392     }
2393
2394     /* these get freed in PrefetchNoCache, so... */
2395     bparms = afs_osi_Alloc(sizeof(struct nocache_read_request));
2396
2397     code = afs_CreateReq(&bparms->areq, get_user_struct()->u_cred);
2398     if (code) {
2399         afs_DestroyReq(bparms->areq);
2400         afs_osi_Free(bparms, sizeof(struct nocache_read_request));
2401         errno = code;
2402         return -1;
2403     }
2404
2405     bparms->auio = &uio;
2406     bparms->offset = offset;
2407     bparms->length = len;
2408
2409     /*
2410      * set up the uio buffer
2411      */
2412     iov[0].iov_base = buf;
2413     iov[0].iov_len = len;
2414     uio.uio_iov = &iov[0];
2415     uio.uio_iovcnt = 1;
2416     uio.uio_offset = offset;
2417     uio.uio_segflg = 0;
2418     uio.uio_fmode = FREAD;
2419     uio.uio_resid = len;
2420
2421     /*
2422      * do the read
2423      */
2424     code = afs_PrefetchNoCache(VTOAFS(fileP), get_user_struct()->u_cred,
2425                                bparms);
2426
2427     if (code) {
2428         errno = code;
2429         return -1;
2430     }
2431
2432     afs_FileOffsets[fd] = uio.uio_offset;
2433     return (len - uio.uio_resid);
2434 }
2435
2436 int
2437 uafs_pread(int fd, char *buf, int len, off_t offset)
2438 {
2439     int retval;
2440     AFS_GLOCK();
2441     retval = uafs_pread_r(fd, buf, len, offset);
2442     AFS_GUNLOCK();
2443     return retval;
2444 }
2445
2446 int
2447 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2448 {
2449     int code;
2450     struct usr_uio uio;
2451     struct iovec iov[1];
2452     struct usr_vnode *fileP;
2453
2454     /*
2455      * Make sure this is an open file
2456      */
2457     fileP = afs_FileTable[fd];
2458     if (fileP == NULL) {
2459         errno = EBADF;
2460         return -1;
2461     }
2462
2463     /*
2464      * set up the uio buffer
2465      */
2466     iov[0].iov_base = buf;
2467     iov[0].iov_len = len;
2468     uio.uio_iov = &iov[0];
2469     uio.uio_iovcnt = 1;
2470     uio.uio_offset = offset;
2471     uio.uio_segflg = 0;
2472     uio.uio_fmode = FREAD;
2473     uio.uio_resid = len;
2474
2475     /*
2476      * do the read
2477      */
2478     code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0);
2479     if (code) {
2480         errno = code;
2481         return -1;
2482     }
2483
2484     afs_FileOffsets[fd] = uio.uio_offset;
2485     return (len - uio.uio_resid);
2486 }
2487
2488 /*
2489  * Copy the attributes of a file into a stat structure.
2490  *
2491  * NOTE: Caller must hold the global AFS lock.
2492  */
2493 int
2494 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2495 {
2496     int code;
2497     struct usr_vattr attrs;
2498
2499     AFS_ASSERT_GLOCK();
2500
2501     /*
2502      * Get the attributes
2503      */
2504     code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2505     if (code != 0) {
2506         return code;
2507     }
2508
2509     /*
2510      * Copy the attributes, zero fields that aren't set
2511      */
2512     memset((void *)stats, 0, sizeof(struct stat));
2513     stats->st_dev = -1;
2514     stats->st_ino = attrs.va_nodeid;
2515     stats->st_mode = attrs.va_mode;
2516     stats->st_nlink = attrs.va_nlink;
2517     stats->st_uid = attrs.va_uid;
2518     stats->st_gid = attrs.va_gid;
2519     stats->st_rdev = attrs.va_rdev;
2520     stats->st_size = attrs.va_size;
2521     stats->st_atime = attrs.va_atime.tv_sec;
2522     stats->st_mtime = attrs.va_mtime.tv_sec;
2523     stats->st_ctime = attrs.va_ctime.tv_sec;
2524     /* preserve dv if possible */
2525 #if defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2526     stats->st_atimespec.tv_nsec = attrs.va_atime.tv_usec * 1000;
2527     stats->st_mtimespec.tv_nsec = attrs.va_mtime.tv_usec * 1000;
2528     stats->st_ctimespec.tv_nsec = attrs.va_ctime.tv_usec * 1000;
2529 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
2530     stats->st_atimensec = attrs.va_atime.tv_usec * 1000;
2531     stats->st_mtimensec = attrs.va_mtime.tv_usec * 1000;
2532     stats->st_ctimensec = attrs.va_ctime.tv_usec * 1000;
2533 #endif
2534     stats->st_blksize = attrs.va_blocksize;
2535     stats->st_blocks = attrs.va_blocks;
2536
2537     return 0;
2538 }
2539
2540 /*
2541  * Get the attributes of a file, do follow links
2542  */
2543 int
2544 uafs_stat(char *path, struct stat *buf)
2545 {
2546     int retval;
2547     AFS_GLOCK();
2548     retval = uafs_stat_r(path, buf);
2549     AFS_GUNLOCK();
2550     return retval;
2551 }
2552
2553 int
2554 uafs_stat_r(char *path, struct stat *buf)
2555 {
2556     int code;
2557     struct vnode *vp;
2558
2559     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2560     if (code != 0) {
2561         errno = code;
2562         return -1;
2563     }
2564     code = uafs_GetAttr(vp, buf);
2565     VN_RELE(vp);
2566     if (code) {
2567         errno = code;
2568         return -1;
2569     }
2570     return 0;
2571 }
2572
2573 /*
2574  * Get the attributes of a file, don't follow links
2575  */
2576 int
2577 uafs_lstat(char *path, struct stat *buf)
2578 {
2579     int retval;
2580     AFS_GLOCK();
2581     retval = uafs_lstat_r(path, buf);
2582     AFS_GUNLOCK();
2583     return retval;
2584 }
2585
2586 int
2587 uafs_lstat_r(char *path, struct stat *buf)
2588 {
2589     int code;
2590     struct vnode *vp;
2591
2592     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2593     if (code != 0) {
2594         errno = code;
2595         return -1;
2596     }
2597     code = uafs_GetAttr(vp, buf);
2598     VN_RELE(vp);
2599     if (code) {
2600         errno = code;
2601         return -1;
2602     }
2603     return 0;
2604 }
2605
2606 /*
2607  * Get the attributes of an open file
2608  */
2609 int
2610 uafs_fstat(int fd, struct stat *buf)
2611 {
2612     int retval;
2613     AFS_GLOCK();
2614     retval = uafs_fstat_r(fd, buf);
2615     AFS_GUNLOCK();
2616     return retval;
2617 }
2618
2619 int
2620 uafs_fstat_r(int fd, struct stat *buf)
2621 {
2622     int code;
2623     struct vnode *vp;
2624
2625     vp = afs_FileTable[fd];
2626     if (vp == NULL) {
2627         errno = EBADF;
2628         return -1;
2629     }
2630     code = uafs_GetAttr(vp, buf);
2631     if (code) {
2632         errno = code;
2633         return -1;
2634     }
2635     return 0;
2636 }
2637
2638 /*
2639  * change the permissions on a file
2640  */
2641 int
2642 uafs_chmod(char *path, int mode)
2643 {
2644     int retval;
2645     AFS_GLOCK();
2646     retval = uafs_chmod_r(path, mode);
2647     AFS_GUNLOCK();
2648     return retval;
2649 }
2650
2651 int
2652 uafs_chmod_r(char *path, int mode)
2653 {
2654     int code;
2655     struct vnode *vp;
2656     struct usr_vattr attrs;
2657
2658     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2659     if (code != 0) {
2660         errno = code;
2661         return -1;
2662     }
2663     usr_vattr_null(&attrs);
2664     attrs.va_mask = ATTR_MODE;
2665     attrs.va_mode = mode;
2666     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2667     VN_RELE(vp);
2668     if (code != 0) {
2669         errno = code;
2670         return -1;
2671     }
2672     return 0;
2673 }
2674
2675 /*
2676  * change the permissions on an open file
2677  */
2678 int
2679 uafs_fchmod(int fd, int mode)
2680 {
2681     int retval;
2682     AFS_GLOCK();
2683     retval = uafs_fchmod_r(fd, mode);
2684     AFS_GUNLOCK();
2685     return retval;
2686 }
2687
2688 int
2689 uafs_fchmod_r(int fd, int mode)
2690 {
2691     int code;
2692     struct vnode *vp;
2693     struct usr_vattr attrs;
2694
2695     vp = afs_FileTable[fd];
2696     if (vp == NULL) {
2697         errno = EBADF;
2698         return -1;
2699     }
2700     usr_vattr_null(&attrs);
2701     attrs.va_mask = ATTR_MODE;
2702     attrs.va_mode = mode;
2703     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2704     if (code != 0) {
2705         errno = code;
2706         return -1;
2707     }
2708     return 0;
2709 }
2710
2711 /*
2712  * truncate a file
2713  */
2714 int
2715 uafs_truncate(char *path, int length)
2716 {
2717     int retval;
2718     AFS_GLOCK();
2719     retval = uafs_truncate_r(path, length);
2720     AFS_GUNLOCK();
2721     return retval;
2722 }
2723
2724 int
2725 uafs_truncate_r(char *path, int length)
2726 {
2727     int code;
2728     struct vnode *vp;
2729     struct usr_vattr attrs;
2730
2731     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2732     if (code != 0) {
2733         errno = code;
2734         return -1;
2735     }
2736     usr_vattr_null(&attrs);
2737     attrs.va_mask = ATTR_SIZE;
2738     attrs.va_size = length;
2739     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2740     VN_RELE(vp);
2741     if (code != 0) {
2742         errno = code;
2743         return -1;
2744     }
2745     return 0;
2746 }
2747
2748 /*
2749  * truncate an open file
2750  */
2751 int
2752 uafs_ftruncate(int fd, int length)
2753 {
2754     int retval;
2755     AFS_GLOCK();
2756     retval = uafs_ftruncate_r(fd, length);
2757     AFS_GUNLOCK();
2758     return retval;
2759 }
2760
2761 int
2762 uafs_ftruncate_r(int fd, int length)
2763 {
2764     int code;
2765     struct vnode *vp;
2766     struct usr_vattr attrs;
2767
2768     vp = afs_FileTable[fd];
2769     if (vp == NULL) {
2770         errno = EBADF;
2771         return -1;
2772     }
2773     usr_vattr_null(&attrs);
2774     attrs.va_mask = ATTR_SIZE;
2775     attrs.va_size = length;
2776     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2777     if (code != 0) {
2778         errno = code;
2779         return -1;
2780     }
2781     return 0;
2782 }
2783
2784 /*
2785  * set the read/write file pointer of an open file
2786  */
2787 int
2788 uafs_lseek(int fd, int offset, int whence)
2789 {
2790     int retval;
2791     AFS_GLOCK();
2792     retval = uafs_lseek_r(fd, offset, whence);
2793     AFS_GUNLOCK();
2794     return retval;
2795 }
2796
2797 int
2798 uafs_lseek_r(int fd, int offset, int whence)
2799 {
2800     int code;
2801     int newpos;
2802     struct usr_vattr attrs;
2803     struct usr_vnode *vp;
2804
2805     vp = afs_FileTable[fd];
2806     if (vp == NULL) {
2807         errno = EBADF;
2808         return -1;
2809     }
2810     switch (whence) {
2811     case SEEK_CUR:
2812         newpos = afs_FileOffsets[fd] + offset;
2813         break;
2814     case SEEK_SET:
2815         newpos = offset;
2816         break;
2817     case SEEK_END:
2818         code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2819         if (code != 0) {
2820             errno = code;
2821             return -1;
2822         }
2823         newpos = attrs.va_size + offset;
2824         break;
2825     default:
2826         errno = EINVAL;
2827         return -1;
2828     }
2829     if (newpos < 0) {
2830         errno = EINVAL;
2831         return -1;
2832     }
2833     afs_FileOffsets[fd] = newpos;
2834     return newpos;
2835 }
2836
2837 /*
2838  * sync a file
2839  */
2840 int
2841 uafs_fsync(int fd)
2842 {
2843     int retval;
2844     AFS_GLOCK();
2845     retval = uafs_fsync_r(fd);
2846     AFS_GUNLOCK();
2847     return retval;
2848 }
2849
2850 int
2851 uafs_fsync_r(int fd)
2852 {
2853     int code;
2854     struct usr_vnode *fileP;
2855
2856
2857     fileP = afs_FileTable[fd];
2858     if (fileP == NULL) {
2859         errno = EBADF;
2860         return -1;
2861     }
2862
2863     code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
2864     if (code != 0) {
2865         errno = code;
2866         return -1;
2867     }
2868
2869     return 0;
2870 }
2871
2872 /*
2873  * Close a file
2874  */
2875 int
2876 uafs_close(int fd)
2877 {
2878     int retval;
2879     AFS_GLOCK();
2880     retval = uafs_close_r(fd);
2881     AFS_GUNLOCK();
2882     return retval;
2883 }
2884
2885 int
2886 uafs_close_r(int fd)
2887 {
2888     int code;
2889     struct usr_vnode *fileP;
2890
2891     fileP = afs_FileTable[fd];
2892     if (fileP == NULL) {
2893         errno = EBADF;
2894         return -1;
2895     }
2896     afs_FileTable[fd] = NULL;
2897
2898     code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
2899     VN_RELE(fileP);
2900     if (code != 0) {
2901         errno = code;
2902         return -1;
2903     }
2904
2905     return 0;
2906 }
2907
2908 /*
2909  * Create a hard link from the source to the target
2910  * Note: file names may not end in a slash.
2911  */
2912 int
2913 uafs_link(char *existing, char *new)
2914 {
2915     int retval;
2916     AFS_GLOCK();
2917     retval = uafs_link_r(existing, new);
2918     AFS_GUNLOCK();
2919     return retval;
2920 }
2921
2922 int
2923 uafs_link_r(char *existing, char *new)
2924 {
2925     int code;
2926     struct usr_vnode *existP;
2927     struct usr_vnode *dirP;
2928     char *nameP;
2929
2930     if (uafs_IsRoot(new)) {
2931         return EACCES;
2932     }
2933
2934     /*
2935      * Look up the existing node.
2936      */
2937     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
2938     if (code != 0) {
2939         errno = code;
2940         return -1;
2941     }
2942
2943     /*
2944      * Look up the parent directory.
2945      */
2946     nameP = uafs_LastPath(new);
2947     if (nameP != NULL) {
2948         code = uafs_LookupParent(new, &dirP);
2949         if (code != 0) {
2950             VN_RELE(existP);
2951             errno = code;
2952             return -1;
2953         }
2954     } else {
2955         dirP = afs_CurrentDir;
2956         nameP = new;
2957         VN_HOLD(dirP);
2958     }
2959
2960     /*
2961      * Make sure the filename has at least one character
2962      */
2963     if (*nameP == '\0') {
2964         VN_RELE(existP);
2965         VN_RELE(dirP);
2966         errno = EINVAL;
2967         return -1;
2968     }
2969
2970     /*
2971      * Create the link
2972      */
2973     code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
2974     VN_RELE(existP);
2975     VN_RELE(dirP);
2976     if (code != 0) {
2977         errno = code;
2978         return -1;
2979     }
2980     return 0;
2981 }
2982
2983 /*
2984  * Create a symbolic link from the source to the target
2985  * Note: file names may not end in a slash.
2986  */
2987 int
2988 uafs_symlink(char *target, char *source)
2989 {
2990     int retval;
2991     AFS_GLOCK();
2992     retval = uafs_symlink_r(target, source);
2993     AFS_GUNLOCK();
2994     return retval;
2995 }
2996
2997 int
2998 uafs_symlink_r(char *target, char *source)
2999 {
3000     int code;
3001     struct usr_vnode *dirP;
3002     struct usr_vattr attrs;
3003     char *nameP;
3004
3005     if (uafs_IsRoot(source)) {
3006         return EACCES;
3007     }
3008
3009     /*
3010      * Look up the parent directory.
3011      */
3012     nameP = uafs_LastPath(source);
3013     if (nameP != NULL) {
3014         code = uafs_LookupParent(source, &dirP);
3015         if (code != 0) {
3016             errno = code;
3017             return -1;
3018         }
3019     } else {
3020         dirP = afs_CurrentDir;
3021         nameP = source;
3022         VN_HOLD(dirP);
3023     }
3024
3025     /*
3026      * Make sure the filename has at least one character
3027      */
3028     if (*nameP == '\0') {
3029         VN_RELE(dirP);
3030         errno = EINVAL;
3031         return -1;
3032     }
3033
3034     /*
3035      * Create the link
3036      */
3037     usr_vattr_null(&attrs);
3038     attrs.va_type = VLNK;
3039     attrs.va_mode = 0777;
3040     attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
3041     attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
3042     code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, NULL,
3043                        get_user_struct()->u_cred);
3044     VN_RELE(dirP);
3045     if (code != 0) {
3046         errno = code;
3047         return -1;
3048     }
3049     return 0;
3050 }
3051
3052 /*
3053  * Read a symbolic link into the buffer
3054  */
3055 int
3056 uafs_readlink(char *path, char *buf, int len)
3057 {
3058     int retval;
3059     AFS_GLOCK();
3060     retval = uafs_readlink_r(path, buf, len);
3061     AFS_GUNLOCK();
3062     return retval;
3063 }
3064
3065 int
3066 uafs_readlink_r(char *path, char *buf, int len)
3067 {
3068     int code;
3069     struct usr_vnode *vp;
3070     struct usr_uio uio;
3071     struct iovec iov[1];
3072
3073     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3074     if (code != 0) {
3075         errno = code;
3076         return -1;
3077     }
3078
3079     if (vp->v_type != VLNK) {
3080         VN_RELE(vp);
3081         errno = EINVAL;
3082         return -1;
3083     }
3084
3085     /*
3086      * set up the uio buffer
3087      */
3088     iov[0].iov_base = buf;
3089     iov[0].iov_len = len;
3090     uio.uio_iov = &iov[0];
3091     uio.uio_iovcnt = 1;
3092     uio.uio_offset = 0;
3093     uio.uio_segflg = 0;
3094     uio.uio_fmode = FREAD;
3095     uio.uio_resid = len;
3096
3097     /*
3098      * Read the the link
3099      */
3100     code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3101     VN_RELE(vp);
3102     if (code) {
3103         errno = code;
3104         return -1;
3105     }
3106
3107     /*
3108      * return the number of bytes read
3109      */
3110     return (len - uio.uio_resid);
3111 }
3112
3113 /*
3114  * Remove a file (or directory)
3115  * Note: file name may not end in a slash.
3116  */
3117 int
3118 uafs_unlink(char *path)
3119 {
3120     int retval;
3121     AFS_GLOCK();
3122     retval = uafs_unlink_r(path);
3123     AFS_GUNLOCK();
3124     return retval;
3125 }
3126
3127 int
3128 uafs_unlink_r(char *path)
3129 {
3130     int code;
3131     struct usr_vnode *dirP;
3132     char *nameP;
3133
3134     if (uafs_IsRoot(path)) {
3135         return EACCES;
3136     }
3137
3138     /*
3139      * Look up the parent directory.
3140      */
3141     nameP = uafs_LastPath(path);
3142     if (nameP != NULL) {
3143         code = uafs_LookupParent(path, &dirP);
3144         if (code != 0) {
3145             errno = code;
3146             return -1;
3147         }
3148     } else {
3149         dirP = afs_CurrentDir;
3150         nameP = path;
3151         VN_HOLD(dirP);
3152     }
3153
3154     /*
3155      * Make sure the filename has at least one character
3156      */
3157     if (*nameP == '\0') {
3158         VN_RELE(dirP);
3159         errno = EINVAL;
3160         return -1;
3161     }
3162
3163     /*
3164      * Remove the file
3165      */
3166     code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3167     VN_RELE(dirP);
3168     if (code != 0) {
3169         errno = code;
3170         return -1;
3171     }
3172
3173     return 0;
3174 }
3175
3176 /*
3177  * Rename a file (or directory)
3178  */
3179 int
3180 uafs_rename(char *old, char *new)
3181 {
3182     int retval;
3183     AFS_GLOCK();
3184     retval = uafs_rename_r(old, new);
3185     AFS_GUNLOCK();
3186     return retval;
3187 }
3188
3189 int
3190 uafs_rename_r(char *old, char *new)
3191 {
3192     int code;
3193     char *onameP;
3194     char *nnameP;
3195     struct usr_vnode *odirP;
3196     struct usr_vnode *ndirP;
3197
3198     if (uafs_IsRoot(new)) {
3199         return EACCES;
3200     }
3201
3202     /*
3203      * Look up the parent directories.
3204      */
3205     onameP = uafs_LastPath(old);
3206     if (onameP != NULL) {
3207         code = uafs_LookupParent(old, &odirP);
3208         if (code != 0) {
3209             errno = code;
3210             return -1;
3211         }
3212     } else {
3213         odirP = afs_CurrentDir;
3214         onameP = old;
3215         VN_HOLD(odirP);
3216     }
3217     nnameP = uafs_LastPath(new);
3218     if (nnameP != NULL) {
3219         code = uafs_LookupParent(new, &ndirP);
3220         if (code != 0) {
3221             errno = code;
3222             return -1;
3223         }
3224     } else {
3225         ndirP = afs_CurrentDir;
3226         nnameP = new;
3227         VN_HOLD(ndirP);
3228     }
3229
3230     /*
3231      * Make sure the filename has at least one character
3232      */
3233     if (*onameP == '\0' || *nnameP == '\0') {
3234         VN_RELE(odirP);
3235         VN_RELE(ndirP);
3236         errno = EINVAL;
3237         return -1;
3238     }
3239
3240     /*
3241      * Rename the file
3242      */
3243     code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
3244     VN_RELE(odirP);
3245     VN_RELE(ndirP);
3246     if (code != 0) {
3247         errno = code;
3248         return -1;
3249     }
3250
3251     return 0;
3252 }
3253
3254 /*
3255  * Remove a or directory
3256  * Note: file name may not end in a slash.
3257  */
3258 int
3259 uafs_rmdir(char *path)
3260 {
3261     int retval;
3262     AFS_GLOCK();
3263     retval = uafs_rmdir_r(path);
3264     AFS_GUNLOCK();
3265     return retval;
3266 }
3267
3268 int
3269 uafs_rmdir_r(char *path)
3270 {
3271     int code;
3272     struct usr_vnode *dirP;
3273     char *nameP;
3274
3275     if (uafs_IsRoot(path)) {
3276         return EACCES;
3277     }
3278
3279     /*
3280      * Look up the parent directory.
3281      */
3282     nameP = uafs_LastPath(path);
3283     if (nameP != NULL) {
3284         code = uafs_LookupParent(path, &dirP);
3285         if (code != 0) {
3286             errno = code;
3287             return -1;
3288         }
3289     } else {
3290         dirP = afs_CurrentDir;
3291         nameP = path;
3292         VN_HOLD(dirP);
3293     }
3294
3295     /*
3296      * Make sure the directory name has at least one character
3297      */
3298     if (*nameP == '\0') {
3299         VN_RELE(dirP);
3300         errno = EINVAL;
3301         return -1;
3302     }
3303
3304     /*
3305      * Remove the directory
3306      */
3307     code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3308     VN_RELE(dirP);
3309     if (code != 0) {
3310         errno = code;
3311         return -1;
3312     }
3313
3314     return 0;
3315 }
3316
3317 /*
3318  * Flush a file from the AFS cache
3319  */
3320 int
3321 uafs_FlushFile(char *path)
3322 {
3323     int code;
3324     struct afs_ioctl iob;
3325
3326     iob.in = NULL;
3327     iob.in_size = 0;
3328     iob.out = NULL;
3329     iob.out_size = 0;
3330
3331     code =
3332         call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3333                      0);
3334     if (code != 0) {
3335         errno = code;
3336         return -1;
3337     }
3338
3339     return 0;
3340 }
3341
3342 int
3343 uafs_FlushFile_r(char *path)
3344 {
3345     int retval;
3346     AFS_GUNLOCK();
3347     retval = uafs_FlushFile(path);
3348     AFS_GLOCK();
3349     return retval;
3350 }
3351
3352 /*
3353  * open a directory
3354  */
3355 usr_DIR *
3356 uafs_opendir(char *path)
3357 {
3358     usr_DIR *retval;
3359     AFS_GLOCK();
3360     retval = uafs_opendir_r(path);
3361     AFS_GUNLOCK();
3362     return retval;
3363 }
3364
3365 usr_DIR *
3366 uafs_opendir_r(char *path)
3367 {
3368     usr_DIR *dirp;
3369     struct usr_vnode *fileP;
3370     int fd;
3371
3372     /*
3373      * Open the directory for reading
3374      */
3375     fd = uafs_open_r(path, O_RDONLY, 0);
3376     if (fd < 0) {
3377         return NULL;
3378     }
3379
3380     fileP = afs_FileTable[fd];
3381     if (fileP == NULL) {
3382         return NULL;
3383     }
3384
3385     if (fileP->v_type != VDIR) {
3386         uafs_close_r(fd);
3387         errno = ENOTDIR;
3388         return NULL;
3389     }
3390
3391     /*
3392      * Set up the directory structures
3393      */
3394     dirp = afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3395                          sizeof(struct usr_dirent));
3396     usr_assert(dirp != NULL);
3397     dirp->dd_buf = (char *)(dirp + 1);
3398     dirp->dd_fd = fd;
3399     dirp->dd_loc = 0;
3400     dirp->dd_size = 0;
3401
3402     errno = 0;
3403     return dirp;
3404 }
3405
3406 /*
3407  * Read directory entries into a file system independent format.
3408  * This routine was developed to support AFS cache consistency testing.
3409  * You should use uafs_readdir instead.
3410  */
3411 int
3412 uafs_getdents(int fd, struct min_direct *buf, int len)
3413 {
3414     int retval;
3415     AFS_GLOCK();
3416     retval = uafs_getdents_r(fd, buf, len);
3417     AFS_GUNLOCK();
3418     return retval;
3419 }
3420
3421 int
3422 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3423 {
3424     int code;
3425     struct usr_uio uio;
3426     struct usr_vnode *vp;
3427     struct iovec iov[1];
3428
3429     /*
3430      * Make sure this is an open file
3431      */
3432     vp = afs_FileTable[fd];
3433     if (vp == NULL) {
3434         AFS_GUNLOCK();
3435         errno = EBADF;
3436         return -1;
3437     }
3438
3439     /*
3440      * set up the uio buffer
3441      */
3442     iov[0].iov_base = (char *)buf;
3443     iov[0].iov_len = len;
3444     uio.uio_iov = &iov[0];
3445     uio.uio_iovcnt = 1;
3446     uio.uio_offset = afs_FileOffsets[fd];
3447     uio.uio_segflg = 0;
3448     uio.uio_fmode = FREAD;
3449     uio.uio_resid = len;
3450
3451     /*
3452      * read the next chunk from the directory
3453      */
3454     code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3455     if (code != 0) {
3456         errno = code;
3457         return -1;
3458     }
3459
3460     afs_FileOffsets[fd] = uio.uio_offset;
3461     return (len - uio.uio_resid);
3462 }
3463
3464 /*
3465  * read from a directory (names only)
3466  */
3467 struct usr_dirent *
3468 uafs_readdir(usr_DIR * dirp)
3469 {
3470     struct usr_dirent *retval;
3471     AFS_GLOCK();
3472     retval = uafs_readdir_r(dirp);
3473     AFS_GUNLOCK();
3474     return retval;
3475 }
3476
3477 struct usr_dirent *
3478 uafs_readdir_r(usr_DIR * dirp)
3479 {
3480     int code;
3481     int len;
3482     struct usr_uio uio;
3483     struct usr_vnode *vp;
3484     struct iovec iov[1];
3485     struct usr_dirent *direntP;
3486     struct min_direct *directP;
3487
3488     if (!dirp) {
3489         errno = EBADF;
3490         return NULL;
3491     }
3492
3493     /*
3494      * Make sure this is an open file
3495      */
3496     vp = afs_FileTable[dirp->dd_fd];
3497     if (vp == NULL) {
3498         errno = EBADF;
3499         return NULL;
3500     }
3501
3502     /*
3503      * If there are no entries in the stream buffer
3504      * then read another chunk
3505      */
3506     directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3507     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3508         /*
3509          * set up the uio buffer
3510          */
3511         iov[0].iov_base = dirp->dd_buf;
3512         iov[0].iov_len = USR_DIRSIZE;
3513         uio.uio_iov = &iov[0];
3514         uio.uio_iovcnt = 1;
3515         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3516         uio.uio_segflg = 0;
3517         uio.uio_fmode = FREAD;
3518         uio.uio_resid = USR_DIRSIZE;
3519
3520         /*
3521          * read the next chunk from the directory
3522          */
3523         code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3524         if (code != 0) {
3525             errno = code;
3526             return NULL;
3527         }
3528         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3529
3530         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3531         dirp->dd_loc = 0;
3532         directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3533     }
3534
3535     /*
3536      * Check for end of file
3537      */
3538     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3539         errno = 0;
3540         return NULL;
3541     }
3542     len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3543     usr_assert(len <= dirp->dd_size);
3544
3545     /*
3546      * Copy the next entry into the usr_dirent structure and advance
3547      */
3548     direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3549     direntP->d_ino = directP->d_fileno;
3550     direntP->d_off = direntP->d_reclen;
3551     direntP->d_reclen =
3552         sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3553     memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3554     direntP->d_name[directP->d_namlen] = '\0';
3555     dirp->dd_loc += len;
3556     dirp->dd_size -= len;
3557
3558     return direntP;
3559 }
3560
3561 /*
3562  * Close a directory
3563  */
3564 int
3565 uafs_closedir(usr_DIR * dirp)
3566 {
3567     int retval;
3568     AFS_GLOCK();
3569     retval = uafs_closedir_r(dirp);
3570     AFS_GUNLOCK();
3571     return retval;
3572 }
3573
3574 int
3575 uafs_closedir_r(usr_DIR * dirp)
3576 {
3577     int fd;
3578     int rc;
3579
3580     if (!dirp) {
3581         errno = EBADF;
3582         return -1;
3583     }
3584
3585     fd = dirp->dd_fd;
3586     afs_osi_Free((char *)dirp,
3587                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3588     rc = uafs_close_r(fd);
3589     return rc;
3590 }
3591
3592 /*
3593  * Destroy AFS credentials from the kernel cache
3594  */
3595 int
3596 uafs_unlog(void)
3597 {
3598     int code;
3599
3600     usr_mutex_lock(&osi_authenticate_lock);
3601     code = ktc_ForgetAllTokens();
3602     usr_mutex_unlock(&osi_authenticate_lock);
3603     return code;
3604 }
3605
3606 int
3607 uafs_unlog_r(void)
3608 {
3609     int retval;
3610     AFS_GUNLOCK();
3611     retval = uafs_unlog();
3612     AFS_GLOCK();
3613     return retval;
3614 }
3615
3616 /*
3617  * Strip the AFS mount point from a pathname string. Return
3618  * NULL if the path is a relative pathname or if the path
3619  * doesn't start with the AFS mount point string.
3620  */
3621 char *
3622 uafs_afsPathName(char *path)
3623 {
3624     char *p;
3625     char lastchar;
3626     int i;
3627
3628     if (path[0] != '/')
3629         return NULL;
3630     lastchar = '/';
3631     for (i = 1, p = path + 1; *p != '\0'; p++) {
3632         /* Ignore duplicate slashes */
3633         if (*p == '/' && lastchar == '/')
3634             continue;
3635         /* Is this a subdirectory of the AFS mount point? */
3636         if (afs_mountDir[i] == '\0' && *p == '/') {
3637             /* strip leading slashes */
3638             while (*(++p) == '/');
3639             return p;
3640         }
3641         /* Reject paths that are not within AFS */
3642         if (*p != afs_mountDir[i])
3643             return NULL;
3644         lastchar = *p;
3645         i++;
3646     }
3647     /* Is this the AFS mount point? */
3648     if (afs_mountDir[i] == '\0') {
3649         usr_assert(*p == '\0');
3650         return p;
3651     }
3652     return NULL;
3653 }
3654
3655 /*
3656  * uafs_getcellstatus
3657  * get the cell status
3658  */
3659 int
3660 uafs_getcellstatus(char *cell, afs_int32 * status)
3661 {
3662     int rc;
3663     struct afs_ioctl iob;
3664
3665     iob.in = cell;
3666     iob.in_size = strlen(cell) + 1;
3667     iob.out = 0;
3668     iob.out_size = 0;
3669
3670     rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
3671                       (long)&iob, 0, 0);
3672
3673     if (rc < 0) {
3674         errno = rc;
3675         return -1;
3676     }
3677
3678     *status = (intptr_t)iob.out;
3679     return 0;
3680 }
3681
3682 /*
3683  * uafs_getvolquota
3684  * Get quota of volume associated with path
3685  */
3686 int
3687 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
3688 {
3689     int rc;
3690     struct afs_ioctl iob;
3691     VolumeStatus status;
3692
3693     iob.in = 0;
3694     iob.in_size = 0;
3695     iob.out = (char *)&status;
3696     iob.out_size = sizeof status;
3697
3698     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
3699                       0, 0);
3700
3701     if (rc != 0) {
3702         errno = rc;
3703         return -1;
3704     }
3705
3706     *BlocksInUse = status.BlocksInUse;
3707     *MaxQuota = status.MaxQuota;
3708     return 0;
3709 }
3710
3711 /*
3712  * uafs_setvolquota
3713  * Set quota of volume associated with path
3714  */
3715 int
3716 uafs_setvolquota(char *path, afs_int32 MaxQuota)
3717 {
3718     int rc;
3719     struct afs_ioctl iob;
3720     VolumeStatus status = { 0 };
3721
3722     iob.in = (char *)&status;
3723     iob.in_size = sizeof status;
3724     iob.out = 0;
3725     iob.out_size = 0;
3726
3727     status.MaxQuota = MaxQuota;
3728     status.MinQuota = -1;
3729
3730     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
3731                       0, 0);
3732
3733     if (rc != 0) {
3734         errno = rc;
3735         return -1;
3736     }
3737
3738     return 0;
3739 }
3740
3741 /*
3742  * uafs_statmountpoint
3743  * Determine whether a dir. is a mount point or not
3744  * return 1 if mount point, 0 if not
3745  */
3746 int
3747 uafs_statmountpoint(char *path)
3748 {
3749     int retval;
3750
3751     AFS_GLOCK();
3752     retval = uafs_statmountpoint_r(path);
3753     AFS_GUNLOCK();
3754     return retval;
3755 }
3756
3757 int
3758 uafs_statmountpoint_r(char *path)
3759 {
3760     int code;
3761     struct vnode *vp;
3762     struct vcache *avc;
3763     int r;
3764
3765     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
3766     if (code != 0) {
3767         errno = code;
3768         return -1;
3769     }
3770
3771     avc = VTOAFS(vp);
3772
3773     r = avc->mvstat;
3774     VN_RELE(vp);
3775     return r;
3776 }
3777
3778 /*
3779  * uafs_getRights
3780  * Get a list of rights for the current user on path.
3781  */
3782 int
3783 uafs_access(char *path, int flags)
3784 {
3785     int code;
3786     struct vnode *vp;
3787     int fileMode = 0;
3788
3789     if (flags & R_OK) {
3790         fileMode |= VREAD;
3791     }
3792     if (flags & W_OK) {
3793         fileMode |= VWRITE;
3794     }
3795     if (flags & X_OK) {
3796         fileMode |= VEXEC;
3797     }
3798
3799     AFS_GLOCK();
3800     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3801     if (code != 0) {
3802         errno = code;
3803         AFS_GUNLOCK();
3804         return -1;
3805     }
3806
3807     code = afs_access(VTOAFS(vp), fileMode, get_user_struct()->u_cred);
3808     VN_RELE(vp);
3809
3810     if (code != 0)
3811         errno = code;
3812
3813     AFS_GUNLOCK();
3814     return code ? -1 : 0;
3815 }
3816
3817 /*
3818  * uafs_getRights
3819  * Get a list of rights for the current user on path.
3820  */
3821 int
3822 uafs_getRights(char *path)
3823 {
3824     int code;
3825     struct vnode *vp;
3826     int afs_rights;
3827
3828     AFS_GLOCK();
3829     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3830     if (code != 0) {
3831         errno = code;
3832         AFS_GUNLOCK();
3833         return -1;
3834     }
3835
3836     afs_rights =
3837         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
3838         | PRSFS_LOCK | PRSFS_ADMINISTER;
3839
3840     afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
3841
3842     AFS_GUNLOCK();
3843     return afs_rights;
3844 }
3845 #endif /* UKERNEL */