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