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