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