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