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