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