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