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