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