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