pull-prototypes-to-head-20020821
[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 "../afs/afsincludes.h" /* Afs-based standard headers */
25 #include "../afs/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 int afs_osi_SetTime(osi_timeval_t *atv)
215 {
216     return 0;
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 void 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, char *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, char *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 *osi_AllocLargeSpace(size_t size)
903 {
904     AFS_STATCNT(osi_AllocLargeSpace);
905     return afs_osi_Alloc(size);
906 }
907
908 void osi_FreeLargeSpace(void *ptr)
909 {
910     AFS_STATCNT(osi_FreeLargeSpace);
911     afs_osi_Free(ptr, 0);
912 }
913
914 void *osi_AllocSmallSpace(size_t size)
915 {
916     AFS_STATCNT(osi_AllocSmallSpace);
917     return afs_osi_Alloc(size);
918 }
919
920 void osi_FreeSmallSpace(void *ptr)
921 {
922     AFS_STATCNT(osi_FreeSmallSpace);
923     afs_osi_Free(ptr, 0);
924 }
925
926 void shutdown_osi(void)
927 {
928     AFS_STATCNT(shutdown_osi);
929     return;
930 }
931
932 void shutdown_osinet(void)
933 {
934     AFS_STATCNT(shutdown_osinet);
935     return;
936 }
937
938 void shutdown_osifile(void)
939 {
940     AFS_STATCNT(shutdown_osifile);
941     return;
942 }
943
944 int afs_nfsclient_init(void)
945 {
946     return 0;
947 }
948
949 void shutdown_nfsclnt(void)
950 {
951     return;
952 }
953
954 void afs_osi_Invisible(void)
955 {
956     return;
957 }
958
959 int osi_GetTime(struct timeval *tv)
960 {
961     gettimeofday(tv, NULL);
962     return 0;
963 }
964
965 int osi_SetTime(struct timeval *tv)
966 {
967     return 0;
968 }
969
970 int osi_Active(struct vcache *avc)
971 {
972     AFS_STATCNT(osi_Active);
973     if (avc->opens > 0) return(1);
974     return 0;
975 }
976
977 int afs_osi_MapStrategy(int (*aproc)(), struct usr_buf *bp)
978 {
979     afs_int32 returnCode;
980     returnCode = (*aproc)(bp);
981     return returnCode;
982 }
983
984 void osi_FlushPages(register struct vcache *avc, struct AFS_UCRED *credp)
985 {
986     ObtainSharedLock(&avc->lock,555);
987     if ((hcmp((avc->m.DataVersion), (avc->mapDV)) <= 0) || 
988         ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
989         ReleaseSharedLock(&avc->lock);
990         return;
991     }
992     UpgradeSToWLock(&avc->lock,565);
993     hset(avc->mapDV, avc->m.DataVersion);
994     ReleaseWriteLock(&avc->lock);
995     return;
996 }
997
998 void osi_FlushText_really(register struct vcache *vp)
999 {
1000     if (hcmp(vp->m.DataVersion, vp->flushDV) > 0) {
1001         hset(vp->flushDV, vp->m.DataVersion);
1002     }
1003     return;
1004 }
1005
1006 int osi_SyncVM(struct vcache *avc)
1007 {
1008     return 0;
1009 }
1010
1011 void osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
1012 {
1013     return;
1014 }
1015
1016 void osi_Init(void)
1017 {
1018     int i;
1019     int rc;
1020     usr_thread_t tid;
1021
1022     /*
1023      * Allocate the table used to implement psuedo-inodes.
1024      */
1025     max_osi_files = cacheFiles + 100;
1026     osi_file_table = (osi_file_table_t *)
1027                      afs_osi_Alloc(max_osi_files * sizeof(osi_file_table_t));
1028     usr_assert(osi_file_table != NULL);
1029
1030 #ifndef NETSCAPE_NSAPI
1031     /*
1032      * Initialize the mutex and condition variable used to implement
1033      * time sleeps.
1034      */
1035     pthread_mutex_init(&usr_sleep_mutex, NULL);
1036     pthread_cond_init(&usr_sleep_cond, NULL);
1037 #endif /* !NETSCAPE_NSAPI */
1038
1039     /*
1040      * Initialize the hash table used for sleep/wakeup
1041      */
1042     for (i = 0 ; i < OSI_WAITHASH_SIZE ; i++) {
1043         DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1044     }
1045     DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1046     osi_waithash_avail = NULL;
1047
1048     /*
1049      * Initialize the AFS file table
1050      */
1051     for (i = 0 ; i < MAX_OSI_FILES ; i++) {
1052         afs_FileTable[i] = NULL;
1053     }
1054
1055     /*
1056      * Initialize the global locks
1057      */
1058     usr_mutex_init(&afs_global_lock);
1059     usr_mutex_init(&rx_global_lock);
1060     usr_mutex_init(&osi_inode_lock);
1061     usr_mutex_init(&osi_waitq_lock);
1062     usr_mutex_init(&osi_authenticate_lock);
1063
1064     /*
1065      * Initialize the AFS OSI credentials
1066      */
1067     afs_osi_cred = *afs_global_ucredp;
1068 }
1069
1070 /* ParseArgs is now obsolete, being handled by cmd */
1071
1072 /*---------------------------------------------------------------------
1073   * GetVFileNumber
1074   *
1075   * Description:
1076   *     Given the final component of a filename expected to be a data cache file,
1077   *     return the integer corresponding to the file.  Note: we reject names that
1078   *     are not a ``V'' followed by an integer.  We also reject those names having
1079   *     the right format but lying outside the range [0..cacheFiles-1].
1080   *
1081   * Arguments:
1082   *     fname : Char ptr to the filename to parse.
1083   *
1084   * Returns:
1085   *     >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
1086   *     -1      otherwise.
1087   *
1088   * Environment:
1089   *     Nothing interesting.
1090   *
1091   * Side Effects:
1092   *     None.
1093   *------------------------------------------------------------------------*/
1094
1095 int GetVFileNumber(char *fname)
1096 {
1097     int computedVNumber;    /*The computed file number we return*/
1098     int filenameLen;        /*Number of chars in filename*/
1099     int currDigit;          /*Current digit being processed*/
1100
1101     /*
1102      * The filename must have at least two characters, the first of which must be a ``V''
1103      * and the second of which cannot be a zero unless the file is exactly two chars long.
1104      */
1105     filenameLen = strlen(fname);
1106     if (filenameLen < 2)
1107         return(-1);
1108     if (fname[0] != 'V')
1109         return(-1);
1110     if ((filenameLen > 2) && (fname[1] == '0'))
1111         return(-1);
1112
1113     /*
1114      * Scan through the characters in the given filename, failing immediately if a non-digit
1115      * is found.
1116      */
1117     for (currDigit = 1; currDigit < filenameLen; currDigit++)
1118         if (isdigit(fname[currDigit]) == 0)
1119             return(-1);
1120
1121     /*
1122      * All relevant characters are digits.  Pull out the decimal number they represent.
1123      * Reject it if it's out of range, otherwise return it.
1124      */
1125     computedVNumber = atoi(++fname);
1126     if (computedVNumber < cacheFiles)
1127         return(computedVNumber);
1128     else
1129         return(-1);
1130 }
1131
1132 /*---------------------------------------------------------------------
1133   * CreateCacheFile
1134   *
1135   * Description:
1136   *     Given a full pathname for a file we need to create for the workstation AFS
1137   *     cache, go ahead and create the file.
1138   *
1139   * Arguments:
1140   *     fname : Full pathname of file to create.
1141   *
1142   * Returns:
1143   *     0   iff the file was created,
1144   *     -1  otherwise.
1145   *
1146   * Environment:
1147   *     The given cache file has been found to be missing.
1148   *
1149   * Side Effects:
1150   *     As described.
1151   *------------------------------------------------------------------------*/
1152
1153 int CreateCacheFile(char *fname)
1154 {
1155     static char rn[] = "CreateCacheFile";   /*Routine name*/
1156     int cfd;                                /*File descriptor to AFS cache file*/
1157     int closeResult;                        /*Result of close()*/
1158
1159     if (afsd_verbose)
1160         printf("%s: Creating cache file '%s'\n",
1161                rn, fname);
1162     cfd = open(fname, createAndTrunc, ownerRWmode);
1163     if  (cfd <= 0) {
1164         printf("%s: Can't create '%s', error return is %d (%d)\n",
1165                rn, fname, cfd, errno);
1166         return(-1);
1167     }
1168     closeResult = close(cfd);
1169     if  (closeResult) {
1170         printf("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
1171                rn, fname, errno);
1172         return(-1);
1173     }
1174
1175     return(0);
1176 }
1177
1178 /*---------------------------------------------------------------------
1179   * SweepAFSCache
1180   *
1181   * Description:
1182   *     Sweep through the AFS cache directory, recording the inode number for
1183   *     each valid data cache file there.  Also, delete any file that doesn't beint32
1184   *     in the cache directory during this sweep, and remember which of the other
1185   *     residents of this directory were seen.  After the sweep, we create any data
1186   *     cache files that were missing.
1187   *
1188   * Arguments:
1189   *     vFilesFound : Set to the number of data cache files found.
1190   *
1191   * Returns:
1192   *     0   if everything went well,
1193   *     -1 otherwise.
1194   *
1195   * Environment:
1196   *     This routine may be called several times.  If the number of data cache files
1197   *     found is less than the global cacheFiles, then the caller will need to call it
1198   *     again to record the inodes of the missing zero-length data cache files created
1199   *     in the previous call.
1200   *
1201   * Side Effects:
1202   *     Fills up the global pathname_for_V array, may create and/or
1203   *     delete files as explained above.
1204   *------------------------------------------------------------------------*/
1205
1206 int SweepAFSCache(int *vFilesFound)
1207 {
1208     static char rn[] = "SweepAFSCache"; /*Routine name*/
1209     char fullpn_FileToDelete[1024];     /*File to be deleted from cache*/
1210     char *fileToDelete;                 /*Ptr to last component of above*/
1211     DIR *cdirp;                         /*Ptr to cache directory structure*/
1212 #undef dirent
1213     struct dirent *currp;               /*Current directory entry*/
1214     int vFileNum;                       /*Data cache file's associated number*/
1215
1216     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1217         if (afsd_debug)
1218             printf("%s: Memory Cache, no cache sweep done\n", rn);
1219         *vFilesFound = 0;
1220         return 0;
1221     }
1222
1223     if (afsd_debug)
1224         printf("%s: Opening cache directory '%s'\n",
1225                rn, cacheBaseDir);
1226
1227     if (chmod(cacheBaseDir, 0700)) {            /* force it to be 700 */
1228         printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n",
1229                rn, cacheBaseDir);
1230         return (-1);
1231     }
1232     cdirp = opendir(cacheBaseDir);
1233     if (cdirp == (DIR *)0) {
1234         printf("%s: Can't open AFS cache directory, '%s'.\n",
1235                rn, cacheBaseDir);
1236         return(-1);
1237     }
1238
1239     /*
1240      * Scan the directory entries, remembering data cache file inodes and the existance
1241      * of other important residents.  Delete all files that don't belong here.
1242      */
1243     *vFilesFound = 0;
1244     sprintf(fullpn_FileToDelete, "%s/", cacheBaseDir);
1245     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
1246
1247     for (currp = readdir(cdirp); currp; currp = readdir(cdirp))
1248         {
1249         if (afsd_debug) {
1250             printf("%s: Current directory entry:\n",
1251                    rn);
1252             printf("\tinode=%d, reclen=%d, name='%s'\n",
1253                    currp->d_ino, currp->d_reclen, currp->d_name);
1254         }
1255
1256         /*
1257          * Guess current entry is for a data cache file.
1258          */
1259         vFileNum = GetVFileNumber(currp->d_name);
1260         if (vFileNum >= 0) {
1261             /*
1262              * Found a valid data cache filename.  Remember this file's name
1263              * and bump the number of files found.
1264              */
1265             pathname_for_V[vFileNum] = afs_osi_Alloc(strlen(currp->d_name) +
1266                                                      strlen(cacheBaseDir) + 2);
1267             usr_assert(pathname_for_V[vFileNum] != NULL);
1268             sprintf(pathname_for_V[vFileNum], "%s/%s",
1269                     cacheBaseDir, currp->d_name);
1270             (*vFilesFound)++;
1271         }
1272         else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
1273             /*
1274              * Found the file holding the dcache entries.
1275              */
1276             missing_DCacheFile = 0;
1277         }
1278         else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
1279             /*
1280              * Found the file holding the volume info.
1281              */
1282             missing_VolInfoFile = 0;
1283         }
1284         else  if ((strcmp(currp->d_name,          ".") == 0) ||
1285                   (strcmp(currp->d_name,         "..") == 0) ||
1286                   (strcmp(currp->d_name, "lost+found") == 0)) {
1287             /*
1288              * Don't do anything - this file is legit, and is to be left alone.
1289              */
1290         }
1291         else {
1292             /*
1293              * This file doesn't belong in the cache.  Nuke it.
1294              */
1295             sprintf(fileToDelete, "%s", currp->d_name);
1296             if (afsd_verbose)
1297                 printf("%s: Deleting '%s'\n",
1298                        rn, fullpn_FileToDelete);
1299             if (unlink(fullpn_FileToDelete)) {
1300                 printf("%s: Can't unlink '%s', errno is %d\n",
1301                        rn, fullpn_FileToDelete, errno);
1302             }
1303         }
1304     }
1305
1306     /*
1307      * Create all the cache files that are missing.
1308      */
1309     if (missing_DCacheFile) {
1310         if (afsd_verbose)
1311             printf("%s: Creating '%s'\n",
1312                    rn, fullpn_DCacheFile);
1313         if (CreateCacheFile(fullpn_DCacheFile))
1314             printf("%s: Can't create '%s'\n",
1315                    rn, fullpn_DCacheFile);
1316     }
1317     if (missing_VolInfoFile) {
1318         if (afsd_verbose)
1319             printf("%s: Creating '%s'\n",
1320                    rn, fullpn_VolInfoFile);
1321         if (CreateCacheFile(fullpn_VolInfoFile))
1322             printf("%s: Can't create '%s'\n",
1323                    rn, fullpn_VolInfoFile);
1324     }
1325
1326     if (*vFilesFound < cacheFiles) {
1327         /*
1328          * We came up short on the number of data cache files found.  Scan through the inode
1329          * list and create all missing files.
1330          */
1331         for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
1332             if (pathname_for_V[vFileNum] == (AFSD_INO_T)0) {
1333                 sprintf(vFileNumber, "%d", vFileNum);
1334                 if (afsd_verbose)
1335                     printf("%s: Creating '%s'\n",
1336                            rn, fullpn_VFile);
1337                 if (CreateCacheFile(fullpn_VFile))
1338                     printf("%s: Can't create '%s'\n",
1339                            rn, fullpn_VFile);
1340             }
1341     }
1342
1343     /*
1344      * Close the directory, return success.
1345      */
1346     if (afsd_debug)
1347         printf("%s: Closing cache directory.\n",
1348                rn);
1349     closedir(cdirp);
1350     return(0);
1351 }
1352
1353 static ConfigCell(register struct afsconf_cell *aci, char *arock, struct afsconf_dir *adir)
1354 {
1355     register int isHomeCell;
1356     register int i;
1357     afs_int32 cellFlags;
1358     afs_int32 hosts[MAXHOSTSPERCELL];
1359
1360     /* figure out if this is the home cell */
1361     isHomeCell = (strcmp(aci->name, afs_LclCellName) == 0);
1362     if (isHomeCell) {
1363         lookingForHomeCell = 0;
1364         cellFlags = 1;      /* home cell, suid is ok */
1365     }
1366     else {
1367         cellFlags = 2;      /* not home, suid is forbidden */
1368     }
1369
1370     /* build address list */
1371     for(i=0;i<MAXHOSTSPERCELL;i++)
1372         memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
1373
1374     if (aci->linkedCell) cellFlags |= 4; /* Flag that linkedCell arg exists,
1375                                             for upwards compatibility */
1376
1377     /* configure one cell */
1378     call_syscall(AFSCALL_CALL, AFSOP_ADDCELL2,
1379              (long)hosts,               /* server addresses */
1380              (long)aci->name,           /* cell name */
1381              (long)cellFlags,           /* is this the home cell? */
1382              (long)aci->linkedCell);    /* Linked cell, if any */
1383     return 0;
1384 }
1385
1386 /*
1387  * Set the UDP port number RX uses for UDP datagrams
1388  */
1389 void uafs_SetRxPort(int port)
1390 {
1391     usr_assert(usr_rx_port == 0);
1392     usr_rx_port = port;
1393 }
1394
1395
1396 /*
1397  * Initialize the user space client.
1398  */
1399 void uafs_Init(
1400     char *rn,
1401     char *mountDirParam,
1402     char *confDirParam,
1403     char *cacheBaseDirParam,
1404     int cacheBlocksParam,
1405     int cacheFilesParam,
1406     int cacheStatEntriesParam,
1407     int dCacheSizeParam,
1408     int vCacheSizeParam,
1409     int chunkSizeParam,
1410     int closeSynchParam,
1411     int debugParam,
1412     int nDaemonsParam,
1413     int cacheFlagsParam,
1414     char *logFile)
1415 {
1416     int st;
1417     struct usr_proc *procp;
1418     struct usr_ucred *ucredp;
1419     int i;
1420     int rc;
1421     int currVFile;                  /* Current AFS cache file number */
1422     int lookupResult;               /* Result of GetLocalCellName() */
1423     int cacheIteration;             /* cache verification loop counter */
1424     int vFilesFound;                /* Num data cache files found in sweep */
1425     FILE *logfd;
1426     afs_int32 vfs1_type = -1;
1427     struct afs_ioctl iob;
1428     char tbuffer[1024];
1429     char *p;
1430     char lastchar;
1431     afs_int32 buffer[MAXIPADDRS];
1432     afs_int32 maskbuffer[MAXIPADDRS];
1433     afs_int32 mtubuffer[MAXIPADDRS];
1434
1435     /*
1436      * Use the thread specific data to implement the user structure
1437      */
1438     usr_keycreate(&afs_global_u_key, free);
1439
1440     /*
1441      * Initialize the global ucred structure
1442      */
1443     afs_global_ucredp = (struct usr_ucred *)
1444                         afs_osi_Alloc(sizeof(struct usr_ucred));
1445     usr_assert(afs_global_ucredp != NULL);
1446     afs_global_ucredp->cr_ref = 1;
1447     afs_global_ucredp->cr_uid = geteuid();
1448     afs_global_ucredp->cr_gid = getegid();
1449     afs_global_ucredp->cr_ruid = getuid();
1450     afs_global_ucredp->cr_rgid = getgid();
1451     afs_global_ucredp->cr_suid = afs_global_ucredp->cr_ruid;
1452     afs_global_ucredp->cr_sgid = afs_global_ucredp->cr_rgid;
1453     st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1454     usr_assert(st >= 0);
1455     afs_global_ucredp->cr_ngroups = (unsigned long)st;
1456     for (i = st ; i < NGROUPS ; i++) {
1457         afs_global_ucredp->cr_groups[i] = NOGROUP;
1458     }
1459
1460     /*
1461      * Initialize the global process structure
1462      */
1463     afs_global_procp = (struct usr_proc *)
1464                        afs_osi_Alloc(sizeof(struct usr_proc));
1465     usr_assert(afs_global_procp != NULL);
1466     afs_global_procp->p_pid = getpid();
1467     afs_global_procp->p_ppid = (pid_t)1;
1468     afs_global_procp->p_ucred = afs_global_ucredp;
1469
1470     /*
1471      * Initialize the AFS mount point, default is '/afs'.
1472      * Strip duplicate/trailing slashes from mount point string.
1473      * afs_mountDirLen is set to strlen(afs_mountDir).
1474      */
1475     if (mountDirParam) {
1476         sprintf(tbuffer, "%s", mountDirParam);
1477     } else {
1478         sprintf(tbuffer, "afs");
1479     }
1480     afs_mountDir[0] = '/';
1481     afs_mountDirLen = 1;
1482     for (lastchar = '/', p = &tbuffer[0] ; *p != '\0' ; p++) {
1483         if (lastchar != '/' || *p != '/') {
1484             afs_mountDir[afs_mountDirLen++] = lastchar = *p;
1485         }
1486     }
1487     if (lastchar == '/' && afs_mountDirLen > 1)
1488         afs_mountDirLen--;
1489     afs_mountDir[afs_mountDirLen] = '\0';
1490     usr_assert(afs_mountDirLen > 1);
1491
1492     /*
1493      * Initialize cache parameters using the input arguments
1494      */
1495
1496     cacheBlocks = cacheBlocksParam;
1497     if (cacheFilesParam != 0) {
1498         cacheFiles = cacheFilesParam;
1499     } else {
1500         cacheFiles = cacheBlocks/10;
1501     }
1502     if (cacheStatEntriesParam != 0) {
1503         cacheStatEntries = cacheStatEntriesParam;
1504     }
1505     strcpy(cacheBaseDir, cacheBaseDirParam);
1506     if (nDaemons != 0) {
1507         nDaemons = nDaemonsParam;
1508     } else {
1509         nDaemons = 3;
1510     }
1511     afsd_verbose = debugParam;
1512     afsd_debug = debugParam;
1513     chunkSize = chunkSizeParam;
1514     if (dCacheSizeParam != 0) {
1515         dCacheSize = dCacheSizeParam;
1516     } else {
1517         dCacheSize = cacheFiles/2;
1518     }
1519     if (vCacheSizeParam != 0) {
1520         vCacheSize = vCacheSizeParam;
1521     }
1522     strcpy(confDir, confDirParam);
1523     afsd_CloseSynch = closeSynchParam;
1524     if (cacheFlagsParam >= 0) {
1525         cacheFlags = cacheFlagsParam;
1526     }
1527     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1528          cacheFiles = dCacheSize; 
1529     }
1530
1531     sprintf(fullpn_CacheInfo,  "%s/%s", confDir, CACHEINFOFILE);
1532     if (logFile == NULL) {
1533         sprintf(fullpn_AFSLogFile,  "%s/%s", confDir, AFSLOGFILE);
1534     } else {
1535         strcpy(fullpn_AFSLogFile, logFile);
1536     }
1537
1538     printf("\n%s: Initializing user space AFS client\n\n", rn);
1539     printf("    mountDir:           %s\n", afs_mountDir);
1540     printf("    confDir:            %s\n", confDir);
1541     printf("    cacheBaseDir:       %s\n", cacheBaseDir);
1542     printf("    cacheBlocks:        %d\n", cacheBlocks);
1543     printf("    cacheFiles:         %d\n", cacheFiles);
1544     printf("    cacheStatEntries:   %d\n", cacheStatEntries);
1545     printf("    dCacheSize:         %d\n", dCacheSize);
1546     printf("    vCacheSize:         %d\n", vCacheSize);
1547     printf("    chunkSize:          %d\n", chunkSize);
1548     printf("    afsd_CloseSynch:    %d\n", afsd_CloseSynch);
1549     printf("    afsd_debug/verbose: %d/%d\n", afsd_debug, afsd_verbose);
1550     printf("    nDaemons:           %d\n", nDaemons);
1551     printf("    cacheFlags:         %d\n", cacheFlags);
1552     printf("    logFile:            %s\n", fullpn_AFSLogFile);
1553     printf("\n");
1554     fflush(stdout);
1555
1556     /*
1557      * Initialize the AFS client
1558      */
1559     osi_Init();
1560
1561     /*
1562      * Pull out all the configuration info for the workstation's AFS cache and
1563      * the cellular community we're willing to let our users see.
1564      */
1565     afs_cdir = afsconf_Open(confDir);
1566     if (!afs_cdir) {
1567         printf("afsd: some file missing or bad in %s\n", confDir);
1568         exit(1);
1569     }
1570
1571     lookupResult = afsconf_GetLocalCell(afs_cdir, afs_LclCellName,
1572                                         sizeof(afs_LclCellName));
1573     if (lookupResult) {
1574         printf("%s: Can't get my home cell name!  [Error is %d]\n",
1575                rn, lookupResult);
1576     }
1577     else {
1578         if (afsd_verbose)
1579             printf("%s: My home cell is '%s'\n",
1580                    rn, afs_LclCellName);
1581     }
1582
1583     if ((logfd = fopen(fullpn_AFSLogFile,"r+")) == 0) {
1584         if (afsd_verbose)  printf("%s: Creating '%s'\n",  rn, fullpn_AFSLogFile);
1585         if (CreateCacheFile(fullpn_AFSLogFile)) {
1586             printf("%s: Can't create '%s' (You may want to use the -logfile option)\n",  rn, fullpn_AFSLogFile);
1587             exit(1);
1588         }
1589     } else
1590         fclose(logfd);
1591
1592     /*
1593      * Create and zero the pathname table for the desired cache files.
1594      */
1595     pathname_for_V = (char **)afs_osi_Alloc(cacheFiles * sizeof(char *));
1596     if (pathname_for_V == NULL) {
1597         printf("%s: malloc() failed for cache file table with %d entries.\n",
1598                rn, cacheFiles);
1599         exit(1);
1600     }
1601     memset(pathname_for_V, 0, (cacheFiles * sizeof(char *)));
1602     if (afsd_debug)
1603         printf("%s: %d pathname_for_V entries at 0x%x, %d bytes\n",
1604                rn, cacheFiles, pathname_for_V, (cacheFiles * sizeof(AFSD_INO_T)));
1605
1606     /*
1607      * Set up all the pathnames we'll need for later.
1608      */
1609     sprintf(fullpn_DCacheFile,  "%s/%s", cacheBaseDir, DCACHEFILE);
1610     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
1611     sprintf(fullpn_VFile,       "%s/V",  cacheBaseDir);
1612     vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
1613
1614     /*
1615      * Start the RX listener.
1616      */
1617     if (afsd_debug)
1618          printf("%s: Calling AFSOP_RXLISTENER_DAEMON\n", rn);
1619     fork_syscall(AFSCALL_CALL, AFSOP_RXLISTENER_DAEMON, FALSE);
1620
1621     /*
1622      * Start the RX event handler.
1623      */
1624     if (afsd_debug)
1625          printf("%s: Calling AFSOP_RXEVENT_DAEMON\n", rn);
1626     fork_syscall(AFSCALL_CALL, AFSOP_RXEVENT_DAEMON, FALSE);
1627
1628     /*
1629      * Set up all the kernel processes needed for AFS.
1630      */
1631
1632     /* initialize AFS callback interface */
1633     {
1634       /* parse multihomed address files */
1635       char reason[1024];
1636       st=parseNetFiles(buffer,maskbuffer,mtubuffer,MAXIPADDRS,reason,
1637                     AFSDIR_CLIENT_NETINFO_FILEPATH,
1638                     AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
1639       if(st>0) 
1640         call_syscall(AFSCALL_CALL, AFSOP_ADVISEADDR, st, (long) (&buffer[0]), 
1641                      (long) (&maskbuffer[0]), (long) (&mtubuffer[0]));
1642       else {
1643         printf("ADVISEADDR: Error in specifying interface addresses:%s\n",reason);
1644         exit(1);
1645       }
1646     }
1647
1648     if (afsd_verbose)
1649         printf("%s: Forking rx callback listener.\n", rn);
1650     /* Child */
1651     if (preallocs < cacheStatEntries+50)
1652         preallocs = cacheStatEntries+50;
1653     fork_syscall(AFSCALL_CALL, AFSOP_START_RXCALLBACK, preallocs);
1654
1655     if (afsd_verbose)
1656         printf("%s: Forking AFS daemon.\n", rn);
1657     fork_syscall(AFSCALL_CALL, AFSOP_START_AFS);
1658
1659     if (afsd_verbose)
1660         printf("%s: Forking check server daemon.\n", rn);
1661     fork_syscall(AFSCALL_CALL, AFSOP_START_CS);
1662
1663     if (afsd_verbose)
1664         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
1665     for (i=0;i<nDaemons;i++) {
1666         fork_syscall(AFSCALL_CALL, AFSOP_START_BKG);
1667     }
1668
1669     /*
1670      * Tell the kernel about each cell in the configuration.
1671      */
1672     lookingForHomeCell = 1;
1673
1674     afsconf_CellApply(afs_cdir, ConfigCell, NULL);
1675
1676     /*
1677      * If we're still looking for the home cell after the whole cell
1678      * configuration database has been parsed, there's something wrong.
1679      */
1680     if (lookingForHomeCell) {
1681         printf("%s: Can't find home cell '%s' in cell database!\n",
1682                rn, afs_LclCellName);
1683     }
1684
1685     if (afsd_verbose)
1686         printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n",
1687                rn, rootVolume);
1688     call_syscall(AFSCALL_CALL, AFSOP_ROOTVOLUME, (long)rootVolume, 0, 0, 0);
1689
1690     /*
1691      * Tell the kernel some basic information about the workstation's cache.
1692      */
1693     if (afsd_verbose)
1694         printf("%s: Calling AFSOP_CACHEINIT: %d stat cache entries,"
1695                " %d optimum cache files, %d blocks in the cache,"
1696                " flags = 0x%x, dcache entries %d\n",
1697                rn, cacheStatEntries, cacheFiles, cacheBlocks, cacheFlags,
1698                dCacheSize);
1699     memset(&cparams, 0, sizeof(cparams));
1700     cparams.cacheScaches = cacheStatEntries;
1701     cparams.cacheFiles = cacheFiles;
1702     cparams.cacheBlocks = cacheBlocks;
1703     cparams.cacheDcaches = dCacheSize;
1704     cparams.cacheVolumes = vCacheSize;
1705     cparams.chunkSize = chunkSize;
1706     cparams.setTimeFlag = FALSE;
1707     cparams.memCacheFlag = cacheFlags;
1708     call_syscall(AFSCALL_CALL, AFSOP_CACHEINIT, (long)&cparams, 0, 0, 0);
1709     if (afsd_CloseSynch) 
1710       call_syscall(AFSCALL_CALL, AFSOP_CLOSEWAIT, 0, 0, 0, 0);
1711
1712     /*
1713      * Sweep the workstation AFS cache directory, remembering the inodes of
1714      * valid files and deleting extraneous files.  Keep sweeping until we
1715      * have the right number of data cache files or we've swept too many
1716      * times.
1717      */
1718     if (afsd_verbose)
1719         printf("%s: Sweeping workstation's AFS cache directory.\n",
1720                rn);
1721     cacheIteration = 0;
1722     /* Memory-cache based system doesn't need any of this */
1723     if(!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
1724         do {
1725             cacheIteration++;
1726             if (SweepAFSCache(&vFilesFound)) {
1727                 printf("%s: Error on sweep %d of workstation AFS cache \
1728                        directory.\n", rn, cacheIteration);
1729                 exit(1);
1730             }
1731             if (afsd_verbose)
1732                 printf("%s: %d out of %d data cache files found in sweep %d.\n",
1733                        rn, vFilesFound, cacheFiles, cacheIteration);
1734         } while ((vFilesFound < cacheFiles) &&
1735                  (cacheIteration < MAX_CACHE_LOOPS));
1736     } else if(afsd_verbose)
1737         printf("%s: Using memory cache, not swept\n", rn);
1738
1739     /*
1740      * Pass the kernel the name of the workstation cache file holding the 
1741      * dcache entries.
1742      */
1743     if (afsd_debug)
1744         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n",
1745                rn, fullpn_DCacheFile);
1746     /* once again, meaningless for a memory-based cache. */
1747     if(!(cacheFlags & AFSCALL_INIT_MEMCACHE))
1748         call_syscall(AFSCALL_CALL, AFSOP_CACHEINFO, (long)fullpn_DCacheFile,
1749                      0, 0, 0);
1750
1751
1752     /*
1753      * Pass the kernel the name of the workstation cache file holding the
1754      * volume information.
1755      */
1756     if (afsd_debug)
1757         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n",
1758                rn, fullpn_VolInfoFile);
1759     call_syscall(AFSCALL_CALL, AFSOP_VOLUMEINFO,(long)fullpn_VolInfoFile,
1760                  0, 0, 0);
1761
1762     /*
1763      * Pass the kernel the name of the afs logging file holding the volume
1764      * information.
1765      */
1766     if (afsd_debug)
1767         printf("%s: Calling AFSOP_AFSLOG: volume info file is '%s'\n",
1768                rn, fullpn_AFSLogFile);
1769     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... nor this ... */
1770         call_syscall(AFSCALL_CALL, AFSOP_AFSLOG,(long)fullpn_AFSLogFile,
1771                      0, 0, 0);
1772
1773     /*
1774      * Give the kernel the names of the AFS files cached on the workstation's
1775      * disk.
1776      */
1777     if (afsd_debug)
1778         printf("%s: Calling AFSOP_CACHEFILES for each of the %d files in '%s'\n",
1779                rn, cacheFiles, cacheBaseDir);
1780     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... and again ... */
1781         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
1782             call_syscall(AFSCALL_CALL, AFSOP_CACHEFILE,
1783                          (long)pathname_for_V[currVFile], 0, 0, 0);
1784         } /*end for*/
1785
1786 #ifndef NETSCAPE_NSAPI
1787     /*
1788      * Copy our tokens from the kernel to the user space client
1789      */
1790     for(i = 0 ; i < 200 ; i++) {
1791         /*
1792          * Get the i'th token from the kernel
1793          */
1794         memset((void *)&tbuffer[0], 0, sizeof(tbuffer));
1795         memcpy((void *)&tbuffer[0], (void *)&i, sizeof(int));
1796         iob.in = tbuffer;
1797         iob.in_size = sizeof(int);
1798         iob.out = tbuffer;
1799         iob.out_size = sizeof(tbuffer);
1800
1801 #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)
1802         rc = syscall(AFS_SYSCALL, AFSCALL_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1803 #elif defined(AFS_USR_SGI_ENV)
1804         rc = syscall(AFS_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1805 #else /* AFS_USR_AIX_ENV */
1806         rc = lpioctl(0, _VICEIOCTL(8), &iob, 0);
1807 #endif
1808         if (rc < 0) {
1809             usr_assert(errno == EDOM);
1810             break;
1811         }
1812
1813         /*
1814          * Now pass the token into the user space kernel
1815          */
1816         rc = uafs_SetTokens(tbuffer, iob.out_size);
1817         usr_assert(rc == 0);
1818     }
1819 #endif /* !NETSCAPE_NSAPI */
1820
1821     /*
1822      * All the necessary info has been passed into the kernel to run an AFS
1823      * system.  Give the kernel our go-ahead.
1824      */
1825     if (afsd_debug)
1826          printf("%s: Calling AFSOP_GO\n", rn);
1827      call_syscall(AFSCALL_CALL, AFSOP_GO, FALSE, 0, 0, 0);
1828
1829     /*
1830      * At this point, we have finished passing the kernel all the info 
1831      * it needs to set up the AFS.  Mount the AFS root.
1832      */
1833     printf("%s: All AFS daemons started.\n", rn);
1834
1835     if (afsd_verbose)
1836         printf("%s: Forking trunc-cache daemon.\n", rn);
1837     fork_syscall(AFSCALL_CALL, AFSOP_START_TRUNCDAEMON);
1838
1839     /*
1840      * Mount the AFS filesystem
1841      */
1842     AFS_GLOCK();
1843     rc = afs_mount(&afs_RootVfs, NULL, NULL);
1844     usr_assert(rc == 0);
1845     rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1846     usr_assert(rc == 0);
1847     AFS_GUNLOCK();
1848
1849     /*
1850      * initialize the current directory to the AFS root
1851      */
1852     afs_CurrentDir = afs_RootVnode;
1853     VN_HOLD(afs_CurrentDir);
1854
1855     return;
1856 }
1857
1858 void uafs_Shutdown(void)
1859 {
1860     int rc;
1861
1862     printf("\n");
1863
1864     AFS_GLOCK();
1865     VN_RELE(afs_CurrentDir);
1866     rc = afs_unmount(&afs_RootVfs);
1867     usr_assert(rc == 0);
1868     AFS_GUNLOCK();
1869
1870     printf("\n");
1871 }
1872
1873 /*
1874  * Donate the current thread to the RX server pool.
1875  */
1876 void uafs_RxServerProc(void)
1877 {
1878     osi_socket sock;
1879     int threadID;
1880     struct rx_call *newcall = NULL;
1881
1882     rxi_MorePackets(2); /* alloc more packets */
1883     threadID = rxi_availProcs++;
1884
1885     while(1) {
1886         sock = OSI_NULLSOCKET;
1887         rxi_ServerProc(threadID, newcall, &sock);
1888         if (sock == OSI_NULLSOCKET) {
1889             break;
1890         }
1891         newcall = NULL;
1892         threadID = -1;
1893         rxi_ListenerProc(sock, &threadID, &newcall);
1894         /* assert(threadID != -1); */
1895         /* assert(newcall != NULL); */
1896     }
1897 }
1898
1899 struct syscallThreadArgs {
1900     long syscall;
1901     long afscall;
1902     long param1;
1903     long param2;
1904     long param3;
1905     long param4;
1906 };
1907
1908 #ifdef NETSCAPE_NSAPI
1909 void syscallThread(void *argp)
1910 #else /* NETSCAPE_NSAPI */
1911 void *syscallThread(void *argp)
1912 #endif /* NETSCAPE_NSAPI */
1913 {
1914     int i;
1915     struct usr_ucred *crp;
1916     struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1917
1918     /*
1919      * AFS daemons run authenticated
1920      */
1921     u.u_viceid = getuid();
1922     crp = u.u_cred;
1923     crp->cr_uid = getuid();
1924     crp->cr_ruid = getuid();
1925     crp->cr_suid = getuid();
1926     crp->cr_groups[0] = getgid();
1927     crp->cr_ngroups = 1;
1928     for (i = 1 ; i < NGROUPS ; i++) {
1929         crp->cr_groups[i] = NOGROUP;
1930     }
1931
1932     call_syscall(sysArgsP->syscall, sysArgsP->afscall,
1933                  sysArgsP->param1, sysArgsP->param2,
1934                  sysArgsP->param3, sysArgsP->param4);
1935
1936     afs_osi_Free(argp, -1);
1937 }
1938
1939 fork_syscall(syscall, afscall, param1, param2, param3, param4)
1940 long syscall, afscall, param1, param2, param3, param4;
1941 {
1942     usr_thread_t tid;
1943     struct syscallThreadArgs *sysArgsP;
1944
1945     sysArgsP = (struct syscallThreadArgs *)
1946                afs_osi_Alloc(sizeof(struct syscallThreadArgs));
1947     usr_assert(sysArgsP != NULL);
1948     sysArgsP->syscall = syscall;
1949     sysArgsP->afscall = afscall;
1950     sysArgsP->param1 = param1;
1951     sysArgsP->param2 = param2;
1952     sysArgsP->param3 = param3;
1953     sysArgsP->param4 = param4;
1954
1955     usr_thread_create(&tid, syscallThread, sysArgsP);
1956     usr_thread_detach(tid);
1957 }
1958
1959 call_syscall(syscall, afscall, param1, param2, param3, param4)
1960 long syscall, afscall, param1, param2, param3, param4;
1961 {
1962     int code = 0;
1963     struct a {
1964         long syscall;
1965         long afscall;
1966         long parm1;
1967         long parm2;
1968         long parm3;
1969         long parm4;
1970     } a;
1971
1972     a.syscall = syscall;
1973     a.afscall = afscall;
1974     a.parm1 = param1;
1975     a.parm2 = param2;
1976     a.parm3 = param3;
1977     a.parm4 = param4;
1978
1979     u.u_error = 0;
1980     u.u_ap = (char *)&a;
1981
1982     code = Afs_syscall();
1983     return code;
1984 }
1985
1986 int uafs_SetTokens(char *tbuffer, int tlen)
1987 {
1988     int rc;
1989     struct afs_ioctl iob;
1990     char outbuf[1024];
1991
1992     iob.in = tbuffer;
1993     iob.in_size = tlen;
1994     iob.out = &outbuf[0];
1995     iob.out_size = sizeof(outbuf);
1996     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
1997     if (rc != 0) {
1998         errno = rc;
1999         return -1;
2000     }
2001     return 0;
2002 }
2003
2004 int uafs_RPCStatsEnableProc(void)
2005 {
2006     int rc;
2007     struct afs_ioctl iob;
2008     afs_int32 flag;
2009
2010     flag = AFSCALL_RXSTATS_ENABLE;
2011     iob.in = (char *)&flag;
2012     iob.in_size = sizeof(afs_int32);
2013     iob.out = NULL;
2014     iob.out_size = 0;
2015     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2016     if (rc != 0) {
2017         errno = rc;
2018         return -1;
2019     }
2020     return rc;
2021 }
2022
2023 int uafs_RPCStatsDisableProc(void)
2024 {
2025     int rc;
2026     struct afs_ioctl iob;
2027     afs_int32 flag;
2028
2029     flag = AFSCALL_RXSTATS_DISABLE;
2030     iob.in = (char *)&flag;
2031     iob.in_size = sizeof(afs_int32);
2032     iob.out = NULL;
2033     iob.out_size = 0;
2034     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2035     if (rc != 0) {
2036         errno = rc;
2037         return -1;
2038     }
2039     return rc;
2040 }
2041
2042 int uafs_RPCStatsClearProc(void)
2043 {
2044     int rc;
2045     struct afs_ioctl iob;
2046     afs_int32 flag;
2047
2048     flag = AFSCALL_RXSTATS_CLEAR;
2049     iob.in = (char *)&flag;
2050     iob.in_size = sizeof(afs_int32);
2051     iob.out = NULL;
2052     iob.out_size = 0;
2053     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2054     if (rc != 0) {
2055         errno = rc;
2056         return -1;
2057     }
2058     return rc;
2059 }
2060
2061 int uafs_RPCStatsEnablePeer(void)
2062 {
2063     int rc;
2064     struct afs_ioctl iob;
2065     afs_int32 flag;
2066
2067     flag = AFSCALL_RXSTATS_ENABLE;
2068     iob.in = (char *)&flag;
2069     iob.in_size = sizeof(afs_int32);
2070     iob.out = NULL;
2071     iob.out_size = 0;
2072     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2073     if (rc != 0) {
2074         errno = rc;
2075         return -1;
2076     }
2077     return rc;
2078 }
2079
2080 int uafs_RPCStatsDisablePeer(void)
2081 {
2082     int rc;
2083     struct afs_ioctl iob;
2084     afs_int32 flag;
2085
2086     flag = AFSCALL_RXSTATS_DISABLE;
2087     iob.in = (char *)&flag;
2088     iob.in_size = sizeof(afs_int32);
2089     iob.out = NULL;
2090     iob.out_size = 0;
2091     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2092     if (rc != 0) {
2093         errno = rc;
2094         return -1;
2095     }
2096     return rc;
2097 }
2098
2099 int uafs_RPCStatsClearPeer(void)
2100 {
2101     int rc;
2102     struct afs_ioctl iob;
2103     afs_int32 flag;
2104
2105     flag = AFSCALL_RXSTATS_CLEAR;
2106     iob.in = (char *)&flag;
2107     iob.in_size = sizeof(afs_int32);
2108     iob.out = NULL;
2109     iob.out_size = 0;
2110     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2111     if (rc != 0) {
2112         errno = rc;
2113         return -1;
2114     }
2115     return rc;
2116 }
2117
2118 /*
2119  * Lookup a file or directory given its path.
2120  * Call VN_HOLD on the output vnode if successful.
2121  * Returns zero on success, error code on failure.
2122  *
2123  * Note: Caller must hold the AFS global lock.
2124  */
2125 int uafs_LookupName(
2126     char *path,
2127     struct usr_vnode *parentVp,
2128     struct usr_vnode **vpp,
2129     int follow,
2130     int no_eval_mtpt)
2131 {
2132     int code;
2133     int linkCount;
2134     struct usr_vnode *vp;
2135     struct usr_vnode *nextVp;
2136     struct usr_vnode *linkVp;
2137     char *tmpPath;
2138     char *pathP;
2139     char *nextPathP;
2140
2141     AFS_ASSERT_GLOCK();
2142
2143     /*
2144      * Absolute paths must start with the AFS mount point.
2145      */
2146     if (path[0] != '/') {
2147         vp = parentVp;
2148     } else {
2149         path = uafs_afsPathName(path);
2150         if (path == NULL) {
2151             return ENOENT;
2152         }
2153         vp = afs_RootVnode;
2154     }
2155
2156     /*
2157      * Loop through the path looking for the new directory
2158      */
2159     tmpPath = afs_osi_Alloc(strlen(path)+1);
2160     usr_assert(tmpPath != NULL);
2161     strcpy(tmpPath, path);
2162     VN_HOLD(vp);
2163     pathP = tmpPath;
2164     while (pathP != NULL && *pathP != '\0') {
2165         usr_assert(*pathP != '/');
2166
2167         /*
2168          * terminate the current component and skip over slashes
2169          */
2170         nextPathP = strchr(pathP, '/');
2171         if (nextPathP != NULL) {
2172             while (*nextPathP == '/') {
2173                 *(nextPathP++) = '\0';
2174             }
2175         }
2176
2177         /*
2178          * Don't call afs_lookup on non-directories
2179          */
2180         if (vp->v_type != VDIR) {
2181             VN_RELE(vp);
2182             afs_osi_Free(tmpPath, strlen(path)+1);
2183             return ENOTDIR;
2184         }
2185
2186         if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
2187             /*
2188              * The AFS root is its own parent
2189              */
2190             nextVp = afs_RootVnode;
2191         } else {
2192             /*
2193              * We need execute permission to search a directory
2194              */
2195             code = afs_access(vp, VEXEC, u.u_cred);
2196             if (code != 0) {
2197                 VN_RELE(vp);
2198                 afs_osi_Free(tmpPath, strlen(path)+1);
2199                 return code;
2200             }
2201
2202             /*
2203              * lookup the next component in the path, we can release the
2204              * subdirectory since we hold the global lock
2205              */
2206             nextVp = NULL;
2207 #ifdef AFS_WEB_ENHANCEMENTS
2208             if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
2209               code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
2210             else
2211               code = afs_lookup(vp, pathP, &nextVp, u.u_cred, AFS_LOOKUP_NOEVAL);
2212 #else
2213             code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0);
2214 #endif /* AFS_WEB_ENHANCEMENTS */
2215             if (code != 0) {
2216                 VN_RELE(vp);
2217                 afs_osi_Free(tmpPath, strlen(path)+1);
2218                 return code;
2219             }
2220         }
2221
2222         /*
2223          * Follow symbolic links for parent directories and
2224          * for leaves when the follow flag is set.
2225          */
2226         if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
2227             linkCount = 0;
2228             while(nextVp->v_type == VLNK) {
2229                 if (++linkCount > MAX_OSI_LINKS) {
2230                     VN_RELE(vp);
2231                     VN_RELE(nextVp);
2232                     afs_osi_Free(tmpPath, strlen(path)+1);
2233                     return code;
2234                 }
2235                 code = uafs_LookupLink(nextVp, vp, &linkVp);
2236                 if (code) {
2237                     VN_RELE(vp);
2238                     VN_RELE(nextVp);
2239                     afs_osi_Free(tmpPath, strlen(path)+1);
2240                     return code;
2241                 }
2242                 VN_RELE(nextVp);
2243                 nextVp = linkVp;
2244             }
2245         }
2246
2247         VN_RELE(vp);
2248         vp = nextVp;
2249         pathP = nextPathP;
2250     }
2251
2252     /*
2253      * Special case, nextPathP is non-null if pathname ends in slash
2254      */
2255     if (nextPathP != NULL && vp->v_type != VDIR) {
2256         VN_RELE(vp);
2257         afs_osi_Free(tmpPath, strlen(path)+1);
2258         return ENOTDIR;
2259     }
2260
2261     afs_osi_Free(tmpPath, strlen(path)+1);
2262     *vpp = vp;
2263     return 0;
2264 }
2265
2266 /*
2267  * Lookup the target of a symbolic link
2268  * Call VN_HOLD on the output vnode if successful.
2269  * Returns zero on success, error code on failure.
2270  *
2271  * Note: Caller must hold the AFS global lock.
2272  */
2273 int uafs_LookupLink(
2274     struct usr_vnode *vp,
2275     struct usr_vnode *parentVp,
2276     struct usr_vnode **vpp)
2277 {
2278     int code;
2279     int len;
2280     char *pathP;
2281     struct usr_vnode *linkVp;
2282     struct usr_uio uio;
2283     struct iovec iov[1];
2284
2285     AFS_ASSERT_GLOCK();
2286
2287     pathP = afs_osi_Alloc(MAX_OSI_PATH+1);
2288     usr_assert(pathP != NULL);
2289
2290     /*
2291      * set up the uio buffer
2292      */
2293     iov[0].iov_base = pathP;
2294     iov[0].iov_len = MAX_OSI_PATH+1;
2295     uio.uio_iov = &iov[0];
2296     uio.uio_iovcnt = 1;
2297     uio.uio_offset = 0;
2298     uio.uio_segflg = 0;
2299     uio.uio_fmode = FREAD;
2300     uio.uio_resid = MAX_OSI_PATH+1;
2301
2302     /*
2303      * Read the link data
2304      */
2305     code = afs_readlink(vp, &uio, u.u_cred);
2306     if (code) {
2307         afs_osi_Free(pathP, MAX_OSI_PATH+1);
2308         return code;
2309     }
2310     len = MAX_OSI_PATH + 1 - uio.uio_resid;
2311     pathP[len] = '\0';
2312
2313     /*
2314      * Find the target of the symbolic link
2315      */
2316     code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
2317     if (code) {
2318         afs_osi_Free(pathP, MAX_OSI_PATH+1);
2319         return code;
2320     }
2321
2322     afs_osi_Free(pathP, MAX_OSI_PATH+1);
2323     *vpp = linkVp;
2324     return 0;
2325 }
2326
2327 /*
2328  * Lookup the parent of a file or directory given its path
2329  * Call VN_HOLD on the output vnode if successful.
2330  * Returns zero on success, error code on failure.
2331  *
2332  * Note: Caller must hold the AFS global lock.
2333  */
2334 int uafs_LookupParent(
2335     char *path,
2336     struct usr_vnode **vpp)
2337 {
2338     int len;
2339     int code;
2340     char *pathP;
2341     struct usr_vnode *parentP;
2342
2343     AFS_ASSERT_GLOCK();
2344
2345     /*
2346      * Absolute path names must start with the AFS mount point.
2347      */
2348     if (*path == '/') {
2349         pathP = uafs_afsPathName(path);
2350         if (pathP == NULL) {
2351             return ENOENT;
2352         }
2353     }
2354
2355     /*
2356      * Find the length of the parent path
2357      */
2358     len = strlen(path);
2359     while(len > 0 && path[len-1] == '/') {
2360         len--;
2361     }
2362     if (len == 0) {
2363         return EINVAL;
2364     }
2365     while(len > 0 && path[len-1] != '/') {
2366         len--;
2367     }
2368     if (len == 0) {
2369         return EINVAL;
2370     }
2371
2372     pathP = afs_osi_Alloc(len);
2373     usr_assert(pathP != NULL);
2374     memcpy(pathP, path, len-1);
2375     pathP[len-1] = '\0';
2376
2377     /*
2378      * look up the parent
2379      */
2380     code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
2381     afs_osi_Free(pathP, len);
2382     if (code != 0) {
2383         return code;
2384     }
2385     if (parentP->v_type != VDIR) {
2386         VN_RELE(parentP);
2387         return ENOTDIR;
2388     }
2389
2390     *vpp = parentP;
2391     return 0;
2392 }
2393
2394 /*
2395  * Return a pointer to the first character in the last component
2396  * of a pathname
2397  */
2398 char *uafs_LastPath(char *path)
2399 {
2400     int len;
2401
2402     len = strlen(path);
2403     while (len > 0 && path[len-1] == '/') {
2404         len--;
2405     }
2406     while (len > 0 && path[len-1] != '/') {
2407         len--;
2408     }
2409     if (len == 0) {
2410         return NULL;
2411     }
2412     return path + len;
2413 }
2414
2415 /*
2416  * Set the working directory.
2417  */
2418 int uafs_chdir(char *path)
2419 {
2420     int retval;
2421     AFS_GLOCK();
2422     retval = uafs_chdir_r(path);
2423     AFS_GUNLOCK();
2424     return retval;
2425 }
2426
2427 int uafs_chdir_r(char *path)
2428 {
2429     int code;
2430     struct vnode *dirP;
2431
2432     code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
2433     if (code != 0) {
2434         errno = code;
2435         return -1;
2436     }
2437     if (dirP->v_type != VDIR) {
2438         VN_RELE(dirP);
2439         errno = ENOTDIR;
2440         return -1;
2441     }
2442     VN_RELE(afs_CurrentDir);
2443     afs_CurrentDir = dirP;
2444     return 0;
2445 }
2446
2447 /*
2448  * Create a directory.
2449  */
2450 int uafs_mkdir(char *path, int mode)
2451 {
2452     int retval;
2453     AFS_GLOCK();
2454     retval = uafs_mkdir_r(path, mode);
2455     AFS_GUNLOCK();
2456     return retval;
2457 }
2458
2459 int uafs_mkdir_r(char *path, int mode)
2460 {
2461     int code;
2462     char *nameP;
2463     struct vnode *parentP;
2464     struct vnode *dirP;
2465     struct usr_vattr attrs;
2466
2467     if (uafs_IsRoot(path)) {
2468         return EACCES;
2469     }
2470
2471     /*
2472      * Look up the parent directory.
2473      */
2474     nameP = uafs_LastPath(path);
2475     if (nameP != NULL) {
2476         code = uafs_LookupParent(path, &parentP);
2477         if (code != 0) {
2478             errno = code;
2479             return -1;
2480         }
2481     } else {
2482         parentP = afs_CurrentDir;
2483         nameP = path;
2484         VN_HOLD(parentP);
2485     }
2486
2487     /*
2488      * Make sure the directory has at least one character
2489      */
2490     if (*nameP == '\0') {
2491         VN_RELE(parentP);
2492         errno = EINVAL;
2493         return -1;
2494     }
2495
2496     /*
2497      * Create the directory
2498      */
2499     usr_vattr_null(&attrs);
2500     attrs.va_type = VREG;
2501     attrs.va_mode = mode;
2502     attrs.va_uid = u.u_cred->cr_uid;
2503     attrs.va_gid = u.u_cred->cr_gid;
2504     dirP = NULL;
2505     code = afs_mkdir(parentP, nameP, &attrs, &dirP, u.u_cred);
2506     VN_RELE(parentP);
2507     if (code != 0) {
2508         errno = code;
2509         return -1;
2510     }
2511     VN_RELE(dirP);
2512     return 0;
2513 }
2514
2515 /*
2516  * Return 1 if path is the AFS root, otherwise return 0
2517  */
2518 int uafs_IsRoot(char *path)
2519 {
2520     while(*path == '/' && *(path+1) == '/') {
2521         path++;
2522     }
2523     if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2524         return 0;
2525     }
2526     path += afs_mountDirLen;
2527     while (*path == '/') {
2528         path++;
2529     }
2530     if (*path != '\0') {
2531         return 0;
2532     }
2533     return 1;
2534 }
2535
2536 /*
2537  * Open a file
2538  * Note: file name may not end in a slash.
2539  */
2540 int uafs_open(char *path, int flags, int mode)
2541 {
2542     int retval;
2543     AFS_GLOCK();
2544     retval = uafs_open_r(path, flags, mode);
2545     AFS_GUNLOCK();
2546     return retval;
2547 }
2548
2549 int uafs_open_r(char *path, int flags, int mode)
2550 {
2551     int fd;
2552     int code;
2553     int openFlags;
2554     int fileMode;
2555     struct usr_vnode *fileP;
2556     struct usr_vnode *dirP;
2557     struct usr_vattr attrs;
2558     char *nameP;
2559
2560     if (uafs_IsRoot(path)) {
2561         fileP = afs_RootVnode;
2562         VN_HOLD(fileP);
2563     } else {
2564         /*
2565          * Look up the parent directory.
2566          */
2567         nameP = uafs_LastPath(path);
2568         if (nameP != NULL) {
2569             code = uafs_LookupParent(path, &dirP);
2570             if (code != 0) {
2571                 errno = code;
2572                 return -1;
2573             }
2574         } else {
2575             dirP = afs_CurrentDir;
2576             nameP = path;
2577             VN_HOLD(dirP);
2578         }
2579
2580         /*
2581          * Make sure the filename has at least one character
2582          */
2583         if (*nameP == '\0') {
2584             VN_RELE(dirP);
2585             errno = EINVAL;
2586             return -1;
2587         }
2588
2589         /*
2590          * Get the VNODE for this file
2591          */
2592         if (flags & O_CREAT) {
2593             usr_vattr_null(&attrs);
2594             attrs.va_type = VREG;
2595             attrs.va_mode = mode;
2596             attrs.va_uid = u.u_cred->cr_uid;
2597             attrs.va_gid = u.u_cred->cr_gid;
2598             if (flags & O_TRUNC) {
2599                 attrs.va_size = 0;
2600             }
2601             fileP = NULL;
2602             code = afs_create(dirP, nameP, &attrs,
2603                               (flags & O_EXCL)?usr_EXCL:usr_NONEXCL,
2604                               mode, &fileP, u.u_cred);
2605             VN_RELE(dirP);
2606             if (code != 0) {
2607                 errno = code;
2608                 return -1;
2609             }
2610         } else {
2611             fileP = NULL;
2612             code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2613             VN_RELE(dirP);
2614             if (code != 0) {
2615                 errno = code;
2616                 return -1;
2617             }
2618
2619             /*
2620              * Check whether we have access to this file
2621              */
2622             fileMode = 0;
2623             if (flags & (O_RDONLY|O_RDWR)) {
2624                 fileMode |= VREAD;
2625             }
2626             if (flags & (O_WRONLY|O_RDWR)) {
2627                 fileMode |= VWRITE;
2628             }
2629             if (!fileMode) fileMode = VREAD;  /* since O_RDONLY is 0 */
2630             code = afs_access(fileP, fileMode, u.u_cred);
2631             if (code != 0) {
2632                 VN_RELE(fileP);
2633                 errno = code;
2634                 return -1;
2635             }
2636
2637             /*
2638              * Get the file attributes, all we need is the size
2639              */
2640             code = afs_getattr(fileP, &attrs, u.u_cred);
2641             if (code != 0) {
2642                 VN_RELE(fileP);
2643                 errno = code;
2644                 return -1;
2645             }
2646         }
2647     }
2648
2649     /*
2650      * Setup the open flags
2651      */
2652     openFlags = 0;
2653     if (flags & O_TRUNC) {
2654         openFlags |= FTRUNC;
2655     }
2656     if (flags & O_APPEND) {
2657         openFlags |= FAPPEND;
2658     }
2659     if (flags & O_SYNC) {
2660         openFlags |= FSYNC;
2661     }
2662     if (flags & O_SYNC) {
2663         openFlags |= FSYNC;
2664     }
2665     if (flags & (O_RDONLY|O_RDWR)) {
2666         openFlags |= FREAD;
2667     }
2668     if (flags & (O_WRONLY|O_RDWR)) {
2669         openFlags |= FWRITE;
2670     }
2671
2672     /*
2673      * Truncate if necessary
2674      */
2675     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2676         usr_vattr_null(&attrs);
2677         attrs.va_size = 0;
2678         code = afs_setattr(fileP, &attrs, u.u_cred);
2679         if (code != 0) {
2680             VN_RELE(fileP);
2681             errno = code;
2682             return -1;
2683         }
2684     }
2685
2686     /*
2687      * do the open
2688      */
2689     code = afs_open(&fileP, openFlags, u.u_cred);
2690     if (code != 0) {
2691         VN_RELE(fileP);
2692         errno = code;
2693         return -1;
2694     }
2695
2696     /*
2697      * Put the vnode pointer into the file table
2698      */
2699     for (fd = 0 ; fd < MAX_OSI_FILES ; fd++) {
2700         if (afs_FileTable[fd] == NULL) {
2701             afs_FileTable[fd] = fileP;
2702             afs_FileFlags[fd] = openFlags;
2703             if (flags & O_APPEND) {
2704                 afs_FileOffsets[fd] = attrs.va_size;
2705             } else {
2706                 afs_FileOffsets[fd] = 0;
2707             }
2708             break;
2709         }
2710     }
2711     if (fd == MAX_OSI_FILES) {
2712         VN_RELE(fileP);
2713         errno = ENFILE;
2714         return -1;
2715     }
2716
2717     return fd;
2718 }
2719
2720 /*
2721  * Create a file
2722  */
2723 int uafs_creat(char *path, int mode)
2724 {
2725     int rc;
2726     rc = uafs_open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
2727     return rc;
2728 }
2729
2730 int uafs_creat_r(char *path, int mode)
2731 {
2732     int rc;
2733     rc = uafs_open_r(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
2734     return rc;
2735 }
2736
2737 /*
2738  * Write to a file
2739  */
2740 int uafs_write(int fd, char *buf, int len)
2741 {
2742     int retval;
2743     AFS_GLOCK();
2744     retval = uafs_write_r(fd, buf, len);
2745     AFS_GUNLOCK();
2746     return retval;
2747 }
2748
2749 int uafs_write_r(int fd, char *buf, int len)
2750 {
2751     int code;
2752     struct usr_uio uio;
2753     struct iovec iov[1];
2754     struct usr_vnode *fileP;
2755
2756     /*
2757      * Make sure this is an open file
2758      */
2759     fileP = afs_FileTable[fd];
2760     if (fileP == NULL) {
2761         errno = EBADF;
2762         return -1;
2763     }
2764
2765     /*
2766      * set up the uio buffer
2767      */
2768     iov[0].iov_base = buf;
2769     iov[0].iov_len = len;
2770     uio.uio_iov = &iov[0];
2771     uio.uio_iovcnt = 1;
2772     uio.uio_offset = afs_FileOffsets[fd];
2773     uio.uio_segflg = 0;
2774     uio.uio_fmode = FWRITE;
2775     uio.uio_resid = len;
2776
2777     /*
2778      * do the write
2779      */
2780
2781     code = afs_write(fileP, &uio, afs_FileFlags[fd], u.u_cred, 0);
2782     if (code) {
2783         errno = code;
2784         return -1;
2785     }
2786
2787     afs_FileOffsets[fd] = uio.uio_offset;
2788     return(len - uio.uio_resid);
2789 }
2790
2791 /*
2792  * Read from a file
2793  */
2794 int uafs_read(int fd, char *buf, int len)
2795 {
2796     int retval;
2797     AFS_GLOCK();
2798     retval = uafs_read_r(fd, buf, len);
2799     AFS_GUNLOCK();
2800     return retval;
2801 }
2802
2803 int uafs_read_r(int fd, char *buf, int len)
2804 {
2805     int code;
2806     struct usr_uio uio;
2807     struct iovec iov[1];
2808     struct usr_vnode *fileP;
2809     struct usr_buf *bufP;
2810
2811     /*
2812      * Make sure this is an open file
2813      */
2814     fileP = afs_FileTable[fd];
2815     if (fileP == NULL) {
2816         errno = EBADF;
2817         return -1;
2818     }
2819
2820     /*
2821      * set up the uio buffer
2822      */
2823     iov[0].iov_base = buf;
2824     iov[0].iov_len = len;
2825     uio.uio_iov = &iov[0];
2826     uio.uio_iovcnt = 1;
2827     uio.uio_offset = afs_FileOffsets[fd];
2828     uio.uio_segflg = 0;
2829     uio.uio_fmode = FREAD;
2830     uio.uio_resid = len;
2831
2832     /*
2833      * do the read
2834      */
2835     code = afs_read(fileP, &uio, u.u_cred, 0, &bufP, 0);
2836     if (code) {
2837         errno = code;
2838         return -1;
2839     }
2840
2841     afs_FileOffsets[fd] = uio.uio_offset;
2842     return(len - uio.uio_resid);
2843 }
2844
2845 /*
2846  * Copy the attributes of a file into a stat structure.
2847  *
2848  * NOTE: Caller must hold the global AFS lock.
2849  */
2850 int uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2851 {
2852     int code;
2853     struct usr_vattr attrs;
2854
2855     AFS_ASSERT_GLOCK();
2856
2857     /*
2858      * Get the attributes
2859      */
2860     code = afs_getattr(vp, &attrs, u.u_cred);
2861     if (code != 0) {
2862         return code;
2863     }
2864
2865     /*
2866      * Copy the attributes, zero fields that aren't set
2867      */
2868     memset((void *)stats, 0, sizeof(struct stat));
2869     stats->st_dev = -1;
2870     stats->st_ino = attrs.va_nodeid;
2871     stats->st_mode = attrs.va_mode;
2872     stats->st_nlink = attrs.va_nlink;
2873     stats->st_uid = attrs.va_uid;
2874     stats->st_gid = attrs.va_gid;
2875     stats->st_rdev = attrs.va_rdev;
2876     stats->st_size = attrs.va_size;
2877     stats->st_atime = attrs.va_atime.tv_sec;
2878     stats->st_mtime = attrs.va_mtime.tv_sec;
2879     stats->st_ctime = attrs.va_ctime.tv_sec;
2880     stats->st_blksize = attrs.va_blocksize;
2881     stats->st_blocks = attrs.va_blocks;
2882
2883     return 0;
2884 }
2885
2886 /*
2887  * Get the attributes of a file, do follow links
2888  */
2889 int uafs_stat(
2890     char *path,
2891     struct stat *buf)
2892 {
2893     int retval;
2894     AFS_GLOCK();
2895     retval = uafs_stat_r(path, buf);
2896     AFS_GUNLOCK();
2897     return retval;
2898 }
2899
2900 int uafs_stat_r(
2901     char *path,
2902     struct stat *buf)
2903 {
2904     int code;
2905     struct vnode *vp;
2906
2907     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2908     if (code != 0) {
2909         errno = code;
2910         return -1;
2911     }
2912     code = uafs_GetAttr(vp, buf);
2913     VN_RELE(vp);
2914     if (code) {
2915         errno = code;
2916         return -1;
2917     }
2918     return 0;
2919 }
2920
2921 /*
2922  * Get the attributes of a file, don't follow links
2923  */
2924 int uafs_lstat(
2925     char *path,
2926     struct stat *buf)
2927 {
2928     int retval;
2929     AFS_GLOCK();
2930     retval = uafs_lstat_r(path, buf);
2931     AFS_GUNLOCK();
2932     return retval;
2933 }
2934
2935 int uafs_lstat_r(
2936     char *path,
2937     struct stat *buf)
2938 {
2939     int code;
2940     struct vnode *vp;
2941
2942     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2943     if (code != 0) {
2944         errno = code;
2945         return -1;
2946     }
2947     code = uafs_GetAttr(vp, buf);
2948     VN_RELE(vp);
2949     if (code) {
2950         errno = code;
2951         return -1;
2952     }
2953     return 0;
2954 }
2955
2956 /*
2957  * Get the attributes of an open file
2958  */
2959 int uafs_fstat(
2960     int fd,
2961     struct stat *buf)
2962 {
2963     int retval;
2964     AFS_GLOCK();
2965     retval = uafs_fstat_r(fd, buf);
2966     AFS_GUNLOCK();
2967     return retval;
2968 }
2969
2970 int uafs_fstat_r(
2971     int fd,
2972     struct stat *buf)
2973 {
2974     int code;
2975     struct vnode *vp;
2976
2977     vp = afs_FileTable[fd];
2978     if (vp == NULL) {
2979         errno = EBADF;
2980         return -1;
2981     }
2982     code = uafs_GetAttr(vp, buf);
2983     VN_RELE(vp);
2984     if (code) {
2985         errno = code;
2986         return -1;
2987     }
2988     return 0;
2989 }
2990
2991 /*
2992  * change the permissions on a file
2993  */
2994 int uafs_chmod(
2995     char *path,
2996     int mode)
2997 {
2998     int retval;
2999     AFS_GLOCK();
3000     retval = uafs_chmod_r(path, mode);
3001     AFS_GUNLOCK();
3002     return retval;
3003 }
3004
3005 int uafs_chmod_r(
3006     char *path,
3007     int mode)
3008 {
3009     int code;
3010     struct vnode *vp;
3011     struct usr_vattr attrs;
3012
3013     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3014     if (code != 0) {
3015         errno = code;
3016         return -1;
3017     }
3018     usr_vattr_null(&attrs);
3019     attrs.va_mode = mode;
3020     code = afs_setattr(vp, &attrs, u.u_cred);
3021     VN_RELE(vp);
3022     if (code != 0) {
3023         errno = code;
3024         return -1;
3025     }
3026     return 0;
3027 }
3028
3029 /*
3030  * change the permissions on an open file
3031  */
3032 int uafs_fchmod(
3033     int fd,
3034     int mode)
3035 {
3036     int retval;
3037     AFS_GLOCK();
3038     retval = uafs_fchmod_r(fd, mode);
3039     AFS_GUNLOCK();
3040     return retval;
3041 }
3042
3043 int uafs_fchmod_r(
3044     int fd,
3045     int mode)
3046 {
3047     int code;
3048     struct vnode *vp;
3049     struct usr_vattr attrs;
3050
3051     vp = afs_FileTable[fd];
3052     if (vp == NULL) {
3053         errno = EBADF;
3054         return -1;
3055     }
3056     usr_vattr_null(&attrs);
3057     attrs.va_mode = mode;
3058     code = afs_setattr(vp, &attrs, u.u_cred);
3059     if (code != 0) {
3060         errno = code;
3061         return -1;
3062     }
3063     return 0;
3064 }
3065
3066 /*
3067  * truncate a file
3068  */
3069 int uafs_truncate(
3070     char *path,
3071     int length)
3072 {
3073     int retval;
3074     AFS_GLOCK();
3075     retval = uafs_truncate_r(path, length);
3076     AFS_GUNLOCK();
3077     return retval;
3078 }
3079
3080 int uafs_truncate_r(
3081     char *path,
3082     int length)
3083 {
3084     int code;
3085     struct vnode *vp;
3086     struct usr_vattr attrs;
3087
3088     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3089     if (code != 0) {
3090         errno = code;
3091         return -1;
3092     }
3093     usr_vattr_null(&attrs);
3094     attrs.va_size = length;
3095     code = afs_setattr(vp, &attrs, u.u_cred);
3096     VN_RELE(vp);
3097     if (code != 0) {
3098         errno = code;
3099         return -1;
3100     }
3101     return 0;
3102 }
3103
3104 /*
3105  * truncate an open file
3106  */
3107 int uafs_ftruncate(
3108     int fd,
3109     int length)
3110 {
3111     int retval;
3112     AFS_GLOCK();
3113     retval = uafs_ftruncate_r(fd, length);
3114     AFS_GUNLOCK();
3115     return retval;
3116 }
3117
3118 int uafs_ftruncate_r(
3119     int fd,
3120     int length)
3121 {
3122     int code;
3123     struct vnode *vp;
3124     struct usr_vattr attrs;
3125
3126     vp = afs_FileTable[fd];
3127     if (vp == NULL) {
3128         errno = EBADF;
3129         return -1;
3130     }
3131     usr_vattr_null(&attrs);
3132     attrs.va_size = length;
3133     code = afs_setattr(vp, &attrs, u.u_cred);
3134     if (code != 0) {
3135         errno = code;
3136         return -1;
3137     }
3138     return 0;
3139 }
3140
3141 /*
3142  * set the read/write file pointer of an open file
3143  */
3144 int uafs_lseek(
3145     int fd,
3146     int offset,
3147     int whence)
3148 {
3149     int retval;
3150     AFS_GLOCK();
3151     retval = uafs_lseek_r(fd, offset, whence);
3152     AFS_GUNLOCK();
3153     return retval;
3154 }
3155
3156 int uafs_lseek_r(
3157     int fd,
3158     int offset,
3159     int whence)
3160 {
3161     int code;
3162     int newpos;
3163     struct usr_vattr attrs;
3164     struct usr_vnode *vp;
3165
3166     vp = afs_FileTable[fd];
3167     if (vp == NULL) {
3168         errno = EBADF;
3169         return -1;
3170     }
3171     switch (whence) {
3172       case SEEK_CUR:
3173         newpos = afs_FileOffsets[fd] + offset;
3174         break;
3175       case SEEK_SET:
3176         newpos = offset;
3177         break;
3178       case SEEK_END:
3179         code = afs_getattr(vp, &attrs, u.u_cred);
3180         if (code != 0) {
3181             errno = code;
3182             return -1;
3183         }
3184         newpos = attrs.va_size + offset;
3185         break;
3186       default:
3187         errno = EINVAL;
3188         return -1;
3189     }
3190     if (newpos < 0) {
3191         errno = EINVAL;
3192         return -1;
3193     }
3194     afs_FileOffsets[fd] = newpos;
3195     return newpos;
3196 }
3197
3198 /*
3199  * sync a file
3200  */
3201 int uafs_fsync(
3202     int fd)
3203 {
3204     int retval;
3205     AFS_GLOCK();
3206     retval = uafs_fsync_r(fd);
3207     AFS_GUNLOCK();
3208     return retval;
3209 }
3210
3211 int uafs_fsync_r(
3212     int fd)
3213 {
3214     int code;
3215     struct usr_vnode *fileP;
3216
3217
3218     fileP = afs_FileTable[fd];
3219     if (fileP == NULL) {
3220         errno = EBADF;
3221         return -1;
3222     }
3223
3224     code = afs_fsync(fileP, u.u_cred);
3225     if (code != 0) {
3226         errno = code;
3227         return -1;
3228     }
3229
3230     return 0; 
3231 }
3232
3233 /*
3234  * Close a file
3235  */
3236 int uafs_close(
3237     int fd)
3238 {
3239     int retval;
3240     AFS_GLOCK();
3241     retval = uafs_close_r(fd);
3242     AFS_GUNLOCK();
3243     return retval;
3244 }
3245
3246 int uafs_close_r(
3247     int fd)
3248 {
3249     int code;
3250     struct usr_vnode *fileP;
3251
3252     fileP = afs_FileTable[fd];
3253     if (fileP == NULL) {
3254         errno = EBADF;
3255         return -1;
3256     }
3257     afs_FileTable[fd] = NULL;
3258
3259     code = afs_close(fileP, afs_FileFlags[fd], u.u_cred);
3260     VN_RELE(fileP);
3261     if (code != 0) {
3262         errno = code;
3263         return -1;
3264     }
3265
3266     return 0; 
3267 }
3268
3269 /*
3270  * Create a hard link from the source to the target
3271  * Note: file names may not end in a slash.
3272  */
3273 int uafs_link(
3274     char *existing,
3275     char *new)
3276 {
3277     int retval;
3278     AFS_GLOCK();
3279     retval = uafs_link_r(existing, new);
3280     AFS_GUNLOCK();
3281     return retval;
3282 }
3283
3284 int uafs_link_r(
3285     char *existing,
3286     char *new)
3287 {
3288     int code;
3289     struct usr_vnode *existP;
3290     struct usr_vnode *dirP;
3291     char *nameP;
3292
3293     if (uafs_IsRoot(new)) {
3294         return EACCES;
3295     }
3296
3297     /*
3298      * Look up the existing node.
3299      */
3300     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
3301     if (code != 0) {
3302         errno = code;
3303         return -1;
3304     }
3305
3306     /*
3307      * Look up the parent directory.
3308      */
3309     nameP = uafs_LastPath(new);
3310     if (nameP != NULL) {
3311         code = uafs_LookupParent(new, &dirP);
3312         if (code != 0) {
3313             VN_RELE(existP);
3314             errno = code;
3315             return -1;
3316         }
3317     } else {
3318         dirP = afs_CurrentDir;
3319         nameP = new;
3320         VN_HOLD(dirP);
3321     }
3322
3323     /*
3324      * Make sure the filename has at least one character
3325      */
3326     if (*nameP == '\0') {
3327         VN_RELE(existP);
3328         VN_RELE(dirP);
3329         errno = EINVAL;
3330         return -1;
3331     }
3332
3333     /*
3334      * Create the link
3335      */
3336     code = afs_link(existP, dirP, nameP, u.u_cred);
3337     VN_RELE(existP);
3338     VN_RELE(dirP);
3339     if (code != 0) {
3340         errno = code;
3341         return -1;
3342     }
3343     return 0;
3344 }
3345
3346 /*
3347  * Create a symbolic link from the source to the target
3348  * Note: file names may not end in a slash.
3349  */
3350 int uafs_symlink(
3351     char *target,
3352     char *source)
3353 {
3354     int retval;
3355     AFS_GLOCK();
3356     retval = uafs_symlink_r(target, source);
3357     AFS_GUNLOCK();
3358     return retval;
3359 }
3360
3361 int uafs_symlink_r(
3362     char *target,
3363     char *source)
3364 {
3365     int code;
3366     struct usr_vnode *dirP;
3367     struct usr_vattr attrs;
3368     char *nameP;
3369
3370     if (uafs_IsRoot(source)) {
3371         return EACCES;
3372     }
3373
3374     /*
3375      * Look up the parent directory.
3376      */
3377     nameP = uafs_LastPath(source);
3378     if (nameP != NULL) {
3379         code = uafs_LookupParent(source, &dirP);
3380         if (code != 0) {
3381             errno = code;
3382             return -1;
3383         }
3384     } else {
3385         dirP = afs_CurrentDir;
3386         nameP = source;
3387         VN_HOLD(dirP);
3388     }
3389
3390     /*
3391      * Make sure the filename has at least one character
3392      */
3393     if (*nameP == '\0') {
3394         VN_RELE(dirP);
3395         errno = EINVAL;
3396         return -1;
3397     }
3398
3399     /*
3400      * Create the link
3401      */
3402     usr_vattr_null(&attrs);
3403     attrs.va_type = VLNK;
3404     attrs.va_mode = 0777;
3405     attrs.va_uid = u.u_cred->cr_uid;
3406     attrs.va_gid = u.u_cred->cr_gid;
3407     code = afs_symlink(dirP, nameP, &attrs, target, u.u_cred);
3408     VN_RELE(dirP);
3409     if (code != 0) {
3410         errno = code;
3411         return -1;
3412     }
3413     return 0;
3414 }
3415
3416 /*
3417  * Read a symbolic link into the buffer
3418  */
3419 int uafs_readlink(
3420     char *path,
3421     char *buf,
3422     int len)
3423 {
3424     int retval;
3425     AFS_GLOCK();
3426     retval = uafs_readlink_r(path, buf, len);
3427     AFS_GUNLOCK();
3428     return retval;
3429 }
3430
3431 int uafs_readlink_r(
3432     char *path,
3433     char *buf,
3434     int len)
3435 {
3436     int code;
3437     struct usr_vnode *vp;
3438     struct usr_uio uio;
3439     struct iovec iov[1];
3440
3441     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3442     if (code != 0) {
3443         errno = code;
3444         return -1;
3445     }
3446
3447     if (vp->v_type != VLNK) {
3448         VN_RELE(vp);
3449         errno = EINVAL;
3450         return -1;
3451     }
3452
3453     /*
3454      * set up the uio buffer
3455      */
3456     iov[0].iov_base = buf;
3457     iov[0].iov_len = len;
3458     uio.uio_iov = &iov[0];
3459     uio.uio_iovcnt = 1;
3460     uio.uio_offset = 0;
3461     uio.uio_segflg = 0;
3462     uio.uio_fmode = FREAD;
3463     uio.uio_resid = len;
3464
3465     /*
3466      * Read the the link
3467      */
3468     code = afs_readlink(vp, &uio, u.u_cred);
3469     VN_RELE(vp);
3470     if (code) {
3471         errno = code;
3472         return -1;
3473     }
3474
3475     /*
3476      * return the number of bytes read
3477      */
3478     return (len - uio.uio_resid);
3479 }
3480
3481 /*
3482  * Remove a file (or directory)
3483  * Note: file name may not end in a slash.
3484  */
3485 int uafs_unlink(
3486     char *path)
3487 {
3488     int retval;
3489     AFS_GLOCK();
3490     retval = uafs_unlink_r(path);
3491     AFS_GUNLOCK();
3492     return retval;
3493 }
3494
3495 int uafs_unlink_r(
3496     char *path)
3497 {
3498     int code;
3499     int openFlags;
3500     struct usr_vnode *fileP;
3501     struct usr_vnode *dirP;
3502     char *nameP;
3503
3504     if (uafs_IsRoot(path)) {
3505         return EACCES;
3506     }
3507
3508     /*
3509      * Look up the parent directory.
3510      */
3511     nameP = uafs_LastPath(path);
3512     if (nameP != NULL) {
3513         code = uafs_LookupParent(path, &dirP);
3514         if (code != 0) {
3515             errno = code;
3516             return -1;
3517         }
3518     } else {
3519         dirP = afs_CurrentDir;
3520         nameP = path;
3521         VN_HOLD(dirP);
3522     }
3523
3524     /*
3525      * Make sure the filename has at least one character
3526      */
3527     if (*nameP == '\0') {
3528         VN_RELE(dirP);
3529         errno = EINVAL;
3530         return -1;
3531     }
3532
3533     /*
3534      * Remove the file
3535      */
3536     code = afs_remove(dirP, nameP, u.u_cred);
3537     VN_RELE(dirP);
3538     if (code != 0) {
3539         errno = code;
3540         return -1;
3541     }
3542
3543     return 0;
3544 }
3545
3546 /*
3547  * Rename a file (or directory)
3548  */
3549 int uafs_rename(
3550     char *old,
3551     char *new)
3552 {
3553     int retval;
3554     AFS_GLOCK();
3555     retval = uafs_rename_r(old, new);
3556     AFS_GUNLOCK();
3557     return retval;
3558 }
3559
3560 int uafs_rename_r(
3561     char *old,
3562     char *new)
3563 {
3564     int code;
3565     char *onameP;
3566     char *nnameP;
3567     struct usr_vnode *odirP;
3568     struct usr_vnode *ndirP;
3569
3570     if (uafs_IsRoot(new)) {
3571         return EACCES;
3572     }
3573
3574     /*
3575      * Look up the parent directories.
3576      */
3577     onameP = uafs_LastPath(old);
3578     if (onameP != NULL) {
3579         code = uafs_LookupParent(old, &odirP);
3580         if (code != 0) {
3581             errno = code;
3582             return -1;
3583         }
3584     } else {
3585         odirP = afs_CurrentDir;
3586         onameP = old;
3587         VN_HOLD(odirP);
3588     }
3589     nnameP = uafs_LastPath(new);
3590     if (nnameP != NULL) {
3591         code = uafs_LookupParent(new, &ndirP);
3592         if (code != 0) {
3593             errno = code;
3594             return -1;
3595         }
3596     } else {
3597         ndirP = afs_CurrentDir;
3598         nnameP = new;
3599         VN_HOLD(ndirP);
3600     }
3601
3602     /*
3603      * Make sure the filename has at least one character
3604      */
3605     if (*onameP == '\0' || *nnameP == '\0') {
3606         VN_RELE(odirP);
3607         VN_RELE(ndirP);
3608         errno = EINVAL;
3609         return -1;
3610     }
3611
3612     /*
3613      * Rename the file
3614      */
3615     code = afs_rename(odirP, onameP, ndirP, nnameP, u.u_cred);
3616     VN_RELE(odirP);
3617     VN_RELE(ndirP);
3618     if (code != 0) {
3619         errno = code;
3620         return -1;
3621     }
3622
3623     return 0;
3624 }
3625
3626 /*
3627  * Remove a or directory
3628  * Note: file name may not end in a slash.
3629  */
3630 int uafs_rmdir(
3631     char *path)
3632 {
3633     int retval;
3634     AFS_GLOCK();
3635     retval = uafs_rmdir_r(path);
3636     AFS_GUNLOCK();
3637     return retval;
3638 }
3639
3640 int uafs_rmdir_r(
3641     char *path)
3642 {
3643     int code;
3644     int openFlags;
3645     struct usr_vnode *fileP;
3646     struct usr_vnode *dirP;
3647     char *nameP;
3648
3649     if (uafs_IsRoot(path)) {
3650         return EACCES;
3651     }
3652
3653     /*
3654      * Look up the parent directory.
3655      */
3656     nameP = uafs_LastPath(path);
3657     if (nameP != NULL) {
3658         code = uafs_LookupParent(path, &dirP);
3659         if (code != 0) {
3660             errno = code;
3661             return -1;
3662         }
3663     } else {
3664         dirP = afs_CurrentDir;
3665         nameP = path;
3666         VN_HOLD(dirP);
3667     }
3668
3669     /*
3670      * Make sure the directory name has at least one character
3671      */
3672     if (*nameP == '\0') {
3673         VN_RELE(dirP);
3674         errno = EINVAL;
3675         return -1;
3676     }
3677
3678     /*
3679      * Remove the directory
3680      */
3681     code = afs_rmdir(dirP, nameP, u.u_cred);
3682     VN_RELE(dirP);
3683     if (code != 0) {
3684         errno = code;
3685         return -1;
3686     }
3687
3688     return 0;
3689 }
3690
3691 /*
3692  * Flush a file from the AFS cache
3693  */
3694 int uafs_FlushFile(
3695      char *path)
3696 {
3697     int code;
3698     struct afs_ioctl iob;
3699
3700     iob.in = NULL;
3701     iob.in_size = 0;
3702     iob.out = NULL;
3703     iob.out_size = 0;
3704
3705     code = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6),
3706                         (long)&iob, 0, 0);
3707     if (code != 0) {
3708         errno = code;
3709         return -1;
3710     }
3711
3712     return 0;
3713 }
3714 int uafs_FlushFile_r(
3715      char *path)
3716 {
3717     int retval;
3718     AFS_GUNLOCK();
3719     retval = uafs_FlushFile(path);
3720     AFS_GLOCK();
3721     return retval;
3722 }
3723
3724 /*
3725  * open a directory
3726  */
3727 usr_DIR *uafs_opendir(
3728     char *path)
3729 {
3730     usr_DIR *retval;
3731     AFS_GLOCK();
3732     retval = uafs_opendir_r(path);
3733     AFS_GUNLOCK();
3734     return retval;
3735 }
3736
3737 usr_DIR *uafs_opendir_r(
3738     char *path)
3739 {
3740     usr_DIR *dirp;
3741     struct usr_vnode *fileP;
3742     int fd;
3743
3744     /*
3745      * Open the directory for reading
3746      */
3747     fd = uafs_open_r(path, O_RDONLY, 0);
3748     if (fd < 0) {
3749         return NULL;
3750     }
3751
3752     fileP = afs_FileTable[fd];
3753     if (fileP == NULL) {
3754      return NULL;
3755     }
3756
3757     if (fileP->v_type != VDIR) {
3758       uafs_close_r(fd);
3759       errno = ENOTDIR;
3760       return NULL;
3761     }
3762
3763     /*
3764      * Set up the directory structures
3765      */
3766     dirp = (usr_DIR *)afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3767                                     sizeof(struct usr_dirent));
3768     usr_assert(dirp != NULL);
3769     dirp->dd_buf = (char *)(dirp+1);
3770     dirp->dd_fd = fd;
3771     dirp->dd_loc = 0;
3772     dirp->dd_size = 0;
3773
3774     errno = 0;
3775     return dirp;
3776 }
3777
3778 /*
3779  * Read directory entries into a file system independent format.
3780  * This routine was developed to support AFS cache consistency testing.
3781  * You should use uafs_readdir instead.
3782  */
3783 int uafs_getdents(
3784     int fd,
3785     struct min_direct *buf,
3786     int len)
3787 {
3788     int retval;
3789     AFS_GLOCK();
3790     retval = uafs_getdents_r(fd, buf, len);
3791     AFS_GUNLOCK();
3792     return retval;
3793 }
3794
3795 int uafs_getdents_r(
3796     int fd,
3797     struct min_direct *buf,
3798     int len)
3799 {
3800     int code;
3801     struct usr_uio uio;
3802     struct usr_vnode *vp;
3803     struct iovec iov[1];
3804
3805     /*
3806      * Make sure this is an open file
3807      */
3808     vp = afs_FileTable[fd];
3809     if (vp == NULL) {
3810         AFS_GUNLOCK();
3811         errno = EBADF;
3812         return -1;
3813     }
3814
3815     /*
3816      * set up the uio buffer
3817      */
3818     iov[0].iov_base = (char *)buf;
3819     iov[0].iov_len = len;
3820     uio.uio_iov = &iov[0];
3821     uio.uio_iovcnt = 1;
3822     uio.uio_offset = afs_FileOffsets[fd];
3823     uio.uio_segflg = 0;
3824     uio.uio_fmode = FREAD;
3825     uio.uio_resid = len;
3826
3827     /*
3828      * read the next chunk from the directory
3829      */
3830     code = afs_readdir(vp, &uio, u.u_cred);
3831     if (code != 0) {
3832         errno = code;
3833         return -1;
3834     }
3835
3836     afs_FileOffsets[fd] = uio.uio_offset;
3837     return(len - uio.uio_resid);
3838 }
3839
3840 /*
3841  * read from a directory (names only)
3842  */
3843 struct usr_dirent *uafs_readdir(
3844     usr_DIR *dirp)
3845 {
3846     struct usr_dirent *retval;
3847     AFS_GLOCK();
3848     retval = uafs_readdir_r(dirp);
3849     AFS_GUNLOCK();
3850     return retval;
3851 }
3852
3853 struct usr_dirent *uafs_readdir_r(
3854     usr_DIR *dirp)
3855 {
3856     int rc;
3857     int code;
3858     int len;
3859     struct usr_uio uio;
3860     struct usr_vnode *vp;
3861     struct iovec iov[1];
3862     struct usr_dirent *direntP;
3863     struct min_direct *directP;
3864
3865     /*
3866      * Make sure this is an open file
3867      */
3868     vp = afs_FileTable[dirp->dd_fd];
3869     if (vp == NULL) {
3870         errno = EBADF;
3871         return NULL;
3872     }
3873
3874     /*
3875      * If there are no entries in the stream buffer
3876      * then read another chunk
3877      */
3878     directP = (struct min_direct *)(dirp->dd_buf+dirp->dd_loc);
3879     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3880         /*
3881          * set up the uio buffer
3882          */
3883         iov[0].iov_base = dirp->dd_buf;
3884         iov[0].iov_len = USR_DIRSIZE;
3885         uio.uio_iov = &iov[0];
3886         uio.uio_iovcnt = 1;
3887         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3888         uio.uio_segflg = 0;
3889         uio.uio_fmode = FREAD;
3890         uio.uio_resid = USR_DIRSIZE;
3891
3892         /*
3893          * read the next chunk from the directory
3894          */
3895         code = afs_readdir(vp, &uio, u.u_cred);
3896         if (code != 0) {
3897             errno = code;
3898             return NULL;
3899         }
3900         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3901
3902         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3903         dirp->dd_loc = 0;
3904         directP = (struct min_direct *)(dirp->dd_buf+dirp->dd_loc);
3905     }
3906
3907     /*
3908      * Check for end of file
3909      */
3910     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3911         errno = 0;
3912         return NULL;
3913     }
3914     len = ((sizeof(struct min_direct)+directP->d_namlen+4) & (~3));
3915     usr_assert(len <= dirp->dd_size);
3916
3917     /*
3918      * Copy the next entry into the usr_dirent structure and advance
3919      */
3920     direntP = (struct usr_dirent *)(dirp->dd_buf+USR_DIRSIZE);
3921     direntP->d_ino = directP->d_fileno;
3922     direntP->d_off = direntP->d_reclen;
3923     direntP->d_reclen = sizeof(struct usr_dirent) - MAXNAMLEN +
3924                                directP->d_namlen + 1;
3925     memcpy(&direntP->d_name[0], (void *)(directP+1), directP->d_namlen);
3926     direntP->d_name[directP->d_namlen] = '\0';
3927     dirp->dd_loc += len;
3928     dirp->dd_size -= len;
3929
3930     return direntP;
3931 }
3932
3933 /*
3934  * Close a directory
3935  */
3936 int uafs_closedir(
3937     usr_DIR *dirp)
3938 {
3939     int retval;
3940     AFS_GLOCK();
3941     retval = uafs_closedir_r(dirp);
3942     AFS_GUNLOCK();
3943     return retval;
3944 }
3945
3946 int uafs_closedir_r(
3947     usr_DIR *dirp)
3948 {
3949     int fd;
3950     int rc;
3951
3952     fd = dirp->dd_fd;
3953     afs_osi_Free((char *)dirp,
3954                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3955     rc = uafs_close_r(fd);
3956     return rc;
3957 }
3958
3959 /*
3960  * Do AFS authentication
3961  */
3962 int uafs_klog(
3963     char *user,
3964     char *cell,
3965     char *passwd,
3966     char **reason)
3967 {
3968     int code;
3969     afs_int32 password_expires = -1;
3970
3971     usr_mutex_lock(&osi_authenticate_lock);
3972     code = ka_UserAuthenticateGeneral(
3973                 KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG2, user,
3974                 NULL, cell, passwd, 0, &password_expires,
3975                 0, reason);
3976     usr_mutex_unlock(&osi_authenticate_lock);
3977     return code;
3978 }
3979
3980 int uafs_klog_r(
3981     char *user,
3982     char *cell,
3983     char *passwd,
3984     char **reason)
3985 {
3986     int retval;
3987     AFS_GUNLOCK();
3988     retval = uafs_klog(user, cell, passwd, reason);
3989     AFS_GLOCK();
3990     return retval;
3991 }
3992
3993 /*
3994  * Destroy AFS credentials from the kernel cache
3995  */
3996 int uafs_unlog(void)
3997 {
3998     int code;
3999
4000     usr_mutex_lock(&osi_authenticate_lock);
4001     code = ktc_ForgetAllTokens();
4002     usr_mutex_unlock(&osi_authenticate_lock);
4003     return code;
4004 }
4005
4006 int uafs_unlog_r(void)
4007 {
4008     int retval;
4009     AFS_GUNLOCK();
4010     retval = uafs_unlog();
4011     AFS_GLOCK();
4012     return retval;
4013 }
4014
4015 /*
4016  * Strip the AFS mount point from a pathname string. Return
4017  * NULL if the path is a relative pathname or if the path
4018  * doesn't start with the AFS mount point string.
4019  */
4020 char *uafs_afsPathName(char *path)
4021 {
4022     char *p;
4023     char lastchar;
4024     int i;
4025
4026     if (path[0] != '/')
4027         return NULL;
4028     lastchar = '/';
4029     for (i = 1, p = path+1; *p != '\0' ; p++) {
4030         /* Ignore duplicate slashes */
4031         if (*p == '/' && lastchar == '/')
4032             continue;
4033         /* Is this a subdirectory of the AFS mount point? */
4034         if (afs_mountDir[i] == '\0' && *p == '/') {
4035             /* strip leading slashes */
4036             while (*(++p) == '/');
4037             return p;
4038         }
4039         /* Reject paths that are not within AFS */
4040         if (*p != afs_mountDir[i])
4041             return NULL;
4042         lastchar = *p;
4043         i++;
4044     }
4045     /* Is this the AFS mount point? */
4046     if (afs_mountDir[i] == '\0') {
4047         usr_assert(*p == '\0');
4048         return p;
4049     }
4050     return NULL;
4051 }
4052
4053 #ifdef AFS_WEB_ENHANCEMENTS
4054 /*
4055  * uafs_klog_nopag
4056  * klog but don't allocate a new pag
4057  */
4058 int uafs_klog_nopag(
4059     char *user,
4060     char *cell,
4061     char *passwd,
4062     char **reason)
4063 {
4064     int code;
4065     afs_int32 password_expires = -1;
4066
4067     usr_mutex_lock(&osi_authenticate_lock);
4068     code = ka_UserAuthenticateGeneral(
4069       KA_USERAUTH_VERSION  /*+KA_USERAUTH_DOSETPAG2*/, user,
4070           NULL, cell, passwd, 0, &password_expires,
4071           0, reason);
4072     usr_mutex_unlock(&osi_authenticate_lock);
4073     return code;
4074 }
4075
4076 /*
4077  * uafs_getcellstatus
4078  * get the cell status
4079  */
4080 int uafs_getcellstatus(char *cell, afs_int32 *status)
4081 {
4082   int rc;
4083   struct afs_ioctl iob;
4084
4085   iob.in = cell;
4086   iob.in_size = strlen(cell)+1;
4087   iob.out = 0;
4088   iob.out_size = 0;
4089
4090   rc = call_syscall(AFSCALL_PIOCTL, /*path*/0, _VICEIOCTL(35),
4091                       (long)&iob, 0, 0);
4092
4093   if (rc < 0) {
4094     errno = rc;
4095     return -1;
4096   }
4097
4098   *status = (afs_int32) iob.out;
4099   return 0;
4100 }
4101
4102 /*
4103  * uafs_getvolquota
4104  * Get quota of volume associated with path
4105  */
4106 int uafs_getvolquota(char *path, afs_int32 *BlocksInUse, afs_int32 *MaxQuota)
4107 {
4108   int rc;
4109   struct afs_ioctl iob;
4110   VolumeStatus *status;
4111   char buf[1024];
4112
4113   iob.in = 0;
4114   iob.in_size = 0;
4115   iob.out = buf;
4116   iob.out_size = 1024;
4117
4118   rc = call_syscall(AFSCALL_PIOCTL, (long) path, _VICEIOCTL(4),
4119                       (long)&iob, 0, 0);
4120
4121   if (rc != 0) {
4122     errno = rc;
4123     return -1;
4124   }
4125
4126   status = (VolumeStatus *) buf;
4127   *BlocksInUse = status->BlocksInUse;
4128   *MaxQuota = status->MaxQuota;
4129   return 0;
4130 }
4131
4132 /*
4133  * uafs_setvolquota
4134  * Set quota of volume associated with path
4135  */
4136 int uafs_setvolquota(char *path, afs_int32 MaxQuota)
4137 {
4138   int rc;
4139   struct afs_ioctl iob;
4140   VolumeStatus *status;
4141   char buf[1024];
4142
4143   iob.in = buf;
4144   iob.in_size = 1024;
4145   iob.out = 0;
4146   iob.out_size = 0;
4147
4148   memset(buf, 0, sizeof(VolumeStatus));
4149   status = (VolumeStatus *) buf;
4150   status->MaxQuota = MaxQuota;
4151   status->MinQuota = -1;
4152
4153   rc = call_syscall(AFSCALL_PIOCTL, (long) path, _VICEIOCTL(5),
4154                       (long)&iob, 0, 0);
4155
4156   if (rc != 0) {
4157     errno = rc;
4158     return -1;
4159   }
4160
4161   return 0;
4162 }
4163
4164 /*
4165  * uafs_statmountpoint
4166  * Determine whether a dir. is a mount point or not
4167  * return 1 if mount point, 0 if not
4168  */
4169 int uafs_statmountpoint(char *path)
4170 {
4171     int retval;
4172     int code;
4173     char buf[256];
4174
4175     AFS_GLOCK();
4176     retval = uafs_statmountpoint_r(path);
4177     AFS_GUNLOCK();
4178     return retval;
4179 }
4180
4181 int uafs_statmountpoint_r(char *path)
4182 {
4183     int code;
4184     struct vnode *vp;
4185     struct vcache *avc;
4186     struct vrequest treq;
4187     int r;
4188
4189     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
4190     if (code != 0) {
4191      errno = code;
4192      return -1;
4193     }
4194
4195     avc = VTOAFS(vp);
4196
4197     r = avc->mvstat;
4198     VN_RELE(vp);
4199     return r;
4200 }
4201
4202 /*
4203  * uafs_getRights
4204  * Get a list of rights for the current user on path.
4205  */
4206 int uafs_getRights(char *path)
4207 {
4208     int code, rc;
4209     struct vnode *vp;
4210     int afs_rights;
4211
4212     AFS_GLOCK();
4213     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
4214     if (code != 0) {
4215      errno = code;
4216      AFS_GUNLOCK();
4217      return -1;
4218     }
4219
4220     afs_rights = PRSFS_READ |
4221       PRSFS_WRITE |
4222       PRSFS_INSERT |
4223       PRSFS_LOOKUP |
4224       PRSFS_DELETE |
4225       PRSFS_LOCK |
4226       PRSFS_ADMINISTER;
4227
4228     afs_rights = afs_getRights (vp, afs_rights, u.u_cred);
4229
4230     AFS_GUNLOCK();
4231     return afs_rights;
4232 }
4233 #endif /* AFS_WEB_ENHANCEMENTS */
4234
4235 #endif /* UKERNEL */