58e7b305779580a427ad69c84e03b42e60249e57
[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     bparms->areq = afs_osi_Alloc(sizeof(struct vrequest));
2409
2410     code = afs_InitReq(bparms->areq, get_user_struct()->u_cred);
2411     if (code) {
2412         afs_osi_Free(bparms->areq, sizeof(struct vrequest));
2413         afs_osi_Free(bparms, sizeof(struct nocache_read_request));
2414         errno = code;
2415         return -1;
2416     }
2417
2418     bparms->auio = &uio;
2419     bparms->offset = offset;
2420     bparms->length = len;
2421
2422     /*
2423      * set up the uio buffer
2424      */
2425     iov[0].iov_base = buf;
2426     iov[0].iov_len = len;
2427     uio.uio_iov = &iov[0];
2428     uio.uio_iovcnt = 1;
2429     uio.uio_offset = offset;
2430     uio.uio_segflg = 0;
2431     uio.uio_fmode = FREAD;
2432     uio.uio_resid = len;
2433
2434     /*
2435      * do the read
2436      */
2437     code = afs_PrefetchNoCache(VTOAFS(fileP), get_user_struct()->u_cred,
2438                                bparms);
2439
2440     if (code) {
2441         errno = code;
2442         return -1;
2443     }
2444
2445     afs_FileOffsets[fd] = uio.uio_offset;
2446     return (len - uio.uio_resid);
2447 }
2448
2449 int
2450 uafs_pread(int fd, char *buf, int len, off_t offset)
2451 {
2452     int retval;
2453     AFS_GLOCK();
2454     retval = uafs_pread_r(fd, buf, len, offset);
2455     AFS_GUNLOCK();
2456     return retval;
2457 }
2458
2459 int
2460 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2461 {
2462     int code;
2463     struct usr_uio uio;
2464     struct iovec iov[1];
2465     struct usr_vnode *fileP;
2466
2467     /*
2468      * Make sure this is an open file
2469      */
2470     fileP = afs_FileTable[fd];
2471     if (fileP == NULL) {
2472         errno = EBADF;
2473         return -1;
2474     }
2475
2476     /*
2477      * set up the uio buffer
2478      */
2479     iov[0].iov_base = buf;
2480     iov[0].iov_len = len;
2481     uio.uio_iov = &iov[0];
2482     uio.uio_iovcnt = 1;
2483     uio.uio_offset = offset;
2484     uio.uio_segflg = 0;
2485     uio.uio_fmode = FREAD;
2486     uio.uio_resid = len;
2487
2488     /*
2489      * do the read
2490      */
2491     code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0);
2492     if (code) {
2493         errno = code;
2494         return -1;
2495     }
2496
2497     afs_FileOffsets[fd] = uio.uio_offset;
2498     return (len - uio.uio_resid);
2499 }
2500
2501 /*
2502  * Copy the attributes of a file into a stat structure.
2503  *
2504  * NOTE: Caller must hold the global AFS lock.
2505  */
2506 int
2507 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2508 {
2509     int code;
2510     struct usr_vattr attrs;
2511
2512     AFS_ASSERT_GLOCK();
2513
2514     /*
2515      * Get the attributes
2516      */
2517     code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2518     if (code != 0) {
2519         return code;
2520     }
2521
2522     /*
2523      * Copy the attributes, zero fields that aren't set
2524      */
2525     memset((void *)stats, 0, sizeof(struct stat));
2526     stats->st_dev = -1;
2527     stats->st_ino = attrs.va_nodeid;
2528     stats->st_mode = attrs.va_mode;
2529     stats->st_nlink = attrs.va_nlink;
2530     stats->st_uid = attrs.va_uid;
2531     stats->st_gid = attrs.va_gid;
2532     stats->st_rdev = attrs.va_rdev;
2533     stats->st_size = attrs.va_size;
2534     stats->st_atime = attrs.va_atime.tv_sec;
2535     stats->st_mtime = attrs.va_mtime.tv_sec;
2536     stats->st_ctime = attrs.va_ctime.tv_sec;
2537     /* preserve dv if possible */
2538 #if defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2539     stats->st_atimespec.tv_nsec = attrs.va_atime.tv_usec * 1000;
2540     stats->st_mtimespec.tv_nsec = attrs.va_mtime.tv_usec * 1000;
2541     stats->st_ctimespec.tv_nsec = attrs.va_ctime.tv_usec * 1000;
2542 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
2543     stats->st_atimensec = attrs.va_atime.tv_usec * 1000;
2544     stats->st_mtimensec = attrs.va_mtime.tv_usec * 1000;
2545     stats->st_ctimensec = attrs.va_ctime.tv_usec * 1000;
2546 #endif
2547     stats->st_blksize = attrs.va_blocksize;
2548     stats->st_blocks = attrs.va_blocks;
2549
2550     return 0;
2551 }
2552
2553 /*
2554  * Get the attributes of a file, do follow links
2555  */
2556 int
2557 uafs_stat(char *path, struct stat *buf)
2558 {
2559     int retval;
2560     AFS_GLOCK();
2561     retval = uafs_stat_r(path, buf);
2562     AFS_GUNLOCK();
2563     return retval;
2564 }
2565
2566 int
2567 uafs_stat_r(char *path, struct stat *buf)
2568 {
2569     int code;
2570     struct vnode *vp;
2571
2572     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2573     if (code != 0) {
2574         errno = code;
2575         return -1;
2576     }
2577     code = uafs_GetAttr(vp, buf);
2578     VN_RELE(vp);
2579     if (code) {
2580         errno = code;
2581         return -1;
2582     }
2583     return 0;
2584 }
2585
2586 /*
2587  * Get the attributes of a file, don't follow links
2588  */
2589 int
2590 uafs_lstat(char *path, struct stat *buf)
2591 {
2592     int retval;
2593     AFS_GLOCK();
2594     retval = uafs_lstat_r(path, buf);
2595     AFS_GUNLOCK();
2596     return retval;
2597 }
2598
2599 int
2600 uafs_lstat_r(char *path, struct stat *buf)
2601 {
2602     int code;
2603     struct vnode *vp;
2604
2605     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2606     if (code != 0) {
2607         errno = code;
2608         return -1;
2609     }
2610     code = uafs_GetAttr(vp, buf);
2611     VN_RELE(vp);
2612     if (code) {
2613         errno = code;
2614         return -1;
2615     }
2616     return 0;
2617 }
2618
2619 /*
2620  * Get the attributes of an open file
2621  */
2622 int
2623 uafs_fstat(int fd, struct stat *buf)
2624 {
2625     int retval;
2626     AFS_GLOCK();
2627     retval = uafs_fstat_r(fd, buf);
2628     AFS_GUNLOCK();
2629     return retval;
2630 }
2631
2632 int
2633 uafs_fstat_r(int fd, struct stat *buf)
2634 {
2635     int code;
2636     struct vnode *vp;
2637
2638     vp = afs_FileTable[fd];
2639     if (vp == NULL) {
2640         errno = EBADF;
2641         return -1;
2642     }
2643     code = uafs_GetAttr(vp, buf);
2644     if (code) {
2645         errno = code;
2646         return -1;
2647     }
2648     return 0;
2649 }
2650
2651 /*
2652  * change the permissions on a file
2653  */
2654 int
2655 uafs_chmod(char *path, int mode)
2656 {
2657     int retval;
2658     AFS_GLOCK();
2659     retval = uafs_chmod_r(path, mode);
2660     AFS_GUNLOCK();
2661     return retval;
2662 }
2663
2664 int
2665 uafs_chmod_r(char *path, int mode)
2666 {
2667     int code;
2668     struct vnode *vp;
2669     struct usr_vattr attrs;
2670
2671     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2672     if (code != 0) {
2673         errno = code;
2674         return -1;
2675     }
2676     usr_vattr_null(&attrs);
2677     attrs.va_mask = ATTR_MODE;
2678     attrs.va_mode = mode;
2679     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2680     VN_RELE(vp);
2681     if (code != 0) {
2682         errno = code;
2683         return -1;
2684     }
2685     return 0;
2686 }
2687
2688 /*
2689  * change the permissions on an open file
2690  */
2691 int
2692 uafs_fchmod(int fd, int mode)
2693 {
2694     int retval;
2695     AFS_GLOCK();
2696     retval = uafs_fchmod_r(fd, mode);
2697     AFS_GUNLOCK();
2698     return retval;
2699 }
2700
2701 int
2702 uafs_fchmod_r(int fd, int mode)
2703 {
2704     int code;
2705     struct vnode *vp;
2706     struct usr_vattr attrs;
2707
2708     vp = afs_FileTable[fd];
2709     if (vp == NULL) {
2710         errno = EBADF;
2711         return -1;
2712     }
2713     usr_vattr_null(&attrs);
2714     attrs.va_mask = ATTR_MODE;
2715     attrs.va_mode = mode;
2716     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2717     if (code != 0) {
2718         errno = code;
2719         return -1;
2720     }
2721     return 0;
2722 }
2723
2724 /*
2725  * truncate a file
2726  */
2727 int
2728 uafs_truncate(char *path, int length)
2729 {
2730     int retval;
2731     AFS_GLOCK();
2732     retval = uafs_truncate_r(path, length);
2733     AFS_GUNLOCK();
2734     return retval;
2735 }
2736
2737 int
2738 uafs_truncate_r(char *path, int length)
2739 {
2740     int code;
2741     struct vnode *vp;
2742     struct usr_vattr attrs;
2743
2744     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2745     if (code != 0) {
2746         errno = code;
2747         return -1;
2748     }
2749     usr_vattr_null(&attrs);
2750     attrs.va_mask = ATTR_SIZE;
2751     attrs.va_size = length;
2752     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2753     VN_RELE(vp);
2754     if (code != 0) {
2755         errno = code;
2756         return -1;
2757     }
2758     return 0;
2759 }
2760
2761 /*
2762  * truncate an open file
2763  */
2764 int
2765 uafs_ftruncate(int fd, int length)
2766 {
2767     int retval;
2768     AFS_GLOCK();
2769     retval = uafs_ftruncate_r(fd, length);
2770     AFS_GUNLOCK();
2771     return retval;
2772 }
2773
2774 int
2775 uafs_ftruncate_r(int fd, int length)
2776 {
2777     int code;
2778     struct vnode *vp;
2779     struct usr_vattr attrs;
2780
2781     vp = afs_FileTable[fd];
2782     if (vp == NULL) {
2783         errno = EBADF;
2784         return -1;
2785     }
2786     usr_vattr_null(&attrs);
2787     attrs.va_mask = ATTR_SIZE;
2788     attrs.va_size = length;
2789     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2790     if (code != 0) {
2791         errno = code;
2792         return -1;
2793     }
2794     return 0;
2795 }
2796
2797 /*
2798  * set the read/write file pointer of an open file
2799  */
2800 int
2801 uafs_lseek(int fd, int offset, int whence)
2802 {
2803     int retval;
2804     AFS_GLOCK();
2805     retval = uafs_lseek_r(fd, offset, whence);
2806     AFS_GUNLOCK();
2807     return retval;
2808 }
2809
2810 int
2811 uafs_lseek_r(int fd, int offset, int whence)
2812 {
2813     int code;
2814     int newpos;
2815     struct usr_vattr attrs;
2816     struct usr_vnode *vp;
2817
2818     vp = afs_FileTable[fd];
2819     if (vp == NULL) {
2820         errno = EBADF;
2821         return -1;
2822     }
2823     switch (whence) {
2824     case SEEK_CUR:
2825         newpos = afs_FileOffsets[fd] + offset;
2826         break;
2827     case SEEK_SET:
2828         newpos = offset;
2829         break;
2830     case SEEK_END:
2831         code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2832         if (code != 0) {
2833             errno = code;
2834             return -1;
2835         }
2836         newpos = attrs.va_size + offset;
2837         break;
2838     default:
2839         errno = EINVAL;
2840         return -1;
2841     }
2842     if (newpos < 0) {
2843         errno = EINVAL;
2844         return -1;
2845     }
2846     afs_FileOffsets[fd] = newpos;
2847     return newpos;
2848 }
2849
2850 /*
2851  * sync a file
2852  */
2853 int
2854 uafs_fsync(int fd)
2855 {
2856     int retval;
2857     AFS_GLOCK();
2858     retval = uafs_fsync_r(fd);
2859     AFS_GUNLOCK();
2860     return retval;
2861 }
2862
2863 int
2864 uafs_fsync_r(int fd)
2865 {
2866     int code;
2867     struct usr_vnode *fileP;
2868
2869
2870     fileP = afs_FileTable[fd];
2871     if (fileP == NULL) {
2872         errno = EBADF;
2873         return -1;
2874     }
2875
2876     code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
2877     if (code != 0) {
2878         errno = code;
2879         return -1;
2880     }
2881
2882     return 0;
2883 }
2884
2885 /*
2886  * Close a file
2887  */
2888 int
2889 uafs_close(int fd)
2890 {
2891     int retval;
2892     AFS_GLOCK();
2893     retval = uafs_close_r(fd);
2894     AFS_GUNLOCK();
2895     return retval;
2896 }
2897
2898 int
2899 uafs_close_r(int fd)
2900 {
2901     int code;
2902     struct usr_vnode *fileP;
2903
2904     fileP = afs_FileTable[fd];
2905     if (fileP == NULL) {
2906         errno = EBADF;
2907         return -1;
2908     }
2909     afs_FileTable[fd] = NULL;
2910
2911     code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
2912     VN_RELE(fileP);
2913     if (code != 0) {
2914         errno = code;
2915         return -1;
2916     }
2917
2918     return 0;
2919 }
2920
2921 /*
2922  * Create a hard link from the source to the target
2923  * Note: file names may not end in a slash.
2924  */
2925 int
2926 uafs_link(char *existing, char *new)
2927 {
2928     int retval;
2929     AFS_GLOCK();
2930     retval = uafs_link_r(existing, new);
2931     AFS_GUNLOCK();
2932     return retval;
2933 }
2934
2935 int
2936 uafs_link_r(char *existing, char *new)
2937 {
2938     int code;
2939     struct usr_vnode *existP;
2940     struct usr_vnode *dirP;
2941     char *nameP;
2942
2943     if (uafs_IsRoot(new)) {
2944         return EACCES;
2945     }
2946
2947     /*
2948      * Look up the existing node.
2949      */
2950     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
2951     if (code != 0) {
2952         errno = code;
2953         return -1;
2954     }
2955
2956     /*
2957      * Look up the parent directory.
2958      */
2959     nameP = uafs_LastPath(new);
2960     if (nameP != NULL) {
2961         code = uafs_LookupParent(new, &dirP);
2962         if (code != 0) {
2963             VN_RELE(existP);
2964             errno = code;
2965             return -1;
2966         }
2967     } else {
2968         dirP = afs_CurrentDir;
2969         nameP = new;
2970         VN_HOLD(dirP);
2971     }
2972
2973     /*
2974      * Make sure the filename has at least one character
2975      */
2976     if (*nameP == '\0') {
2977         VN_RELE(existP);
2978         VN_RELE(dirP);
2979         errno = EINVAL;
2980         return -1;
2981     }
2982
2983     /*
2984      * Create the link
2985      */
2986     code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
2987     VN_RELE(existP);
2988     VN_RELE(dirP);
2989     if (code != 0) {
2990         errno = code;
2991         return -1;
2992     }
2993     return 0;
2994 }
2995
2996 /*
2997  * Create a symbolic link from the source to the target
2998  * Note: file names may not end in a slash.
2999  */
3000 int
3001 uafs_symlink(char *target, char *source)
3002 {
3003     int retval;
3004     AFS_GLOCK();
3005     retval = uafs_symlink_r(target, source);
3006     AFS_GUNLOCK();
3007     return retval;
3008 }
3009
3010 int
3011 uafs_symlink_r(char *target, char *source)
3012 {
3013     int code;
3014     struct usr_vnode *dirP;
3015     struct usr_vattr attrs;
3016     char *nameP;
3017
3018     if (uafs_IsRoot(source)) {
3019         return EACCES;
3020     }
3021
3022     /*
3023      * Look up the parent directory.
3024      */
3025     nameP = uafs_LastPath(source);
3026     if (nameP != NULL) {
3027         code = uafs_LookupParent(source, &dirP);
3028         if (code != 0) {
3029             errno = code;
3030             return -1;
3031         }
3032     } else {
3033         dirP = afs_CurrentDir;
3034         nameP = source;
3035         VN_HOLD(dirP);
3036     }
3037
3038     /*
3039      * Make sure the filename has at least one character
3040      */
3041     if (*nameP == '\0') {
3042         VN_RELE(dirP);
3043         errno = EINVAL;
3044         return -1;
3045     }
3046
3047     /*
3048      * Create the link
3049      */
3050     usr_vattr_null(&attrs);
3051     attrs.va_type = VLNK;
3052     attrs.va_mode = 0777;
3053     attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
3054     attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
3055     code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, NULL,
3056                        get_user_struct()->u_cred);
3057     VN_RELE(dirP);
3058     if (code != 0) {
3059         errno = code;
3060         return -1;
3061     }
3062     return 0;
3063 }
3064
3065 /*
3066  * Read a symbolic link into the buffer
3067  */
3068 int
3069 uafs_readlink(char *path, char *buf, int len)
3070 {
3071     int retval;
3072     AFS_GLOCK();
3073     retval = uafs_readlink_r(path, buf, len);
3074     AFS_GUNLOCK();
3075     return retval;
3076 }
3077
3078 int
3079 uafs_readlink_r(char *path, char *buf, int len)
3080 {
3081     int code;
3082     struct usr_vnode *vp;
3083     struct usr_uio uio;
3084     struct iovec iov[1];
3085
3086     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3087     if (code != 0) {
3088         errno = code;
3089         return -1;
3090     }
3091
3092     if (vp->v_type != VLNK) {
3093         VN_RELE(vp);
3094         errno = EINVAL;
3095         return -1;
3096     }
3097
3098     /*
3099      * set up the uio buffer
3100      */
3101     iov[0].iov_base = buf;
3102     iov[0].iov_len = len;
3103     uio.uio_iov = &iov[0];
3104     uio.uio_iovcnt = 1;
3105     uio.uio_offset = 0;
3106     uio.uio_segflg = 0;
3107     uio.uio_fmode = FREAD;
3108     uio.uio_resid = len;
3109
3110     /*
3111      * Read the the link
3112      */
3113     code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3114     VN_RELE(vp);
3115     if (code) {
3116         errno = code;
3117         return -1;
3118     }
3119
3120     /*
3121      * return the number of bytes read
3122      */
3123     return (len - uio.uio_resid);
3124 }
3125
3126 /*
3127  * Remove a file (or directory)
3128  * Note: file name may not end in a slash.
3129  */
3130 int
3131 uafs_unlink(char *path)
3132 {
3133     int retval;
3134     AFS_GLOCK();
3135     retval = uafs_unlink_r(path);
3136     AFS_GUNLOCK();
3137     return retval;
3138 }
3139
3140 int
3141 uafs_unlink_r(char *path)
3142 {
3143     int code;
3144     struct usr_vnode *dirP;
3145     char *nameP;
3146
3147     if (uafs_IsRoot(path)) {
3148         return EACCES;
3149     }
3150
3151     /*
3152      * Look up the parent directory.
3153      */
3154     nameP = uafs_LastPath(path);
3155     if (nameP != NULL) {
3156         code = uafs_LookupParent(path, &dirP);
3157         if (code != 0) {
3158             errno = code;
3159             return -1;
3160         }
3161     } else {
3162         dirP = afs_CurrentDir;
3163         nameP = path;
3164         VN_HOLD(dirP);
3165     }
3166
3167     /*
3168      * Make sure the filename has at least one character
3169      */
3170     if (*nameP == '\0') {
3171         VN_RELE(dirP);
3172         errno = EINVAL;
3173         return -1;
3174     }
3175
3176     /*
3177      * Remove the file
3178      */
3179     code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3180     VN_RELE(dirP);
3181     if (code != 0) {
3182         errno = code;
3183         return -1;
3184     }
3185
3186     return 0;
3187 }
3188
3189 /*
3190  * Rename a file (or directory)
3191  */
3192 int
3193 uafs_rename(char *old, char *new)
3194 {
3195     int retval;
3196     AFS_GLOCK();
3197     retval = uafs_rename_r(old, new);
3198     AFS_GUNLOCK();
3199     return retval;
3200 }
3201
3202 int
3203 uafs_rename_r(char *old, char *new)
3204 {
3205     int code;
3206     char *onameP;
3207     char *nnameP;
3208     struct usr_vnode *odirP;
3209     struct usr_vnode *ndirP;
3210
3211     if (uafs_IsRoot(new)) {
3212         return EACCES;
3213     }
3214
3215     /*
3216      * Look up the parent directories.
3217      */
3218     onameP = uafs_LastPath(old);
3219     if (onameP != NULL) {
3220         code = uafs_LookupParent(old, &odirP);
3221         if (code != 0) {
3222             errno = code;
3223             return -1;
3224         }
3225     } else {
3226         odirP = afs_CurrentDir;
3227         onameP = old;
3228         VN_HOLD(odirP);
3229     }
3230     nnameP = uafs_LastPath(new);
3231     if (nnameP != NULL) {
3232         code = uafs_LookupParent(new, &ndirP);
3233         if (code != 0) {
3234             errno = code;
3235             return -1;
3236         }
3237     } else {
3238         ndirP = afs_CurrentDir;
3239         nnameP = new;
3240         VN_HOLD(ndirP);
3241     }
3242
3243     /*
3244      * Make sure the filename has at least one character
3245      */
3246     if (*onameP == '\0' || *nnameP == '\0') {
3247         VN_RELE(odirP);
3248         VN_RELE(ndirP);
3249         errno = EINVAL;
3250         return -1;
3251     }
3252
3253     /*
3254      * Rename the file
3255      */
3256     code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
3257     VN_RELE(odirP);
3258     VN_RELE(ndirP);
3259     if (code != 0) {
3260         errno = code;
3261         return -1;
3262     }
3263
3264     return 0;
3265 }
3266
3267 /*
3268  * Remove a or directory
3269  * Note: file name may not end in a slash.
3270  */
3271 int
3272 uafs_rmdir(char *path)
3273 {
3274     int retval;
3275     AFS_GLOCK();
3276     retval = uafs_rmdir_r(path);
3277     AFS_GUNLOCK();
3278     return retval;
3279 }
3280
3281 int
3282 uafs_rmdir_r(char *path)
3283 {
3284     int code;
3285     struct usr_vnode *dirP;
3286     char *nameP;
3287
3288     if (uafs_IsRoot(path)) {
3289         return EACCES;
3290     }
3291
3292     /*
3293      * Look up the parent directory.
3294      */
3295     nameP = uafs_LastPath(path);
3296     if (nameP != NULL) {
3297         code = uafs_LookupParent(path, &dirP);
3298         if (code != 0) {
3299             errno = code;
3300             return -1;
3301         }
3302     } else {
3303         dirP = afs_CurrentDir;
3304         nameP = path;
3305         VN_HOLD(dirP);
3306     }
3307
3308     /*
3309      * Make sure the directory name has at least one character
3310      */
3311     if (*nameP == '\0') {
3312         VN_RELE(dirP);
3313         errno = EINVAL;
3314         return -1;
3315     }
3316
3317     /*
3318      * Remove the directory
3319      */
3320     code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3321     VN_RELE(dirP);
3322     if (code != 0) {
3323         errno = code;
3324         return -1;
3325     }
3326
3327     return 0;
3328 }
3329
3330 /*
3331  * Flush a file from the AFS cache
3332  */
3333 int
3334 uafs_FlushFile(char *path)
3335 {
3336     int code;
3337     struct afs_ioctl iob;
3338
3339     iob.in = NULL;
3340     iob.in_size = 0;
3341     iob.out = NULL;
3342     iob.out_size = 0;
3343
3344     code =
3345         call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3346                      0);
3347     if (code != 0) {
3348         errno = code;
3349         return -1;
3350     }
3351
3352     return 0;
3353 }
3354
3355 int
3356 uafs_FlushFile_r(char *path)
3357 {
3358     int retval;
3359     AFS_GUNLOCK();
3360     retval = uafs_FlushFile(path);
3361     AFS_GLOCK();
3362     return retval;
3363 }
3364
3365 /*
3366  * open a directory
3367  */
3368 usr_DIR *
3369 uafs_opendir(char *path)
3370 {
3371     usr_DIR *retval;
3372     AFS_GLOCK();
3373     retval = uafs_opendir_r(path);
3374     AFS_GUNLOCK();
3375     return retval;
3376 }
3377
3378 usr_DIR *
3379 uafs_opendir_r(char *path)
3380 {
3381     usr_DIR *dirp;
3382     struct usr_vnode *fileP;
3383     int fd;
3384
3385     /*
3386      * Open the directory for reading
3387      */
3388     fd = uafs_open_r(path, O_RDONLY, 0);
3389     if (fd < 0) {
3390         return NULL;
3391     }
3392
3393     fileP = afs_FileTable[fd];
3394     if (fileP == NULL) {
3395         return NULL;
3396     }
3397
3398     if (fileP->v_type != VDIR) {
3399         uafs_close_r(fd);
3400         errno = ENOTDIR;
3401         return NULL;
3402     }
3403
3404     /*
3405      * Set up the directory structures
3406      */
3407     dirp = afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3408                          sizeof(struct usr_dirent));
3409     usr_assert(dirp != NULL);
3410     dirp->dd_buf = (char *)(dirp + 1);
3411     dirp->dd_fd = fd;
3412     dirp->dd_loc = 0;
3413     dirp->dd_size = 0;
3414
3415     errno = 0;
3416     return dirp;
3417 }
3418
3419 /*
3420  * Read directory entries into a file system independent format.
3421  * This routine was developed to support AFS cache consistency testing.
3422  * You should use uafs_readdir instead.
3423  */
3424 int
3425 uafs_getdents(int fd, struct min_direct *buf, int len)
3426 {
3427     int retval;
3428     AFS_GLOCK();
3429     retval = uafs_getdents_r(fd, buf, len);
3430     AFS_GUNLOCK();
3431     return retval;
3432 }
3433
3434 int
3435 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3436 {
3437     int code;
3438     struct usr_uio uio;
3439     struct usr_vnode *vp;
3440     struct iovec iov[1];
3441
3442     /*
3443      * Make sure this is an open file
3444      */
3445     vp = afs_FileTable[fd];
3446     if (vp == NULL) {
3447         AFS_GUNLOCK();
3448         errno = EBADF;
3449         return -1;
3450     }
3451
3452     /*
3453      * set up the uio buffer
3454      */
3455     iov[0].iov_base = (char *)buf;
3456     iov[0].iov_len = len;
3457     uio.uio_iov = &iov[0];
3458     uio.uio_iovcnt = 1;
3459     uio.uio_offset = afs_FileOffsets[fd];
3460     uio.uio_segflg = 0;
3461     uio.uio_fmode = FREAD;
3462     uio.uio_resid = len;
3463
3464     /*
3465      * read the next chunk from the directory
3466      */
3467     code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3468     if (code != 0) {
3469         errno = code;
3470         return -1;
3471     }
3472
3473     afs_FileOffsets[fd] = uio.uio_offset;
3474     return (len - uio.uio_resid);
3475 }
3476
3477 /*
3478  * read from a directory (names only)
3479  */
3480 struct usr_dirent *
3481 uafs_readdir(usr_DIR * dirp)
3482 {
3483     struct usr_dirent *retval;
3484     AFS_GLOCK();
3485     retval = uafs_readdir_r(dirp);
3486     AFS_GUNLOCK();
3487     return retval;
3488 }
3489
3490 struct usr_dirent *
3491 uafs_readdir_r(usr_DIR * dirp)
3492 {
3493     int code;
3494     int len;
3495     struct usr_uio uio;
3496     struct usr_vnode *vp;
3497     struct iovec iov[1];
3498     struct usr_dirent *direntP;
3499     struct min_direct *directP;
3500
3501     if (!dirp) {
3502         errno = EBADF;
3503         return NULL;
3504     }
3505
3506     /*
3507      * Make sure this is an open file
3508      */
3509     vp = afs_FileTable[dirp->dd_fd];
3510     if (vp == NULL) {
3511         errno = EBADF;
3512         return NULL;
3513     }
3514
3515     /*
3516      * If there are no entries in the stream buffer
3517      * then read another chunk
3518      */
3519     directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3520     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3521         /*
3522          * set up the uio buffer
3523          */
3524         iov[0].iov_base = dirp->dd_buf;
3525         iov[0].iov_len = USR_DIRSIZE;
3526         uio.uio_iov = &iov[0];
3527         uio.uio_iovcnt = 1;
3528         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3529         uio.uio_segflg = 0;
3530         uio.uio_fmode = FREAD;
3531         uio.uio_resid = USR_DIRSIZE;
3532
3533         /*
3534          * read the next chunk from the directory
3535          */
3536         code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3537         if (code != 0) {
3538             errno = code;
3539             return NULL;
3540         }
3541         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3542
3543         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3544         dirp->dd_loc = 0;
3545         directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3546     }
3547
3548     /*
3549      * Check for end of file
3550      */
3551     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3552         errno = 0;
3553         return NULL;
3554     }
3555     len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3556     usr_assert(len <= dirp->dd_size);
3557
3558     /*
3559      * Copy the next entry into the usr_dirent structure and advance
3560      */
3561     direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3562     direntP->d_ino = directP->d_fileno;
3563     direntP->d_off = direntP->d_reclen;
3564     direntP->d_reclen =
3565         sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3566     memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3567     direntP->d_name[directP->d_namlen] = '\0';
3568     dirp->dd_loc += len;
3569     dirp->dd_size -= len;
3570
3571     return direntP;
3572 }
3573
3574 /*
3575  * Close a directory
3576  */
3577 int
3578 uafs_closedir(usr_DIR * dirp)
3579 {
3580     int retval;
3581     AFS_GLOCK();
3582     retval = uafs_closedir_r(dirp);
3583     AFS_GUNLOCK();
3584     return retval;
3585 }
3586
3587 int
3588 uafs_closedir_r(usr_DIR * dirp)
3589 {
3590     int fd;
3591     int rc;
3592
3593     if (!dirp) {
3594         errno = EBADF;
3595         return -1;
3596     }
3597
3598     fd = dirp->dd_fd;
3599     afs_osi_Free((char *)dirp,
3600                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3601     rc = uafs_close_r(fd);
3602     return rc;
3603 }
3604
3605 /*
3606  * Destroy AFS credentials from the kernel cache
3607  */
3608 int
3609 uafs_unlog(void)
3610 {
3611     int code;
3612
3613     usr_mutex_lock(&osi_authenticate_lock);
3614     code = ktc_ForgetAllTokens();
3615     usr_mutex_unlock(&osi_authenticate_lock);
3616     return code;
3617 }
3618
3619 int
3620 uafs_unlog_r(void)
3621 {
3622     int retval;
3623     AFS_GUNLOCK();
3624     retval = uafs_unlog();
3625     AFS_GLOCK();
3626     return retval;
3627 }
3628
3629 /*
3630  * Strip the AFS mount point from a pathname string. Return
3631  * NULL if the path is a relative pathname or if the path
3632  * doesn't start with the AFS mount point string.
3633  */
3634 char *
3635 uafs_afsPathName(char *path)
3636 {
3637     char *p;
3638     char lastchar;
3639     int i;
3640
3641     if (path[0] != '/')
3642         return NULL;
3643     lastchar = '/';
3644     for (i = 1, p = path + 1; *p != '\0'; p++) {
3645         /* Ignore duplicate slashes */
3646         if (*p == '/' && lastchar == '/')
3647             continue;
3648         /* Is this a subdirectory of the AFS mount point? */
3649         if (afs_mountDir[i] == '\0' && *p == '/') {
3650             /* strip leading slashes */
3651             while (*(++p) == '/');
3652             return p;
3653         }
3654         /* Reject paths that are not within AFS */
3655         if (*p != afs_mountDir[i])
3656             return NULL;
3657         lastchar = *p;
3658         i++;
3659     }
3660     /* Is this the AFS mount point? */
3661     if (afs_mountDir[i] == '\0') {
3662         usr_assert(*p == '\0');
3663         return p;
3664     }
3665     return NULL;
3666 }
3667
3668 /*
3669  * uafs_getcellstatus
3670  * get the cell status
3671  */
3672 int
3673 uafs_getcellstatus(char *cell, afs_int32 * status)
3674 {
3675     int rc;
3676     struct afs_ioctl iob;
3677
3678     iob.in = cell;
3679     iob.in_size = strlen(cell) + 1;
3680     iob.out = 0;
3681     iob.out_size = 0;
3682
3683     rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
3684                       (long)&iob, 0, 0);
3685
3686     if (rc < 0) {
3687         errno = rc;
3688         return -1;
3689     }
3690
3691     *status = (intptr_t)iob.out;
3692     return 0;
3693 }
3694
3695 /*
3696  * uafs_getvolquota
3697  * Get quota of volume associated with path
3698  */
3699 int
3700 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
3701 {
3702     int rc;
3703     struct afs_ioctl iob;
3704     VolumeStatus status;
3705
3706     iob.in = 0;
3707     iob.in_size = 0;
3708     iob.out = (char *)&status;
3709     iob.out_size = sizeof status;
3710
3711     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
3712                       0, 0);
3713
3714     if (rc != 0) {
3715         errno = rc;
3716         return -1;
3717     }
3718
3719     *BlocksInUse = status.BlocksInUse;
3720     *MaxQuota = status.MaxQuota;
3721     return 0;
3722 }
3723
3724 /*
3725  * uafs_setvolquota
3726  * Set quota of volume associated with path
3727  */
3728 int
3729 uafs_setvolquota(char *path, afs_int32 MaxQuota)
3730 {
3731     int rc;
3732     struct afs_ioctl iob;
3733     VolumeStatus status = { 0 };
3734
3735     iob.in = (char *)&status;
3736     iob.in_size = sizeof status;
3737     iob.out = 0;
3738     iob.out_size = 0;
3739
3740     status.MaxQuota = MaxQuota;
3741     status.MinQuota = -1;
3742
3743     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
3744                       0, 0);
3745
3746     if (rc != 0) {
3747         errno = rc;
3748         return -1;
3749     }
3750
3751     return 0;
3752 }
3753
3754 /*
3755  * uafs_statmountpoint
3756  * Determine whether a dir. is a mount point or not
3757  * return 1 if mount point, 0 if not
3758  */
3759 int
3760 uafs_statmountpoint(char *path)
3761 {
3762     int retval;
3763
3764     AFS_GLOCK();
3765     retval = uafs_statmountpoint_r(path);
3766     AFS_GUNLOCK();
3767     return retval;
3768 }
3769
3770 int
3771 uafs_statmountpoint_r(char *path)
3772 {
3773     int code;
3774     struct vnode *vp;
3775     struct vcache *avc;
3776     int r;
3777
3778     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
3779     if (code != 0) {
3780         errno = code;
3781         return -1;
3782     }
3783
3784     avc = VTOAFS(vp);
3785
3786     r = avc->mvstat;
3787     VN_RELE(vp);
3788     return r;
3789 }
3790
3791 /*
3792  * uafs_getRights
3793  * Get a list of rights for the current user on path.
3794  */
3795 int
3796 uafs_access(char *path, int flags)
3797 {
3798     int code;
3799     struct vnode *vp;
3800     int fileMode = 0;
3801
3802     if (flags & R_OK) {
3803         fileMode |= VREAD;
3804     }
3805     if (flags & W_OK) {
3806         fileMode |= VWRITE;
3807     }
3808     if (flags & X_OK) {
3809         fileMode |= VEXEC;
3810     }
3811
3812     AFS_GLOCK();
3813     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3814     if (code != 0) {
3815         errno = code;
3816         AFS_GUNLOCK();
3817         return -1;
3818     }
3819
3820     code = afs_access(VTOAFS(vp), fileMode, get_user_struct()->u_cred);
3821     VN_RELE(vp);
3822
3823     if (code != 0)
3824         errno = code;
3825
3826     AFS_GUNLOCK();
3827     return code ? -1 : 0;
3828 }
3829
3830 /*
3831  * uafs_getRights
3832  * Get a list of rights for the current user on path.
3833  */
3834 int
3835 uafs_getRights(char *path)
3836 {
3837     int code;
3838     struct vnode *vp;
3839     int afs_rights;
3840
3841     AFS_GLOCK();
3842     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3843     if (code != 0) {
3844         errno = code;
3845         AFS_GUNLOCK();
3846         return -1;
3847     }
3848
3849     afs_rights =
3850         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
3851         | PRSFS_LOCK | PRSFS_ADMINISTER;
3852
3853     afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
3854
3855     AFS_GUNLOCK();
3856     return afs_rights;
3857 }
3858 #endif /* UKERNEL */