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