UKERNEL: Add uafs_setMountDir
[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 "rx/rx_globals.h"
33 #include "afsd/afsd.h"
34
35 #define VFS 1
36 #undef  VIRTUE
37 #undef  VICE
38
39 #ifndef AFS_CACHE_VNODE_PATH
40 #error You must compile UKERNEL code with -DAFS_CACHE_VNODE_PATH
41 #endif
42
43 #define CACHEINFOFILE   "cacheinfo"
44 #define AFSLOGFILE      "AFSLog"
45 #define DCACHEFILE      "CacheItems"
46 #define VOLINFOFILE     "VolumeItems"
47 #define CELLINFOFILE    "CellItems"
48 #define MAXIPADDRS 64
49
50 #ifndef MIN
51 #define MIN(A,B)        ((A)<(B)?(A):(B))
52 #endif
53 #ifndef MAX
54 #define MAX(A,B)        ((A)>(B)?(A):(B))
55 #endif
56
57 extern int cacheDiskType;
58
59 char afs_LclCellName[64];
60
61 static struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
62 static int afs_FileFlags[MAX_OSI_FILES];
63 static off_t afs_FileOffsets[MAX_OSI_FILES];
64
65 #define MAX_CACHE_LOOPS 4
66
67 static struct usr_vfs afs_RootVfs;
68 static struct usr_vnode *afs_RootVnode = NULL;
69 static struct usr_vnode *afs_CurrentDir = NULL;
70
71 static char afs_mountDir[1024]; /* AFS mount point */
72 static int afs_mountDirLen;             /* strlen of AFS mount point */
73
74 struct afsconf_dir *afs_cdir;   /* config dir */
75
76 int afs_bufferpages = 100;
77
78 static usr_key_t afs_global_u_key;
79
80 static struct usr_proc *afs_global_procp = NULL;
81 static struct usr_ucred *afs_global_ucredp = NULL;
82
83 struct usr_ucred afs_osi_cred, *afs_osi_credp;
84 usr_mutex_t afs_global_lock;
85 usr_thread_t afs_global_owner;
86 usr_mutex_t rx_global_lock;
87 usr_thread_t rx_global_owner;
88
89 static usr_mutex_t osi_dummy_lock;
90 static usr_mutex_t osi_waitq_lock;
91 static usr_mutex_t osi_authenticate_lock;
92 afs_lock_t afs_ftf;
93 afs_lock_t osi_flplock;
94 afs_lock_t osi_fsplock;
95
96 #ifndef NETSCAPE_NSAPI
97
98 /*
99  * Mutex and condition variable used to implement sleep
100  */
101 pthread_mutex_t usr_sleep_mutex;
102 pthread_cond_t usr_sleep_cond;
103
104 #endif /* !NETSCAPE_NSAPI */
105
106 int call_syscall(long, long, long, long, long, long);
107 int fork_syscall(long, long, long, long, long, long);
108
109
110 /*
111  * Hash table mapping addresses onto wait structures for
112  * osi_Sleep/osi_Wakeup and osi_Wait/osi_Wakeup
113  */
114 typedef struct osi_wait {
115     caddr_t addr;
116     usr_cond_t cond;
117     int flag;
118     struct osi_wait *next;
119     struct osi_wait *prev;
120     time_t expiration;
121     struct osi_wait *timedNext;
122     struct osi_wait *timedPrev;
123 } osi_wait_t;
124
125 /*
126  * Head of the linked list of available waitq structures.
127  */
128 static osi_wait_t *osi_waithash_avail;
129
130 /*
131  * List of timed waits, NSAPI does not provide a cond_timed
132  * wait, so we need to keep track of the timed waits ourselves and
133  * periodically check for expirations
134  */
135 static osi_wait_t *osi_timedwait_head;
136 static osi_wait_t *osi_timedwait_tail;
137
138 static struct {
139     osi_wait_t *head;
140     osi_wait_t *tail;
141 } osi_waithash_table[OSI_WAITHASH_SIZE];
142
143 /*
144  * Never call afs_brelse
145  */
146 int
147 ufs_brelse(struct usr_vnode *vp, struct usr_buf *bp)
148 {
149     usr_assert(0);
150     return 0;
151 }
152
153 /*
154  * I am not sure what to do with these, they assert for now
155  */
156 int
157 iodone(struct usr_buf *bp)
158 {
159     usr_assert(0);
160     return 0;
161 }
162
163 struct usr_file *
164 getf(int fd)
165 {
166     usr_assert(0);
167     return 0;
168 }
169
170 /*
171  * Every user is a super user
172  */
173 int
174 afs_osi_suser(void *credp)
175 {
176     return 1;
177 }
178
179 int
180 afs_suser(void *credp)
181 {
182     return 1;
183 }
184
185 /*
186  * These are no-ops in user space
187  */
188
189 void
190 afs_osi_SetTime(osi_timeval_t * atv)
191 {
192     return;
193 }
194
195 /*
196  * xflock should never fall through, the only files we know
197  * about are AFS files
198  */
199 int
200 usr_flock(void)
201 {
202     usr_assert(0);
203     return 0;
204 }
205
206 /*
207  * ioctl should never fall through, the only files we know
208  * about are AFS files
209  */
210 int
211 usr_ioctl(void)
212 {
213     usr_assert(0);
214     return 0;
215 }
216
217 /*
218  * We do not support the inode related system calls
219  */
220 int
221 afs_syscall_icreate(long a, long b, long c, long d, long e, long f)
222 {
223     usr_assert(0);
224     return 0;
225 }
226
227 int
228 afs_syscall_iincdec(int dev, int inode, int inode_p1, int amount)
229 {
230     usr_assert(0);
231     return 0;
232 }
233
234 int
235 afs_syscall_iopen(int dev, int inode, int usrmod)
236 {
237     usr_assert(0);
238     return 0;
239 }
240
241 int
242 afs_syscall_ireadwrite(void)
243 {
244     usr_assert(0);
245     return 0;
246 }
247
248 /*
249  * these routines are referenced in the vfsops structure, but
250  * should never get called
251  */
252 int
253 vno_close(void)
254 {
255     usr_assert(0);
256     return 0;
257 }
258
259 int
260 vno_ioctl(void)
261 {
262     usr_assert(0);
263     return 0;
264 }
265
266 int
267 vno_rw(void)
268 {
269     usr_assert(0);
270     return 0;
271 }
272
273 int
274 vno_select(void)
275 {
276     usr_assert(0);
277     return 0;
278 }
279
280 /*
281  * uiomove copies data between kernel buffers and uio buffers
282  */
283 int
284 usr_uiomove(char *kbuf, int n, int rw, struct usr_uio *uio)
285 {
286     int nio;
287     int len;
288     char *ptr;
289     struct iovec *iovp;
290
291     nio = uio->uio_iovcnt;
292     iovp = uio->uio_iov;
293
294     if (nio <= 0)
295         return EFAULT;
296
297     /*
298      * copy the data
299      */
300     ptr = kbuf;
301     while (nio > 0 && n > 0) {
302         len = MIN(n, iovp->iov_len);
303         if (rw == UIO_READ) {
304             memcpy(iovp->iov_base, ptr, len);
305         } else {
306             memcpy(ptr, iovp->iov_base, len);
307         }
308         n -= len;
309         ptr += len;
310         uio->uio_resid -= len;
311         uio->uio_offset += len;
312         iovp->iov_base = (char *)(iovp->iov_base) + len;
313         iovp->iov_len -= len;
314         iovp++;
315         nio--;
316     }
317
318     if (n > 0)
319         return EFAULT;
320     return 0;
321 }
322
323 /*
324  * routines to manage user credentials
325  */
326 struct usr_ucred *
327 usr_crcopy(struct usr_ucred *credp)
328 {
329     struct usr_ucred *newcredp;
330
331     newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
332     *newcredp = *credp;
333     newcredp->cr_ref = 1;
334     return newcredp;
335 }
336
337 struct usr_ucred *
338 usr_crget(void)
339 {
340     struct usr_ucred *newcredp;
341
342     newcredp = (struct usr_ucred *)afs_osi_Alloc(sizeof(struct usr_ucred));
343     newcredp->cr_ref = 1;
344     return newcredp;
345 }
346
347 int
348 usr_crfree(struct usr_ucred *credp)
349 {
350     credp->cr_ref--;
351     if (credp->cr_ref == 0) {
352         afs_osi_Free((char *)credp, sizeof(struct usr_ucred));
353     }
354     return 0;
355 }
356
357 int
358 usr_crhold(struct usr_ucred *credp)
359 {
360     credp->cr_ref++;
361     return 0;
362 }
363
364 void
365 usr_vattr_null(struct usr_vattr *vap)
366 {
367     int n;
368     char *cp;
369
370     n = sizeof(struct usr_vattr);
371     cp = (char *)vap;
372     while (n--) {
373         *cp++ = -1;
374     }
375 }
376
377 /*
378  * Initialize the thread specific data used to simulate the
379  * kernel environment for each thread. The user structure
380  * is stored in the thread specific data.
381  */
382 void
383 uafs_InitThread(void)
384 {
385     int st;
386     struct usr_user *uptr;
387
388     /*
389      * initialize the thread specific user structure. Use malloc to
390      * allocate the data block, so pthread_finish can free the buffer
391      * when this thread terminates.
392      */
393     uptr =
394         (struct usr_user *)malloc(sizeof(struct usr_user) +
395                                   sizeof(struct usr_ucred));
396     usr_assert(uptr != NULL);
397     uptr->u_error = 0;
398     uptr->u_prio = 0;
399     uptr->u_procp = afs_global_procp;
400     uptr->u_cred = (struct usr_ucred *)(uptr + 1);
401     *uptr->u_cred = *afs_global_ucredp;
402     st = usr_setspecific(afs_global_u_key, (void *)uptr);
403     usr_assert(st == 0);
404 }
405
406 /*
407  * routine to get the user structure from the thread specific data.
408  * this routine is used to implement the global 'u' structure. Initializes
409  * the thread if needed.
410  */
411 struct usr_user *
412 get_user_struct(void)
413 {
414     struct usr_user *uptr;
415     int st;
416     st = usr_getspecific(afs_global_u_key, (void **)&uptr);
417     usr_assert(st == 0);
418     if (uptr == NULL) {
419         uafs_InitThread();
420         st = usr_getspecific(afs_global_u_key, (void **)&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 = (osi_wait_t *) 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 = (osi_wait_t *) 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 = (struct osi_file *)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 #ifdef AFS_WEB_ENHANCEMENTS
1745             if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
1746                 code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
1747             else
1748                 code =
1749                     afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred,
1750                                AFS_LOOKUP_NOEVAL);
1751 #else
1752             code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
1753 #endif /* AFS_WEB_ENHANCEMENTS */
1754             if (nextVc)
1755                 nextVp=AFSTOV(nextVc);
1756             if (code != 0) {
1757                 VN_RELE(vp);
1758                 afs_osi_Free(tmpPath, strlen(path) + 1);
1759                 return code;
1760             }
1761         }
1762
1763         /*
1764          * Follow symbolic links for parent directories and
1765          * for leaves when the follow flag is set.
1766          */
1767         if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
1768             linkCount = 0;
1769             while (nextVp->v_type == VLNK) {
1770                 if (++linkCount > MAX_OSI_LINKS) {
1771                     VN_RELE(vp);
1772                     VN_RELE(nextVp);
1773                     afs_osi_Free(tmpPath, strlen(path) + 1);
1774                     return code;
1775                 }
1776                 code = uafs_LookupLink(nextVp, vp, &linkVp);
1777                 if (code) {
1778                     VN_RELE(vp);
1779                     VN_RELE(nextVp);
1780                     afs_osi_Free(tmpPath, strlen(path) + 1);
1781                     return code;
1782                 }
1783                 VN_RELE(nextVp);
1784                 nextVp = linkVp;
1785             }
1786         }
1787
1788         VN_RELE(vp);
1789         vp = nextVp;
1790         pathP = nextPathP;
1791     }
1792
1793     /*
1794      * Special case, nextPathP is non-null if pathname ends in slash
1795      */
1796     if (nextPathP != NULL && vp->v_type != VDIR) {
1797         VN_RELE(vp);
1798         afs_osi_Free(tmpPath, strlen(path) + 1);
1799         return ENOTDIR;
1800     }
1801
1802     afs_osi_Free(tmpPath, strlen(path) + 1);
1803     *vpp = vp;
1804     return 0;
1805 }
1806
1807 /*
1808  * Lookup the target of a symbolic link
1809  * Call VN_HOLD on the output vnode if successful.
1810  * Returns zero on success, error code on failure.
1811  *
1812  * Note: Caller must hold the AFS global lock.
1813  */
1814 int
1815 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
1816                 struct usr_vnode **vpp)
1817 {
1818     int code;
1819     int len;
1820     char *pathP;
1821     struct usr_vnode *linkVp;
1822     struct usr_uio uio;
1823     struct iovec iov[1];
1824
1825     AFS_ASSERT_GLOCK();
1826
1827     pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
1828     usr_assert(pathP != NULL);
1829
1830     /*
1831      * set up the uio buffer
1832      */
1833     iov[0].iov_base = pathP;
1834     iov[0].iov_len = MAX_OSI_PATH + 1;
1835     uio.uio_iov = &iov[0];
1836     uio.uio_iovcnt = 1;
1837     uio.uio_offset = 0;
1838     uio.uio_segflg = 0;
1839     uio.uio_fmode = FREAD;
1840     uio.uio_resid = MAX_OSI_PATH + 1;
1841
1842     /*
1843      * Read the link data
1844      */
1845     code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
1846     if (code) {
1847         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1848         return code;
1849     }
1850     len = MAX_OSI_PATH + 1 - uio.uio_resid;
1851     pathP[len] = '\0';
1852
1853     /*
1854      * Find the target of the symbolic link
1855      */
1856     code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
1857     if (code) {
1858         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1859         return code;
1860     }
1861
1862     afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1863     *vpp = linkVp;
1864     return 0;
1865 }
1866
1867 /*
1868  * Lookup the parent of a file or directory given its path
1869  * Call VN_HOLD on the output vnode if successful.
1870  * Returns zero on success, error code on failure.
1871  *
1872  * Note: Caller must hold the AFS global lock.
1873  */
1874 int
1875 uafs_LookupParent(char *path, struct usr_vnode **vpp)
1876 {
1877     int len;
1878     int code;
1879     char *pathP;
1880     struct usr_vnode *parentP;
1881
1882     AFS_ASSERT_GLOCK();
1883
1884     /*
1885      * Absolute path names must start with the AFS mount point.
1886      */
1887     if (*path == '/') {
1888         pathP = uafs_afsPathName(path);
1889         if (pathP == NULL) {
1890             return ENOENT;
1891         }
1892     }
1893
1894     /*
1895      * Find the length of the parent path
1896      */
1897     len = strlen(path);
1898     while (len > 0 && path[len - 1] == '/') {
1899         len--;
1900     }
1901     if (len == 0) {
1902         return EINVAL;
1903     }
1904     while (len > 0 && path[len - 1] != '/') {
1905         len--;
1906     }
1907     if (len == 0) {
1908         return EINVAL;
1909     }
1910
1911     pathP = afs_osi_Alloc(len);
1912     usr_assert(pathP != NULL);
1913     memcpy(pathP, path, len - 1);
1914     pathP[len - 1] = '\0';
1915
1916     /*
1917      * look up the parent
1918      */
1919     code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
1920     afs_osi_Free(pathP, len);
1921     if (code != 0) {
1922         return code;
1923     }
1924     if (parentP->v_type != VDIR) {
1925         VN_RELE(parentP);
1926         return ENOTDIR;
1927     }
1928
1929     *vpp = parentP;
1930     return 0;
1931 }
1932
1933 /*
1934  * Return a pointer to the first character in the last component
1935  * of a pathname
1936  */
1937 char *
1938 uafs_LastPath(char *path)
1939 {
1940     int len;
1941
1942     len = strlen(path);
1943     while (len > 0 && path[len - 1] == '/') {
1944         len--;
1945     }
1946     while (len > 0 && path[len - 1] != '/') {
1947         len--;
1948     }
1949     if (len == 0) {
1950         return NULL;
1951     }
1952     return path + len;
1953 }
1954
1955 /*
1956  * Set the working directory.
1957  */
1958 int
1959 uafs_chdir(char *path)
1960 {
1961     int retval;
1962     AFS_GLOCK();
1963     retval = uafs_chdir_r(path);
1964     AFS_GUNLOCK();
1965     return retval;
1966 }
1967
1968 int
1969 uafs_chdir_r(char *path)
1970 {
1971     int code;
1972     struct vnode *dirP;
1973
1974     code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
1975     if (code != 0) {
1976         errno = code;
1977         return -1;
1978     }
1979     if (dirP->v_type != VDIR) {
1980         VN_RELE(dirP);
1981         errno = ENOTDIR;
1982         return -1;
1983     }
1984     VN_RELE(afs_CurrentDir);
1985     afs_CurrentDir = dirP;
1986     return 0;
1987 }
1988
1989 /*
1990  * Create a directory.
1991  */
1992 int
1993 uafs_mkdir(char *path, int mode)
1994 {
1995     int retval;
1996     AFS_GLOCK();
1997     retval = uafs_mkdir_r(path, mode);
1998     AFS_GUNLOCK();
1999     return retval;
2000 }
2001
2002 int
2003 uafs_mkdir_r(char *path, int mode)
2004 {
2005     int code;
2006     char *nameP;
2007     struct vnode *parentP;
2008     struct vcache *dirP;
2009     struct usr_vattr attrs;
2010
2011     if (uafs_IsRoot(path)) {
2012         return EACCES;
2013     }
2014
2015     /*
2016      * Look up the parent directory.
2017      */
2018     nameP = uafs_LastPath(path);
2019     if (nameP != NULL) {
2020         code = uafs_LookupParent(path, &parentP);
2021         if (code != 0) {
2022             errno = code;
2023             return -1;
2024         }
2025     } else {
2026         parentP = afs_CurrentDir;
2027         nameP = path;
2028         VN_HOLD(parentP);
2029     }
2030
2031     /*
2032      * Make sure the directory has at least one character
2033      */
2034     if (*nameP == '\0') {
2035         VN_RELE(parentP);
2036         errno = EINVAL;
2037         return -1;
2038     }
2039
2040     /*
2041      * Create the directory
2042      */
2043     usr_vattr_null(&attrs);
2044     attrs.va_type = VREG;
2045     attrs.va_mode = mode;
2046     attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2047     attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2048     dirP = NULL;
2049     code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, get_user_struct()->u_cred);
2050     VN_RELE(parentP);
2051     if (code != 0) {
2052         errno = code;
2053         return -1;
2054     }
2055     VN_RELE(AFSTOV(dirP));
2056     return 0;
2057 }
2058
2059 /*
2060  * Return 1 if path is the AFS root, otherwise return 0
2061  */
2062 int
2063 uafs_IsRoot(char *path)
2064 {
2065     while (*path == '/' && *(path + 1) == '/') {
2066         path++;
2067     }
2068     if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2069         return 0;
2070     }
2071     path += afs_mountDirLen;
2072     while (*path == '/') {
2073         path++;
2074     }
2075     if (*path != '\0') {
2076         return 0;
2077     }
2078     return 1;
2079 }
2080
2081 /*
2082  * Open a file
2083  * Note: file name may not end in a slash.
2084  */
2085 int
2086 uafs_open(char *path, int flags, int mode)
2087 {
2088     int retval;
2089     AFS_GLOCK();
2090     retval = uafs_open_r(path, flags, mode);
2091     AFS_GUNLOCK();
2092     return retval;
2093 }
2094
2095 int
2096 uafs_open_r(char *path, int flags, int mode)
2097 {
2098     int fd;
2099     int code;
2100     int openFlags;
2101     int fileMode;
2102     struct usr_vnode *fileP;
2103     struct usr_vnode *dirP;
2104     struct usr_vattr attrs;
2105     char *nameP;
2106
2107     struct vcache* vc;
2108
2109     if (uafs_IsRoot(path)) {
2110         fileP = afs_RootVnode;
2111         VN_HOLD(fileP);
2112     } else {
2113         /*
2114          * Look up the parent directory.
2115          */
2116         nameP = uafs_LastPath(path);
2117         if (nameP != NULL) {
2118             code = uafs_LookupParent(path, &dirP);
2119             if (code != 0) {
2120                 errno = code;
2121                 return -1;
2122             }
2123         } else {
2124             dirP = afs_CurrentDir;
2125             nameP = path;
2126             VN_HOLD(dirP);
2127         }
2128
2129         /*
2130          * Make sure the filename has at least one character
2131          */
2132         if (*nameP == '\0') {
2133             VN_RELE(dirP);
2134             errno = EINVAL;
2135             return -1;
2136         }
2137
2138         /*
2139          * Get the VNODE for this file
2140          */
2141         if (flags & O_CREAT) {
2142             usr_vattr_null(&attrs);
2143             attrs.va_type = VREG;
2144             attrs.va_mode = mode;
2145             attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2146             attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2147             if (flags & O_TRUNC) {
2148                 attrs.va_size = 0;
2149             }
2150             fileP = NULL;
2151             vc=VTOAFS(fileP);
2152             code =
2153                 afs_create(VTOAFS(dirP), nameP, &attrs,
2154                            (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2155                            &vc, get_user_struct()->u_cred);
2156             VN_RELE(dirP);
2157             if (code != 0) {
2158                 errno = code;
2159                 return -1;
2160             }
2161             fileP = AFSTOV(vc);
2162         } else {
2163             fileP = NULL;
2164             code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2165             VN_RELE(dirP);
2166             if (code != 0) {
2167                 errno = code;
2168                 return -1;
2169             }
2170
2171             /*
2172              * Check whether we have access to this file
2173              */
2174             fileMode = 0;
2175             if (flags & (O_RDONLY | O_RDWR)) {
2176                 fileMode |= VREAD;
2177             }
2178             if (flags & (O_WRONLY | O_RDWR)) {
2179                 fileMode |= VWRITE;
2180             }
2181             if (!fileMode)
2182                 fileMode = VREAD;       /* since O_RDONLY is 0 */
2183             code = afs_access(VTOAFS(fileP), fileMode, get_user_struct()->u_cred);
2184             if (code != 0) {
2185                 VN_RELE(fileP);
2186                 errno = code;
2187                 return -1;
2188             }
2189
2190             /*
2191              * Get the file attributes, all we need is the size
2192              */
2193             code = afs_getattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2194             if (code != 0) {
2195                 VN_RELE(fileP);
2196                 errno = code;
2197                 return -1;
2198             }
2199         }
2200     }
2201
2202     /*
2203      * Setup the open flags
2204      */
2205     openFlags = 0;
2206     if (flags & O_TRUNC) {
2207         openFlags |= FTRUNC;
2208     }
2209     if (flags & O_APPEND) {
2210         openFlags |= FAPPEND;
2211     }
2212     if (flags & O_SYNC) {
2213         openFlags |= FSYNC;
2214     }
2215     if (flags & O_SYNC) {
2216         openFlags |= FSYNC;
2217     }
2218     if (flags & (O_RDONLY | O_RDWR)) {
2219         openFlags |= FREAD;
2220     }
2221     if (flags & (O_WRONLY | O_RDWR)) {
2222         openFlags |= FWRITE;
2223     }
2224     if ((openFlags & (FREAD | FWRITE)) == 0) {
2225         /* O_RDONLY is 0, so ... */
2226         openFlags |= FREAD;
2227     }
2228
2229     /*
2230      * Truncate if necessary
2231      */
2232     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2233         usr_vattr_null(&attrs);
2234         attrs.va_mask = ATTR_SIZE;
2235         attrs.va_size = 0;
2236         code = afs_setattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2237         if (code != 0) {
2238             VN_RELE(fileP);
2239             errno = code;
2240             return -1;
2241         }
2242     }
2243
2244     vc=VTOAFS(fileP);   
2245     /*
2246      * do the open
2247      */
2248     code = afs_open(&vc, openFlags, get_user_struct()->u_cred);
2249     if (code != 0) {
2250         VN_RELE(fileP);
2251         errno = code;
2252         return -1;
2253     }
2254
2255     /*
2256      * Put the vnode pointer into the file table
2257      */
2258     for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2259         if (afs_FileTable[fd] == NULL) {
2260             afs_FileTable[fd] = fileP;
2261             afs_FileFlags[fd] = openFlags;
2262             if (flags & O_APPEND) {
2263                 afs_FileOffsets[fd] = attrs.va_size;
2264             } else {
2265                 afs_FileOffsets[fd] = 0;
2266             }
2267             break;
2268         }
2269     }
2270     if (fd == MAX_OSI_FILES) {
2271         VN_RELE(fileP);
2272         errno = ENFILE;
2273         return -1;
2274     }
2275
2276     return fd;
2277 }
2278
2279 /*
2280  * Create a file
2281  */
2282 int
2283 uafs_creat(char *path, int mode)
2284 {
2285     int rc;
2286     rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2287     return rc;
2288 }
2289
2290 int
2291 uafs_creat_r(char *path, int mode)
2292 {
2293     int rc;
2294     rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2295     return rc;
2296 }
2297
2298 /*
2299  * Write to a file
2300  */
2301 int
2302 uafs_write(int fd, char *buf, int len)
2303 {
2304     int retval;
2305     AFS_GLOCK();
2306     retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
2307     AFS_GUNLOCK();
2308     return retval;
2309 }
2310
2311 int
2312 uafs_pwrite(int fd, char *buf, int len, off_t offset)
2313 {
2314     int retval;
2315     AFS_GLOCK();
2316     retval = uafs_pwrite_r(fd, buf, len, offset);
2317     AFS_GUNLOCK();
2318     return retval;
2319 }
2320
2321 int
2322 uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
2323 {
2324     int code;
2325     struct usr_uio uio;
2326     struct iovec iov[1];
2327     struct usr_vnode *fileP;
2328
2329     /*
2330      * Make sure this is an open file
2331      */
2332     fileP = afs_FileTable[fd];
2333     if (fileP == NULL) {
2334         errno = EBADF;
2335         return -1;
2336     }
2337
2338     /*
2339      * set up the uio buffer
2340      */
2341     iov[0].iov_base = buf;
2342     iov[0].iov_len = len;
2343     uio.uio_iov = &iov[0];
2344     uio.uio_iovcnt = 1;
2345     uio.uio_offset = offset;
2346     uio.uio_segflg = 0;
2347     uio.uio_fmode = FWRITE;
2348     uio.uio_resid = len;
2349
2350     /*
2351      * do the write
2352      */
2353
2354     code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], get_user_struct()->u_cred, 0);
2355     if (code) {
2356         errno = code;
2357         return -1;
2358     }
2359
2360     afs_FileOffsets[fd] = uio.uio_offset;
2361     return (len - uio.uio_resid);
2362 }
2363
2364 /*
2365  * Read from a file
2366  */
2367 int
2368 uafs_read(int fd, char *buf, int len)
2369 {
2370     int retval;
2371     AFS_GLOCK();
2372     retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
2373     AFS_GUNLOCK();
2374     return retval;
2375 }
2376
2377 int
2378 uafs_pread(int fd, char *buf, int len, off_t offset)
2379 {
2380     int retval;
2381     AFS_GLOCK();
2382     retval = uafs_pread_r(fd, buf, len, offset);
2383     AFS_GUNLOCK();
2384     return retval;
2385 }
2386
2387 int
2388 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2389 {
2390     int code;
2391     struct usr_uio uio;
2392     struct iovec iov[1];
2393     struct usr_vnode *fileP;
2394     struct usr_buf *bufP;
2395
2396     /*
2397      * Make sure this is an open file
2398      */
2399     fileP = afs_FileTable[fd];
2400     if (fileP == NULL) {
2401         errno = EBADF;
2402         return -1;
2403     }
2404
2405     /*
2406      * set up the uio buffer
2407      */
2408     iov[0].iov_base = buf;
2409     iov[0].iov_len = len;
2410     uio.uio_iov = &iov[0];
2411     uio.uio_iovcnt = 1;
2412     uio.uio_offset = offset;
2413     uio.uio_segflg = 0;
2414     uio.uio_fmode = FREAD;
2415     uio.uio_resid = len;
2416
2417     /*
2418      * do the read
2419      */
2420     code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0, &bufP, 0);
2421     if (code) {
2422         errno = code;
2423         return -1;
2424     }
2425
2426     afs_FileOffsets[fd] = uio.uio_offset;
2427     return (len - uio.uio_resid);
2428 }
2429
2430 /*
2431  * Copy the attributes of a file into a stat structure.
2432  *
2433  * NOTE: Caller must hold the global AFS lock.
2434  */
2435 int
2436 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2437 {
2438     int code;
2439     struct usr_vattr attrs;
2440
2441     AFS_ASSERT_GLOCK();
2442
2443     /*
2444      * Get the attributes
2445      */
2446     code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2447     if (code != 0) {
2448         return code;
2449     }
2450
2451     /*
2452      * Copy the attributes, zero fields that aren't set
2453      */
2454     memset((void *)stats, 0, sizeof(struct stat));
2455     stats->st_dev = -1;
2456     stats->st_ino = attrs.va_nodeid;
2457     stats->st_mode = attrs.va_mode;
2458     stats->st_nlink = attrs.va_nlink;
2459     stats->st_uid = attrs.va_uid;
2460     stats->st_gid = attrs.va_gid;
2461     stats->st_rdev = attrs.va_rdev;
2462     stats->st_size = attrs.va_size;
2463     stats->st_atime = attrs.va_atime.tv_sec;
2464     stats->st_mtime = attrs.va_mtime.tv_sec;
2465     stats->st_ctime = attrs.va_ctime.tv_sec;
2466     stats->st_blksize = attrs.va_blocksize;
2467     stats->st_blocks = attrs.va_blocks;
2468
2469     return 0;
2470 }
2471
2472 /*
2473  * Get the attributes of a file, do follow links
2474  */
2475 int
2476 uafs_stat(char *path, struct stat *buf)
2477 {
2478     int retval;
2479     AFS_GLOCK();
2480     retval = uafs_stat_r(path, buf);
2481     AFS_GUNLOCK();
2482     return retval;
2483 }
2484
2485 int
2486 uafs_stat_r(char *path, struct stat *buf)
2487 {
2488     int code;
2489     struct vnode *vp;
2490
2491     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2492     if (code != 0) {
2493         errno = code;
2494         return -1;
2495     }
2496     code = uafs_GetAttr(vp, buf);
2497     VN_RELE(vp);
2498     if (code) {
2499         errno = code;
2500         return -1;
2501     }
2502     return 0;
2503 }
2504
2505 /*
2506  * Get the attributes of a file, don't follow links
2507  */
2508 int
2509 uafs_lstat(char *path, struct stat *buf)
2510 {
2511     int retval;
2512     AFS_GLOCK();
2513     retval = uafs_lstat_r(path, buf);
2514     AFS_GUNLOCK();
2515     return retval;
2516 }
2517
2518 int
2519 uafs_lstat_r(char *path, struct stat *buf)
2520 {
2521     int code;
2522     struct vnode *vp;
2523
2524     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2525     if (code != 0) {
2526         errno = code;
2527         return -1;
2528     }
2529     code = uafs_GetAttr(vp, buf);
2530     VN_RELE(vp);
2531     if (code) {
2532         errno = code;
2533         return -1;
2534     }
2535     return 0;
2536 }
2537
2538 /*
2539  * Get the attributes of an open file
2540  */
2541 int
2542 uafs_fstat(int fd, struct stat *buf)
2543 {
2544     int retval;
2545     AFS_GLOCK();
2546     retval = uafs_fstat_r(fd, buf);
2547     AFS_GUNLOCK();
2548     return retval;
2549 }
2550
2551 int
2552 uafs_fstat_r(int fd, struct stat *buf)
2553 {
2554     int code;
2555     struct vnode *vp;
2556
2557     vp = afs_FileTable[fd];
2558     if (vp == NULL) {
2559         errno = EBADF;
2560         return -1;
2561     }
2562     code = uafs_GetAttr(vp, buf);
2563     if (code) {
2564         errno = code;
2565         return -1;
2566     }
2567     return 0;
2568 }
2569
2570 /*
2571  * change the permissions on a file
2572  */
2573 int
2574 uafs_chmod(char *path, int mode)
2575 {
2576     int retval;
2577     AFS_GLOCK();
2578     retval = uafs_chmod_r(path, mode);
2579     AFS_GUNLOCK();
2580     return retval;
2581 }
2582
2583 int
2584 uafs_chmod_r(char *path, int mode)
2585 {
2586     int code;
2587     struct vnode *vp;
2588     struct usr_vattr attrs;
2589
2590     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2591     if (code != 0) {
2592         errno = code;
2593         return -1;
2594     }
2595     usr_vattr_null(&attrs);
2596     attrs.va_mask = ATTR_MODE;
2597     attrs.va_mode = mode;
2598     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2599     VN_RELE(vp);
2600     if (code != 0) {
2601         errno = code;
2602         return -1;
2603     }
2604     return 0;
2605 }
2606
2607 /*
2608  * change the permissions on an open file
2609  */
2610 int
2611 uafs_fchmod(int fd, int mode)
2612 {
2613     int retval;
2614     AFS_GLOCK();
2615     retval = uafs_fchmod_r(fd, mode);
2616     AFS_GUNLOCK();
2617     return retval;
2618 }
2619
2620 int
2621 uafs_fchmod_r(int fd, int mode)
2622 {
2623     int code;
2624     struct vnode *vp;
2625     struct usr_vattr attrs;
2626
2627     vp = afs_FileTable[fd];
2628     if (vp == NULL) {
2629         errno = EBADF;
2630         return -1;
2631     }
2632     usr_vattr_null(&attrs);
2633     attrs.va_mask = ATTR_MODE;
2634     attrs.va_mode = mode;
2635     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2636     if (code != 0) {
2637         errno = code;
2638         return -1;
2639     }
2640     return 0;
2641 }
2642
2643 /*
2644  * truncate a file
2645  */
2646 int
2647 uafs_truncate(char *path, int length)
2648 {
2649     int retval;
2650     AFS_GLOCK();
2651     retval = uafs_truncate_r(path, length);
2652     AFS_GUNLOCK();
2653     return retval;
2654 }
2655
2656 int
2657 uafs_truncate_r(char *path, int length)
2658 {
2659     int code;
2660     struct vnode *vp;
2661     struct usr_vattr attrs;
2662
2663     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2664     if (code != 0) {
2665         errno = code;
2666         return -1;
2667     }
2668     usr_vattr_null(&attrs);
2669     attrs.va_mask = ATTR_SIZE;
2670     attrs.va_size = length;
2671     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2672     VN_RELE(vp);
2673     if (code != 0) {
2674         errno = code;
2675         return -1;
2676     }
2677     return 0;
2678 }
2679
2680 /*
2681  * truncate an open file
2682  */
2683 int
2684 uafs_ftruncate(int fd, int length)
2685 {
2686     int retval;
2687     AFS_GLOCK();
2688     retval = uafs_ftruncate_r(fd, length);
2689     AFS_GUNLOCK();
2690     return retval;
2691 }
2692
2693 int
2694 uafs_ftruncate_r(int fd, int length)
2695 {
2696     int code;
2697     struct vnode *vp;
2698     struct usr_vattr attrs;
2699
2700     vp = afs_FileTable[fd];
2701     if (vp == NULL) {
2702         errno = EBADF;
2703         return -1;
2704     }
2705     usr_vattr_null(&attrs);
2706     attrs.va_mask = ATTR_SIZE;
2707     attrs.va_size = length;
2708     code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2709     if (code != 0) {
2710         errno = code;
2711         return -1;
2712     }
2713     return 0;
2714 }
2715
2716 /*
2717  * set the read/write file pointer of an open file
2718  */
2719 int
2720 uafs_lseek(int fd, int offset, int whence)
2721 {
2722     int retval;
2723     AFS_GLOCK();
2724     retval = uafs_lseek_r(fd, offset, whence);
2725     AFS_GUNLOCK();
2726     return retval;
2727 }
2728
2729 int
2730 uafs_lseek_r(int fd, int offset, int whence)
2731 {
2732     int code;
2733     int newpos;
2734     struct usr_vattr attrs;
2735     struct usr_vnode *vp;
2736
2737     vp = afs_FileTable[fd];
2738     if (vp == NULL) {
2739         errno = EBADF;
2740         return -1;
2741     }
2742     switch (whence) {
2743     case SEEK_CUR:
2744         newpos = afs_FileOffsets[fd] + offset;
2745         break;
2746     case SEEK_SET:
2747         newpos = offset;
2748         break;
2749     case SEEK_END:
2750         code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2751         if (code != 0) {
2752             errno = code;
2753             return -1;
2754         }
2755         newpos = attrs.va_size + offset;
2756         break;
2757     default:
2758         errno = EINVAL;
2759         return -1;
2760     }
2761     if (newpos < 0) {
2762         errno = EINVAL;
2763         return -1;
2764     }
2765     afs_FileOffsets[fd] = newpos;
2766     return newpos;
2767 }
2768
2769 /*
2770  * sync a file
2771  */
2772 int
2773 uafs_fsync(int fd)
2774 {
2775     int retval;
2776     AFS_GLOCK();
2777     retval = uafs_fsync_r(fd);
2778     AFS_GUNLOCK();
2779     return retval;
2780 }
2781
2782 int
2783 uafs_fsync_r(int fd)
2784 {
2785     int code;
2786     struct usr_vnode *fileP;
2787
2788
2789     fileP = afs_FileTable[fd];
2790     if (fileP == NULL) {
2791         errno = EBADF;
2792         return -1;
2793     }
2794
2795     code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
2796     if (code != 0) {
2797         errno = code;
2798         return -1;
2799     }
2800
2801     return 0;
2802 }
2803
2804 /*
2805  * Close a file
2806  */
2807 int
2808 uafs_close(int fd)
2809 {
2810     int retval;
2811     AFS_GLOCK();
2812     retval = uafs_close_r(fd);
2813     AFS_GUNLOCK();
2814     return retval;
2815 }
2816
2817 int
2818 uafs_close_r(int fd)
2819 {
2820     int code;
2821     struct usr_vnode *fileP;
2822
2823     fileP = afs_FileTable[fd];
2824     if (fileP == NULL) {
2825         errno = EBADF;
2826         return -1;
2827     }
2828     afs_FileTable[fd] = NULL;
2829
2830     code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
2831     VN_RELE(fileP);
2832     if (code != 0) {
2833         errno = code;
2834         return -1;
2835     }
2836
2837     return 0;
2838 }
2839
2840 /*
2841  * Create a hard link from the source to the target
2842  * Note: file names may not end in a slash.
2843  */
2844 int
2845 uafs_link(char *existing, char *new)
2846 {
2847     int retval;
2848     AFS_GLOCK();
2849     retval = uafs_link_r(existing, new);
2850     AFS_GUNLOCK();
2851     return retval;
2852 }
2853
2854 int
2855 uafs_link_r(char *existing, char *new)
2856 {
2857     int code;
2858     struct usr_vnode *existP;
2859     struct usr_vnode *dirP;
2860     char *nameP;
2861
2862     if (uafs_IsRoot(new)) {
2863         return EACCES;
2864     }
2865
2866     /*
2867      * Look up the existing node.
2868      */
2869     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
2870     if (code != 0) {
2871         errno = code;
2872         return -1;
2873     }
2874
2875     /*
2876      * Look up the parent directory.
2877      */
2878     nameP = uafs_LastPath(new);
2879     if (nameP != NULL) {
2880         code = uafs_LookupParent(new, &dirP);
2881         if (code != 0) {
2882             VN_RELE(existP);
2883             errno = code;
2884             return -1;
2885         }
2886     } else {
2887         dirP = afs_CurrentDir;
2888         nameP = new;
2889         VN_HOLD(dirP);
2890     }
2891
2892     /*
2893      * Make sure the filename has at least one character
2894      */
2895     if (*nameP == '\0') {
2896         VN_RELE(existP);
2897         VN_RELE(dirP);
2898         errno = EINVAL;
2899         return -1;
2900     }
2901
2902     /*
2903      * Create the link
2904      */
2905     code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
2906     VN_RELE(existP);
2907     VN_RELE(dirP);
2908     if (code != 0) {
2909         errno = code;
2910         return -1;
2911     }
2912     return 0;
2913 }
2914
2915 /*
2916  * Create a symbolic link from the source to the target
2917  * Note: file names may not end in a slash.
2918  */
2919 int
2920 uafs_symlink(char *target, char *source)
2921 {
2922     int retval;
2923     AFS_GLOCK();
2924     retval = uafs_symlink_r(target, source);
2925     AFS_GUNLOCK();
2926     return retval;
2927 }
2928
2929 int
2930 uafs_symlink_r(char *target, char *source)
2931 {
2932     int code;
2933     struct usr_vnode *dirP;
2934     struct usr_vattr attrs;
2935     char *nameP;
2936
2937     if (uafs_IsRoot(source)) {
2938         return EACCES;
2939     }
2940
2941     /*
2942      * Look up the parent directory.
2943      */
2944     nameP = uafs_LastPath(source);
2945     if (nameP != NULL) {
2946         code = uafs_LookupParent(source, &dirP);
2947         if (code != 0) {
2948             errno = code;
2949             return -1;
2950         }
2951     } else {
2952         dirP = afs_CurrentDir;
2953         nameP = source;
2954         VN_HOLD(dirP);
2955     }
2956
2957     /*
2958      * Make sure the filename has at least one character
2959      */
2960     if (*nameP == '\0') {
2961         VN_RELE(dirP);
2962         errno = EINVAL;
2963         return -1;
2964     }
2965
2966     /*
2967      * Create the link
2968      */
2969     usr_vattr_null(&attrs);
2970     attrs.va_type = VLNK;
2971     attrs.va_mode = 0777;
2972     attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2973     attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2974     code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, get_user_struct()->u_cred);
2975     VN_RELE(dirP);
2976     if (code != 0) {
2977         errno = code;
2978         return -1;
2979     }
2980     return 0;
2981 }
2982
2983 /*
2984  * Read a symbolic link into the buffer
2985  */
2986 int
2987 uafs_readlink(char *path, char *buf, int len)
2988 {
2989     int retval;
2990     AFS_GLOCK();
2991     retval = uafs_readlink_r(path, buf, len);
2992     AFS_GUNLOCK();
2993     return retval;
2994 }
2995
2996 int
2997 uafs_readlink_r(char *path, char *buf, int len)
2998 {
2999     int code;
3000     struct usr_vnode *vp;
3001     struct usr_uio uio;
3002     struct iovec iov[1];
3003
3004     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3005     if (code != 0) {
3006         errno = code;
3007         return -1;
3008     }
3009
3010     if (vp->v_type != VLNK) {
3011         VN_RELE(vp);
3012         errno = EINVAL;
3013         return -1;
3014     }
3015
3016     /*
3017      * set up the uio buffer
3018      */
3019     iov[0].iov_base = buf;
3020     iov[0].iov_len = len;
3021     uio.uio_iov = &iov[0];
3022     uio.uio_iovcnt = 1;
3023     uio.uio_offset = 0;
3024     uio.uio_segflg = 0;
3025     uio.uio_fmode = FREAD;
3026     uio.uio_resid = len;
3027
3028     /*
3029      * Read the the link
3030      */
3031     code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3032     VN_RELE(vp);
3033     if (code) {
3034         errno = code;
3035         return -1;
3036     }
3037
3038     /*
3039      * return the number of bytes read
3040      */
3041     return (len - uio.uio_resid);
3042 }
3043
3044 /*
3045  * Remove a file (or directory)
3046  * Note: file name may not end in a slash.
3047  */
3048 int
3049 uafs_unlink(char *path)
3050 {
3051     int retval;
3052     AFS_GLOCK();
3053     retval = uafs_unlink_r(path);
3054     AFS_GUNLOCK();
3055     return retval;
3056 }
3057
3058 int
3059 uafs_unlink_r(char *path)
3060 {
3061     int code;
3062     struct usr_vnode *dirP;
3063     char *nameP;
3064
3065     if (uafs_IsRoot(path)) {
3066         return EACCES;
3067     }
3068
3069     /*
3070      * Look up the parent directory.
3071      */
3072     nameP = uafs_LastPath(path);
3073     if (nameP != NULL) {
3074         code = uafs_LookupParent(path, &dirP);
3075         if (code != 0) {
3076             errno = code;
3077             return -1;
3078         }
3079     } else {
3080         dirP = afs_CurrentDir;
3081         nameP = path;
3082         VN_HOLD(dirP);
3083     }
3084
3085     /*
3086      * Make sure the filename has at least one character
3087      */
3088     if (*nameP == '\0') {
3089         VN_RELE(dirP);
3090         errno = EINVAL;
3091         return -1;
3092     }
3093
3094     /*
3095      * Remove the file
3096      */
3097     code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3098     VN_RELE(dirP);
3099     if (code != 0) {
3100         errno = code;
3101         return -1;
3102     }
3103
3104     return 0;
3105 }
3106
3107 /*
3108  * Rename a file (or directory)
3109  */
3110 int
3111 uafs_rename(char *old, char *new)
3112 {
3113     int retval;
3114     AFS_GLOCK();
3115     retval = uafs_rename_r(old, new);
3116     AFS_GUNLOCK();
3117     return retval;
3118 }
3119
3120 int
3121 uafs_rename_r(char *old, char *new)
3122 {
3123     int code;
3124     char *onameP;
3125     char *nnameP;
3126     struct usr_vnode *odirP;
3127     struct usr_vnode *ndirP;
3128
3129     if (uafs_IsRoot(new)) {
3130         return EACCES;
3131     }
3132
3133     /*
3134      * Look up the parent directories.
3135      */
3136     onameP = uafs_LastPath(old);
3137     if (onameP != NULL) {
3138         code = uafs_LookupParent(old, &odirP);
3139         if (code != 0) {
3140             errno = code;
3141             return -1;
3142         }
3143     } else {
3144         odirP = afs_CurrentDir;
3145         onameP = old;
3146         VN_HOLD(odirP);
3147     }
3148     nnameP = uafs_LastPath(new);
3149     if (nnameP != NULL) {
3150         code = uafs_LookupParent(new, &ndirP);
3151         if (code != 0) {
3152             errno = code;
3153             return -1;
3154         }
3155     } else {
3156         ndirP = afs_CurrentDir;
3157         nnameP = new;
3158         VN_HOLD(ndirP);
3159     }
3160
3161     /*
3162      * Make sure the filename has at least one character
3163      */
3164     if (*onameP == '\0' || *nnameP == '\0') {
3165         VN_RELE(odirP);
3166         VN_RELE(ndirP);
3167         errno = EINVAL;
3168         return -1;
3169     }
3170
3171     /*
3172      * Rename the file
3173      */
3174     code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
3175     VN_RELE(odirP);
3176     VN_RELE(ndirP);
3177     if (code != 0) {
3178         errno = code;
3179         return -1;
3180     }
3181
3182     return 0;
3183 }
3184
3185 /*
3186  * Remove a or directory
3187  * Note: file name may not end in a slash.
3188  */
3189 int
3190 uafs_rmdir(char *path)
3191 {
3192     int retval;
3193     AFS_GLOCK();
3194     retval = uafs_rmdir_r(path);
3195     AFS_GUNLOCK();
3196     return retval;
3197 }
3198
3199 int
3200 uafs_rmdir_r(char *path)
3201 {
3202     int code;
3203     struct usr_vnode *dirP;
3204     char *nameP;
3205
3206     if (uafs_IsRoot(path)) {
3207         return EACCES;
3208     }
3209
3210     /*
3211      * Look up the parent directory.
3212      */
3213     nameP = uafs_LastPath(path);
3214     if (nameP != NULL) {
3215         code = uafs_LookupParent(path, &dirP);
3216         if (code != 0) {
3217             errno = code;
3218             return -1;
3219         }
3220     } else {
3221         dirP = afs_CurrentDir;
3222         nameP = path;
3223         VN_HOLD(dirP);
3224     }
3225
3226     /*
3227      * Make sure the directory name has at least one character
3228      */
3229     if (*nameP == '\0') {
3230         VN_RELE(dirP);
3231         errno = EINVAL;
3232         return -1;
3233     }
3234
3235     /*
3236      * Remove the directory
3237      */
3238     code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3239     VN_RELE(dirP);
3240     if (code != 0) {
3241         errno = code;
3242         return -1;
3243     }
3244
3245     return 0;
3246 }
3247
3248 /*
3249  * Flush a file from the AFS cache
3250  */
3251 int
3252 uafs_FlushFile(char *path)
3253 {
3254     int code;
3255     struct afs_ioctl iob;
3256
3257     iob.in = NULL;
3258     iob.in_size = 0;
3259     iob.out = NULL;
3260     iob.out_size = 0;
3261
3262     code =
3263         call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3264                      0);
3265     if (code != 0) {
3266         errno = code;
3267         return -1;
3268     }
3269
3270     return 0;
3271 }
3272
3273 int
3274 uafs_FlushFile_r(char *path)
3275 {
3276     int retval;
3277     AFS_GUNLOCK();
3278     retval = uafs_FlushFile(path);
3279     AFS_GLOCK();
3280     return retval;
3281 }
3282
3283 /*
3284  * open a directory
3285  */
3286 usr_DIR *
3287 uafs_opendir(char *path)
3288 {
3289     usr_DIR *retval;
3290     AFS_GLOCK();
3291     retval = uafs_opendir_r(path);
3292     AFS_GUNLOCK();
3293     return retval;
3294 }
3295
3296 usr_DIR *
3297 uafs_opendir_r(char *path)
3298 {
3299     usr_DIR *dirp;
3300     struct usr_vnode *fileP;
3301     int fd;
3302
3303     /*
3304      * Open the directory for reading
3305      */
3306     fd = uafs_open_r(path, O_RDONLY, 0);
3307     if (fd < 0) {
3308         return NULL;
3309     }
3310
3311     fileP = afs_FileTable[fd];
3312     if (fileP == NULL) {
3313         return NULL;
3314     }
3315
3316     if (fileP->v_type != VDIR) {
3317         uafs_close_r(fd);
3318         errno = ENOTDIR;
3319         return NULL;
3320     }
3321
3322     /*
3323      * Set up the directory structures
3324      */
3325     dirp =
3326         (usr_DIR *) afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3327                                   sizeof(struct usr_dirent));
3328     usr_assert(dirp != NULL);
3329     dirp->dd_buf = (char *)(dirp + 1);
3330     dirp->dd_fd = fd;
3331     dirp->dd_loc = 0;
3332     dirp->dd_size = 0;
3333
3334     errno = 0;
3335     return dirp;
3336 }
3337
3338 /*
3339  * Read directory entries into a file system independent format.
3340  * This routine was developed to support AFS cache consistency testing.
3341  * You should use uafs_readdir instead.
3342  */
3343 int
3344 uafs_getdents(int fd, struct min_direct *buf, int len)
3345 {
3346     int retval;
3347     AFS_GLOCK();
3348     retval = uafs_getdents_r(fd, buf, len);
3349     AFS_GUNLOCK();
3350     return retval;
3351 }
3352
3353 int
3354 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3355 {
3356     int code;
3357     struct usr_uio uio;
3358     struct usr_vnode *vp;
3359     struct iovec iov[1];
3360
3361     /*
3362      * Make sure this is an open file
3363      */
3364     vp = afs_FileTable[fd];
3365     if (vp == NULL) {
3366         AFS_GUNLOCK();
3367         errno = EBADF;
3368         return -1;
3369     }
3370
3371     /*
3372      * set up the uio buffer
3373      */
3374     iov[0].iov_base = (char *)buf;
3375     iov[0].iov_len = len;
3376     uio.uio_iov = &iov[0];
3377     uio.uio_iovcnt = 1;
3378     uio.uio_offset = afs_FileOffsets[fd];
3379     uio.uio_segflg = 0;
3380     uio.uio_fmode = FREAD;
3381     uio.uio_resid = len;
3382
3383     /*
3384      * read the next chunk from the directory
3385      */
3386     code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3387     if (code != 0) {
3388         errno = code;
3389         return -1;
3390     }
3391
3392     afs_FileOffsets[fd] = uio.uio_offset;
3393     return (len - uio.uio_resid);
3394 }
3395
3396 /*
3397  * read from a directory (names only)
3398  */
3399 struct usr_dirent *
3400 uafs_readdir(usr_DIR * dirp)
3401 {
3402     struct usr_dirent *retval;
3403     AFS_GLOCK();
3404     retval = uafs_readdir_r(dirp);
3405     AFS_GUNLOCK();
3406     return retval;
3407 }
3408
3409 struct usr_dirent *
3410 uafs_readdir_r(usr_DIR * dirp)
3411 {
3412     int code;
3413     int len;
3414     struct usr_uio uio;
3415     struct usr_vnode *vp;
3416     struct iovec iov[1];
3417     struct usr_dirent *direntP;
3418     struct min_direct *directP;
3419
3420     if (!dirp) {
3421         errno = EBADF;
3422         return NULL;
3423     }
3424
3425     /*
3426      * Make sure this is an open file
3427      */
3428     vp = afs_FileTable[dirp->dd_fd];
3429     if (vp == NULL) {
3430         errno = EBADF;
3431         return NULL;
3432     }
3433
3434     /*
3435      * If there are no entries in the stream buffer
3436      * then read another chunk
3437      */
3438     directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3439     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3440         /*
3441          * set up the uio buffer
3442          */
3443         iov[0].iov_base = dirp->dd_buf;
3444         iov[0].iov_len = USR_DIRSIZE;
3445         uio.uio_iov = &iov[0];
3446         uio.uio_iovcnt = 1;
3447         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3448         uio.uio_segflg = 0;
3449         uio.uio_fmode = FREAD;
3450         uio.uio_resid = USR_DIRSIZE;
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 NULL;
3459         }
3460         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3461
3462         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3463         dirp->dd_loc = 0;
3464         directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3465     }
3466
3467     /*
3468      * Check for end of file
3469      */
3470     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3471         errno = 0;
3472         return NULL;
3473     }
3474     len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3475     usr_assert(len <= dirp->dd_size);
3476
3477     /*
3478      * Copy the next entry into the usr_dirent structure and advance
3479      */
3480     direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3481     direntP->d_ino = directP->d_fileno;
3482     direntP->d_off = direntP->d_reclen;
3483     direntP->d_reclen =
3484         sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3485     memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3486     direntP->d_name[directP->d_namlen] = '\0';
3487     dirp->dd_loc += len;
3488     dirp->dd_size -= len;
3489
3490     return direntP;
3491 }
3492
3493 /*
3494  * Close a directory
3495  */
3496 int
3497 uafs_closedir(usr_DIR * dirp)
3498 {
3499     int retval;
3500     AFS_GLOCK();
3501     retval = uafs_closedir_r(dirp);
3502     AFS_GUNLOCK();
3503     return retval;
3504 }
3505
3506 int
3507 uafs_closedir_r(usr_DIR * dirp)
3508 {
3509     int fd;
3510     int rc;
3511
3512     if (!dirp) {
3513         errno = EBADF;
3514         return -1;
3515     }
3516
3517     fd = dirp->dd_fd;
3518     afs_osi_Free((char *)dirp,
3519                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3520     rc = uafs_close_r(fd);
3521     return rc;
3522 }
3523
3524 /*
3525  * Do AFS authentication
3526  */
3527 int
3528 uafs_klog(char *user, char *cell, char *passwd, char **reason)
3529 {
3530     int code;
3531     afs_int32 password_expires = -1;
3532
3533     usr_mutex_lock(&osi_authenticate_lock);
3534     code =
3535         ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION +
3536                                    KA_USERAUTH_DOSETPAG2, user, NULL, cell,
3537                                    passwd, 0, &password_expires, 0, reason);
3538     usr_mutex_unlock(&osi_authenticate_lock);
3539     return code;
3540 }
3541
3542 int
3543 uafs_klog_r(char *user, char *cell, char *passwd, char **reason)
3544 {
3545     int retval;
3546     AFS_GUNLOCK();
3547     retval = uafs_klog(user, cell, passwd, reason);
3548     AFS_GLOCK();
3549     return retval;
3550 }
3551
3552 /*
3553  * Destroy AFS credentials from the kernel cache
3554  */
3555 int
3556 uafs_unlog(void)
3557 {
3558     int code;
3559
3560     usr_mutex_lock(&osi_authenticate_lock);
3561     code = ktc_ForgetAllTokens();
3562     usr_mutex_unlock(&osi_authenticate_lock);
3563     return code;
3564 }
3565
3566 int
3567 uafs_unlog_r(void)
3568 {
3569     int retval;
3570     AFS_GUNLOCK();
3571     retval = uafs_unlog();
3572     AFS_GLOCK();
3573     return retval;
3574 }
3575
3576 /*
3577  * Strip the AFS mount point from a pathname string. Return
3578  * NULL if the path is a relative pathname or if the path
3579  * doesn't start with the AFS mount point string.
3580  */
3581 char *
3582 uafs_afsPathName(char *path)
3583 {
3584     char *p;
3585     char lastchar;
3586     int i;
3587
3588     if (path[0] != '/')
3589         return NULL;
3590     lastchar = '/';
3591     for (i = 1, p = path + 1; *p != '\0'; p++) {
3592         /* Ignore duplicate slashes */
3593         if (*p == '/' && lastchar == '/')
3594             continue;
3595         /* Is this a subdirectory of the AFS mount point? */
3596         if (afs_mountDir[i] == '\0' && *p == '/') {
3597             /* strip leading slashes */
3598             while (*(++p) == '/');
3599             return p;
3600         }
3601         /* Reject paths that are not within AFS */
3602         if (*p != afs_mountDir[i])
3603             return NULL;
3604         lastchar = *p;
3605         i++;
3606     }
3607     /* Is this the AFS mount point? */
3608     if (afs_mountDir[i] == '\0') {
3609         usr_assert(*p == '\0');
3610         return p;
3611     }
3612     return NULL;
3613 }
3614
3615 #ifdef AFS_WEB_ENHANCEMENTS
3616 /*
3617  * uafs_klog_nopag
3618  * klog but don't allocate a new pag
3619  */
3620 int
3621 uafs_klog_nopag(char *user, char *cell, char *passwd, char **reason)
3622 {
3623     int code;
3624     afs_int32 password_expires = -1;
3625
3626     usr_mutex_lock(&osi_authenticate_lock);
3627     code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
3628                                       /*+KA_USERAUTH_DOSETPAG2 */ , user,
3629                                       NULL, cell, passwd, 0,
3630                                       &password_expires, 0, reason);
3631     usr_mutex_unlock(&osi_authenticate_lock);
3632     return code;
3633 }
3634
3635 /*
3636  * uafs_getcellstatus
3637  * get the cell status
3638  */
3639 int
3640 uafs_getcellstatus(char *cell, afs_int32 * status)
3641 {
3642     int rc;
3643     struct afs_ioctl iob;
3644
3645     iob.in = cell;
3646     iob.in_size = strlen(cell) + 1;
3647     iob.out = 0;
3648     iob.out_size = 0;
3649
3650     rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
3651                       (long)&iob, 0, 0);
3652
3653     if (rc < 0) {
3654         errno = rc;
3655         return -1;
3656     }
3657
3658     *status = (intptr_t)iob.out;
3659     return 0;
3660 }
3661
3662 /*
3663  * uafs_getvolquota
3664  * Get quota of volume associated with path
3665  */
3666 int
3667 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
3668 {
3669     int rc;
3670     struct afs_ioctl iob;
3671     VolumeStatus *status;
3672     char buf[1024];
3673
3674     iob.in = 0;
3675     iob.in_size = 0;
3676     iob.out = buf;
3677     iob.out_size = 1024;
3678
3679     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
3680                       0, 0);
3681
3682     if (rc != 0) {
3683         errno = rc;
3684         return -1;
3685     }
3686
3687     status = (VolumeStatus *) buf;
3688     *BlocksInUse = status->BlocksInUse;
3689     *MaxQuota = status->MaxQuota;
3690     return 0;
3691 }
3692
3693 /*
3694  * uafs_setvolquota
3695  * Set quota of volume associated with path
3696  */
3697 int
3698 uafs_setvolquota(char *path, afs_int32 MaxQuota)
3699 {
3700     int rc;
3701     struct afs_ioctl iob;
3702     VolumeStatus *status;
3703     char buf[1024];
3704
3705     iob.in = buf;
3706     iob.in_size = 1024;
3707     iob.out = 0;
3708     iob.out_size = 0;
3709
3710     memset(buf, 0, sizeof(VolumeStatus));
3711     status = (VolumeStatus *) buf;
3712     status->MaxQuota = MaxQuota;
3713     status->MinQuota = -1;
3714
3715     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
3716                       0, 0);
3717
3718     if (rc != 0) {
3719         errno = rc;
3720         return -1;
3721     }
3722
3723     return 0;
3724 }
3725
3726 /*
3727  * uafs_statmountpoint
3728  * Determine whether a dir. is a mount point or not
3729  * return 1 if mount point, 0 if not
3730  */
3731 int
3732 uafs_statmountpoint(char *path)
3733 {
3734     int retval;
3735
3736     AFS_GLOCK();
3737     retval = uafs_statmountpoint_r(path);
3738     AFS_GUNLOCK();
3739     return retval;
3740 }
3741
3742 int
3743 uafs_statmountpoint_r(char *path)
3744 {
3745     int code;
3746     struct vnode *vp;
3747     struct vcache *avc;
3748     int r;
3749
3750     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
3751     if (code != 0) {
3752         errno = code;
3753         return -1;
3754     }
3755
3756     avc = VTOAFS(vp);
3757
3758     r = avc->mvstat;
3759     VN_RELE(vp);
3760     return r;
3761 }
3762
3763 /*
3764  * uafs_getRights
3765  * Get a list of rights for the current user on path.
3766  */
3767 int
3768 uafs_getRights(char *path)
3769 {
3770     int code;
3771     struct vnode *vp;
3772     int afs_rights;
3773
3774     AFS_GLOCK();
3775     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3776     if (code != 0) {
3777         errno = code;
3778         AFS_GUNLOCK();
3779         return -1;
3780     }
3781
3782     afs_rights =
3783         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
3784         | PRSFS_LOCK | PRSFS_ADMINISTER;
3785
3786     afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
3787
3788     AFS_GUNLOCK();
3789     return afs_rights;
3790 }
3791 #endif /* AFS_WEB_ENHANCEMENTS */
3792
3793 #endif /* UKERNEL */