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