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