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