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