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