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