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