snowleopard 64 bit warning death
[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, 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_SGI62_ENV) || defined(AFS_USR_DARWIN100_ENV)
1305             printf("\tinode=%" AFS_INT64_FMT ", reclen=%d, name='%s'\n",
1306                    currp->d_ino, currp->d_reclen, currp->d_name);
1307 #elif defined(AFS_USR_DFBSD_ENV)
1308             printf("\tinode=%d, name='%s'\n", currp->d_ino,
1309                    currp->d_name);
1310 #else
1311             printf("\tinode=%d, reclen=%d, name='%s'\n", currp->d_ino,
1312                    currp->d_reclen, currp->d_name);
1313 #endif
1314         }
1315
1316         /*
1317          * Guess current entry is for a data cache file.
1318          */
1319         vFileNum = GetVFileNumber(currp->d_name);
1320         if (vFileNum >= 0) {
1321             /*
1322              * Found a valid data cache filename.  Remember this file's name
1323              * and bump the number of files found.
1324              */
1325             pathname_for_V[vFileNum] =
1326                 afs_osi_Alloc(strlen(currp->d_name) + strlen(cacheBaseDir) +
1327                               2);
1328             usr_assert(pathname_for_V[vFileNum] != NULL);
1329             sprintf(pathname_for_V[vFileNum], "%s/%s", cacheBaseDir,
1330                     currp->d_name);
1331             (*vFilesFound)++;
1332         } else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
1333             /*
1334              * Found the file holding the dcache entries.
1335              */
1336             missing_DCacheFile = 0;
1337         } else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
1338             /*
1339              * Found the file holding the volume info.
1340              */
1341             missing_VolInfoFile = 0;
1342         } else if (strcmp(currp->d_name, CELLINFOFILE) == 0) {
1343             missing_CellInfoFile = 0;
1344         } else if ((strcmp(currp->d_name, ".") == 0)
1345                    || (strcmp(currp->d_name, "..") == 0)
1346                    || (strcmp(currp->d_name, "lost+found") == 0)) {
1347             /*
1348              * Don't do anything - this file is legit, and is to be left alone.
1349              */
1350         } else {
1351             /*
1352              * This file doesn't belong in the cache.  Nuke it.
1353              */
1354             sprintf(fileToDelete, "%s", currp->d_name);
1355             if (afsd_verbose)
1356                 printf("%s: Deleting '%s'\n", rn, fullpn_FileToDelete);
1357             if (unlink(fullpn_FileToDelete)) {
1358                 printf("%s: Can't unlink '%s', errno is %d\n", rn,
1359                        fullpn_FileToDelete, errno);
1360             }
1361         }
1362     }
1363
1364     /*
1365      * Create all the cache files that are missing.
1366      */
1367     if (missing_DCacheFile) {
1368         if (afsd_verbose)
1369             printf("%s: Creating '%s'\n", rn, fullpn_DCacheFile);
1370         if (CreateCacheFile(fullpn_DCacheFile))
1371             printf("%s: Can't create '%s'\n", rn, fullpn_DCacheFile);
1372     }
1373     if (missing_VolInfoFile) {
1374         if (afsd_verbose)
1375             printf("%s: Creating '%s'\n", rn, fullpn_VolInfoFile);
1376         if (CreateCacheFile(fullpn_VolInfoFile))
1377             printf("%s: Can't create '%s'\n", rn, fullpn_VolInfoFile);
1378     }
1379     if (missing_CellInfoFile) {
1380         if (afsd_verbose)
1381             printf("%s: Creating '%s'\n", rn, fullpn_CellInfoFile);
1382         if (CreateCacheFile(fullpn_CellInfoFile))
1383             printf("%s: Can't create '%s'\n", rn, fullpn_CellInfoFile);
1384     }
1385
1386     if (*vFilesFound < cacheFiles) {
1387         /*
1388          * We came up short on the number of data cache files found.  Scan through the inode
1389          * list and create all missing files.
1390          */
1391         for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
1392             if (pathname_for_V[vFileNum] == (AFSD_INO_T) 0) {
1393                 sprintf(vFileNumber, "%d", vFileNum);
1394                 if (afsd_verbose)
1395                     printf("%s: Creating '%s'\n", rn, fullpn_VFile);
1396                 if (CreateCacheFile(fullpn_VFile))
1397                     printf("%s: Can't create '%s'\n", rn, fullpn_VFile);
1398             }
1399     }
1400
1401     /*
1402      * Close the directory, return success.
1403      */
1404     if (afsd_debug)
1405         printf("%s: Closing cache directory.\n", rn);
1406     closedir(cdirp);
1407     return (0);
1408 }
1409
1410 static int
1411 ConfigCell(register struct afsconf_cell *aci, void *arock,
1412            struct afsconf_dir *adir)
1413 {
1414     register int isHomeCell;
1415     register int i;
1416     afs_int32 cellFlags = 0;
1417     afs_int32 hosts[MAXHOSTSPERCELL];
1418
1419     /* figure out if this is the home cell */
1420     isHomeCell = (strcmp(aci->name, afs_LclCellName) == 0);
1421     if (!isHomeCell)
1422         cellFlags = 2;          /* not home, suid is forbidden */
1423
1424     /* build address list */
1425     for (i = 0; i < MAXHOSTSPERCELL; i++)
1426         memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
1427
1428     if (aci->linkedCell)
1429         cellFlags |= 4;         /* Flag that linkedCell arg exists,
1430                                  * for upwards compatibility */
1431
1432     /* configure one cell */
1433     call_syscall(AFSCALL_CALL, AFSOP_ADDCELL2, (long)hosts,     /* server addresses */
1434                  (long)aci->name,       /* cell name */
1435                  (long)cellFlags,       /* is this the home cell? */
1436                  (long)aci->linkedCell);        /* Linked cell, if any */
1437     return 0;
1438 }
1439
1440 static int
1441 ConfigCellAlias(struct afsconf_cellalias *aca, void *arock, struct afsconf_dir *adir)
1442 {
1443         call_syscall(AFSOP_ADDCELLALIAS, (long)aca->aliasName, 
1444                      (long)aca->realName, 0, 0, 0);
1445         return 0;
1446 }
1447
1448 /*
1449  * Set the UDP port number RX uses for UDP datagrams
1450  */
1451 void
1452 uafs_SetRxPort(int port)
1453 {
1454     usr_assert(usr_rx_port == 0);
1455     usr_rx_port = port;
1456 }
1457
1458
1459 /*
1460  * Initialize the user space client.
1461  */
1462 void
1463 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
1464           char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
1465           int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
1466           int chunkSizeParam, int closeSynchParam, int debugParam,
1467           int nDaemonsParam, int cacheFlagsParam, char *logFile)
1468 {
1469     int st;
1470     int i;
1471     int rc;
1472     int currVFile;              /* Current AFS cache file number */
1473     int lookupResult;           /* Result of GetLocalCellName() */
1474     int cacheIteration;         /* cache verification loop counter */
1475     int vFilesFound;            /* Num data cache files found in sweep */
1476     FILE *logfd;
1477     char tbuffer[1024];
1478     char *p;
1479     char lastchar;
1480     afs_int32 buffer[MAXIPADDRS];
1481     afs_int32 maskbuffer[MAXIPADDRS];
1482     afs_int32 mtubuffer[MAXIPADDRS];
1483
1484     /*
1485      * Use the thread specific data to implement the user structure
1486      */
1487     usr_keycreate(&afs_global_u_key, free);
1488
1489     /*
1490      * Initialize the global ucred structure
1491      */
1492     afs_global_ucredp = (struct usr_ucred *)
1493         afs_osi_Alloc(sizeof(struct usr_ucred));
1494     usr_assert(afs_global_ucredp != NULL);
1495     afs_global_ucredp->cr_ref = 1;
1496     afs_global_ucredp->cr_uid = geteuid();
1497     afs_global_ucredp->cr_gid = getegid();
1498     afs_global_ucredp->cr_ruid = getuid();
1499     afs_global_ucredp->cr_rgid = getgid();
1500     afs_global_ucredp->cr_suid = afs_global_ucredp->cr_ruid;
1501     afs_global_ucredp->cr_sgid = afs_global_ucredp->cr_rgid;
1502     st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1503     usr_assert(st >= 0);
1504     afs_global_ucredp->cr_ngroups = (unsigned long)st;
1505     for (i = st; i < NGROUPS; i++) {
1506         afs_global_ucredp->cr_groups[i] = NOGROUP;
1507     }
1508
1509     /*
1510      * Initialize the global process structure
1511      */
1512     afs_global_procp = (struct usr_proc *)
1513         afs_osi_Alloc(sizeof(struct usr_proc));
1514     usr_assert(afs_global_procp != NULL);
1515     afs_global_procp->p_pid = osi_getpid();
1516     afs_global_procp->p_ppid = (pid_t) 1;
1517     afs_global_procp->p_ucred = afs_global_ucredp;
1518
1519     /*
1520      * Initialize the AFS mount point, default is '/afs'.
1521      * Strip duplicate/trailing slashes from mount point string.
1522      * afs_mountDirLen is set to strlen(afs_mountDir).
1523      */
1524     if (mountDirParam) {
1525         sprintf(tbuffer, "%s", mountDirParam);
1526     } else {
1527         sprintf(tbuffer, "afs");
1528     }
1529     afs_mountDir[0] = '/';
1530     afs_mountDirLen = 1;
1531     for (lastchar = '/', p = &tbuffer[0]; *p != '\0'; p++) {
1532         if (lastchar != '/' || *p != '/') {
1533             afs_mountDir[afs_mountDirLen++] = lastchar = *p;
1534         }
1535     }
1536     if (lastchar == '/' && afs_mountDirLen > 1)
1537         afs_mountDirLen--;
1538     afs_mountDir[afs_mountDirLen] = '\0';
1539     usr_assert(afs_mountDirLen > 1);
1540
1541     /*
1542      * Initialize cache parameters using the input arguments
1543      */
1544
1545     cacheBlocks = cacheBlocksParam;
1546     if (cacheFilesParam != 0) {
1547         cacheFiles = cacheFilesParam;
1548     } else {
1549         cacheFiles = cacheBlocks / 10;
1550     }
1551     if (cacheStatEntriesParam != 0) {
1552         cacheStatEntries = cacheStatEntriesParam;
1553     }
1554     strcpy(cacheBaseDir, cacheBaseDirParam);
1555     if (nDaemonsParam != 0) {
1556         nDaemons = nDaemonsParam;
1557     } else {
1558         nDaemons = 3;
1559     }
1560     afsd_verbose = debugParam;
1561     afsd_debug = debugParam;
1562     chunkSize = chunkSizeParam;
1563     if (dCacheSizeParam != 0) {
1564         dCacheSize = dCacheSizeParam;
1565     } else {
1566         dCacheSize = cacheFiles / 2;
1567     }
1568     if (vCacheSizeParam != 0) {
1569         vCacheSize = vCacheSizeParam;
1570     }
1571     strcpy(confDir, confDirParam);
1572     afsd_CloseSynch = closeSynchParam;
1573     if (cacheFlagsParam >= 0) {
1574         cacheFlags = cacheFlagsParam;
1575     }
1576     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1577         cacheFiles = dCacheSize;
1578     }
1579
1580     sprintf(fullpn_CacheInfo, "%s/%s", confDir, CACHEINFOFILE);
1581     if (logFile == NULL) {
1582         sprintf(fullpn_AFSLogFile, "%s/%s", confDir, AFSLOGFILE);
1583     } else {
1584         strcpy(fullpn_AFSLogFile, logFile);
1585     }
1586
1587     printf("\n%s: Initializing user space AFS client\n\n", rn);
1588     printf("    mountDir:           %s\n", afs_mountDir);
1589     printf("    confDir:            %s\n", confDir);
1590     printf("    cacheBaseDir:       %s\n", cacheBaseDir);
1591     printf("    cacheBlocks:        %d\n", cacheBlocks);
1592     printf("    cacheFiles:         %d\n", cacheFiles);
1593     printf("    cacheStatEntries:   %d\n", cacheStatEntries);
1594     printf("    dCacheSize:         %d\n", dCacheSize);
1595     printf("    vCacheSize:         %d\n", vCacheSize);
1596     printf("    chunkSize:          %d\n", chunkSize);
1597     printf("    afsd_CloseSynch:    %d\n", afsd_CloseSynch);
1598     printf("    afsd_debug/verbose: %d/%d\n", afsd_debug, afsd_verbose);
1599     printf("    nDaemons:           %d\n", nDaemons);
1600     printf("    cacheFlags:         %d\n", cacheFlags);
1601     printf("    logFile:            %s\n", fullpn_AFSLogFile);
1602     printf("\n");
1603     fflush(stdout);
1604
1605     /*
1606      * Initialize the AFS client
1607      */
1608     osi_Init();
1609
1610     /*
1611      * Pull out all the configuration info for the workstation's AFS cache and
1612      * the cellular community we're willing to let our users see.
1613      */
1614     afs_cdir = afsconf_Open(confDir);
1615     if (!afs_cdir) {
1616         printf("afsd: some file missing or bad in %s\n", confDir);
1617         exit(1);
1618     }
1619
1620     lookupResult =
1621         afsconf_GetLocalCell(afs_cdir, afs_LclCellName,
1622                              sizeof(afs_LclCellName));
1623     if (lookupResult) {
1624         printf("%s: Can't get my home cell name!  [Error is %d]\n", rn,
1625                lookupResult);
1626     } else {
1627         if (afsd_verbose)
1628             printf("%s: My home cell is '%s'\n", rn, afs_LclCellName);
1629     }
1630
1631     if ((logfd = fopen(fullpn_AFSLogFile, "r+")) == 0) {
1632         if (afsd_verbose)
1633             printf("%s: Creating '%s'\n", rn, fullpn_AFSLogFile);
1634         if (CreateCacheFile(fullpn_AFSLogFile)) {
1635             printf
1636                 ("%s: Can't create '%s' (You may want to use the -logfile option)\n",
1637                  rn, fullpn_AFSLogFile);
1638             exit(1);
1639         }
1640     } else
1641         fclose(logfd);
1642
1643     /*
1644      * Create and zero the pathname table for the desired cache files.
1645      */
1646     pathname_for_V = (char **)afs_osi_Alloc(cacheFiles * sizeof(char *));
1647     if (pathname_for_V == NULL) {
1648         printf("%s: malloc() failed for cache file table with %d entries.\n",
1649                rn, cacheFiles);
1650         exit(1);
1651     }
1652     memset(pathname_for_V, 0, (cacheFiles * sizeof(char *)));
1653     if (afsd_debug)
1654         printf("%s: %d pathname_for_V entries at %" AFS_PTR_FMT
1655                ", %lud bytes\n", rn, cacheFiles, pathname_for_V,
1656                afs_printable_uint32_lu(cacheFiles * sizeof(AFSD_INO_T)));
1657
1658     /*
1659      * Set up all the pathnames we'll need for later.
1660      */
1661     sprintf(fullpn_DCacheFile, "%s/%s", cacheBaseDir, DCACHEFILE);
1662     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
1663     sprintf(fullpn_CellInfoFile, "%s/%s", cacheBaseDir, CELLINFOFILE);
1664     sprintf(fullpn_VFile, "%s/V", cacheBaseDir);
1665     vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
1666
1667     /* initialize AFS callback interface */
1668     {
1669         /* parse multihomed address files */
1670         char reason[1024];
1671         st = parseNetFiles((afs_uint32*)buffer,(afs_uint32*) maskbuffer, (afs_uint32*)mtubuffer, MAXIPADDRS, reason,
1672                            AFSDIR_CLIENT_NETINFO_FILEPATH,
1673                            AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
1674         if (st > 0)
1675             call_syscall(AFSCALL_CALL, AFSOP_ADVISEADDR, st,
1676                          (long)(&buffer[0]), (long)(&maskbuffer[0]),
1677                          (long)(&mtubuffer[0]));
1678         else {
1679             printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
1680                    reason);
1681             exit(1);
1682         }
1683     }
1684
1685     /*
1686      * Start the RX listener.
1687      */
1688     if (afsd_debug)
1689         printf("%s: Calling AFSOP_RXLISTENER_DAEMON\n", rn);
1690     fork_syscall(AFSCALL_CALL, AFSOP_RXLISTENER_DAEMON, FALSE, FALSE, FALSE, 0);
1691
1692     if (afsd_verbose)
1693         printf("%s: Forking rx callback listener.\n", rn);
1694     /* Child */
1695     if (preallocs < cacheStatEntries + 50)
1696         preallocs = cacheStatEntries + 50;
1697     fork_syscall(AFSCALL_CALL, AFSOP_START_RXCALLBACK, preallocs, 0, 0, 0);
1698
1699     /*
1700      * Start the RX event handler.
1701      */
1702     if (afsd_debug)
1703         printf("%s: Calling AFSOP_RXEVENT_DAEMON\n", rn);
1704     fork_syscall(AFSCALL_CALL, AFSOP_RXEVENT_DAEMON, FALSE, 0, 0, 0);
1705
1706     /*
1707      * Set up all the kernel processes needed for AFS.
1708      */
1709
1710     if (afsd_verbose)
1711         printf("%s: Initializing AFS daemon.\n", rn);
1712     call_syscall(AFSCALL_CALL, AFSOP_BASIC_INIT, 1, 0, 0, 0);
1713
1714     /*
1715      * Tell the kernel some basic information about the workstation's cache.
1716      */
1717     if (afsd_verbose)
1718         printf("%s: Calling AFSOP_CACHEINIT: %d stat cache entries,"
1719                " %d optimum cache files, %d blocks in the cache,"
1720                " flags = 0x%x, dcache entries %d\n", rn, cacheStatEntries,
1721                cacheFiles, cacheBlocks, cacheFlags, dCacheSize);
1722     memset(&cparams, 0, sizeof(cparams));
1723     cparams.cacheScaches = cacheStatEntries;
1724     cparams.cacheFiles = cacheFiles;
1725     cparams.cacheBlocks = cacheBlocks;
1726     cparams.cacheDcaches = dCacheSize;
1727     cparams.cacheVolumes = vCacheSize;
1728     cparams.chunkSize = chunkSize;
1729     cparams.setTimeFlag = FALSE;
1730     cparams.memCacheFlag = cacheFlags;
1731     call_syscall(AFSCALL_CALL, AFSOP_CACHEINIT, (long)&cparams, 0, 0, 0);
1732     if (afsd_CloseSynch)
1733         call_syscall(AFSCALL_CALL, AFSOP_CLOSEWAIT, 0, 0, 0, 0);
1734
1735     /*
1736      * Sweep the workstation AFS cache directory, remembering the inodes of
1737      * valid files and deleting extraneous files.  Keep sweeping until we
1738      * have the right number of data cache files or we've swept too many
1739      * times.
1740      */
1741     if (afsd_verbose)
1742         printf("%s: Sweeping workstation's AFS cache directory.\n", rn);
1743     cacheIteration = 0;
1744     /* Memory-cache based system doesn't need any of this */
1745     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
1746         do {
1747             cacheIteration++;
1748             if (SweepAFSCache(&vFilesFound)) {
1749                 printf("%s: Error on sweep %d of workstation AFS cache \
1750                        directory.\n", rn, cacheIteration);
1751                 exit(1);
1752             }
1753             if (afsd_verbose)
1754                 printf
1755                     ("%s: %d out of %d data cache files found in sweep %d.\n",
1756                      rn, vFilesFound, cacheFiles, cacheIteration);
1757         } while ((vFilesFound < cacheFiles)
1758                  && (cacheIteration < MAX_CACHE_LOOPS));
1759     } else if (afsd_verbose)
1760         printf("%s: Using memory cache, not swept\n", rn);
1761
1762     /*
1763      * Pass the kernel the name of the workstation cache file holding the 
1764      * dcache entries.
1765      */
1766     if (afsd_debug)
1767         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n", rn,
1768                fullpn_DCacheFile);
1769     /* once again, meaningless for a memory-based cache. */
1770     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
1771         call_syscall(AFSCALL_CALL, AFSOP_CACHEINFO, (long)fullpn_DCacheFile,
1772                      0, 0, 0);
1773
1774     call_syscall(AFSCALL_CALL, AFSOP_CELLINFO, (long)fullpn_CellInfoFile, 0,
1775                  0, 0);
1776
1777     /*
1778      * Pass the kernel the name of the workstation cache file holding the
1779      * volume information.
1780      */
1781     if (afsd_debug)
1782         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n", rn,
1783                fullpn_VolInfoFile);
1784     call_syscall(AFSCALL_CALL, AFSOP_VOLUMEINFO, (long)fullpn_VolInfoFile, 0,
1785                  0, 0);
1786
1787     /*
1788      * Pass the kernel the name of the afs logging file holding the volume
1789      * information.
1790      */
1791     if (afsd_debug)
1792         printf("%s: Calling AFSOP_AFSLOG: volume info file is '%s'\n", rn,
1793                fullpn_AFSLogFile);
1794     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))  /* ... nor this ... */
1795         call_syscall(AFSCALL_CALL, AFSOP_AFSLOG, (long)fullpn_AFSLogFile, 0,
1796                      0, 0);
1797
1798     /*
1799      * Tell the kernel about each cell in the configuration.
1800      */
1801     afsconf_CellApply(afs_cdir, ConfigCell, NULL);
1802     afsconf_CellAliasApply(afs_cdir, ConfigCellAlias, NULL);
1803
1804     /*
1805      * Set the primary cell name.
1806      */
1807     call_syscall(AFSCALL_CALL, AFSOP_SET_THISCELL, (long)afs_LclCellName, 0, 0, 0);
1808
1809     if (afsd_verbose)
1810         printf("%s: Forking AFS daemon.\n", rn);
1811     fork_syscall(AFSCALL_CALL, AFSOP_START_AFS, 0, 0, 0, 0);
1812
1813     if (afsd_verbose)
1814         printf("%s: Forking check server daemon.\n", rn);
1815     fork_syscall(AFSCALL_CALL, AFSOP_START_CS, 0, 0, 0, 0);
1816
1817     if (afsd_verbose)
1818         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
1819     for (i = 0; i < nDaemons; i++) {
1820         fork_syscall(AFSCALL_CALL, AFSOP_START_BKG, 0, 0, 0, 0);
1821     }
1822
1823     if (afsd_verbose)
1824         printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n", rn, rootVolume);
1825     call_syscall(AFSCALL_CALL, AFSOP_ROOTVOLUME, (long)rootVolume, 0, 0, 0);
1826
1827     /*
1828      * Give the kernel the names of the AFS files cached on the workstation's
1829      * disk.
1830      */
1831     if (afsd_debug)
1832         printf
1833             ("%s: Calling AFSOP_CACHEFILES for each of the %d files in '%s'\n",
1834              rn, cacheFiles, cacheBaseDir);
1835     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))  /* ... and again ... */
1836         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
1837             call_syscall(AFSCALL_CALL, AFSOP_CACHEFILE,
1838                          (long)pathname_for_V[currVFile], 0, 0, 0);
1839         }
1840     /*end for */
1841 /*#ifndef NETSCAPE_NSAPI*/
1842 #if 0
1843 /* this breaks solaris if the kernel-mode client has never been installed,
1844  * and it doesn't seem to work now anyway, so just disable it */
1845
1846     /*
1847      * Copy our tokens from the kernel to the user space client
1848      */
1849     for (i = 0; i < 200; i++) {
1850         /*
1851          * Get the i'th token from the kernel
1852          */
1853         memset((void *)&tbuffer[0], 0, sizeof(tbuffer));
1854         memcpy((void *)&tbuffer[0], (void *)&i, sizeof(int));
1855         iob.in = tbuffer;
1856         iob.in_size = sizeof(int);
1857         iob.out = tbuffer;
1858         iob.out_size = sizeof(tbuffer);
1859
1860 #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)
1861         rc = syscall(AFS_SYSCALL, AFSCALL_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1862 #elif defined(AFS_USR_SGI_ENV)
1863         rc = syscall(AFS_PIOCTL, 0, _VICEIOCTL(8), &iob, 0);
1864 #else /* AFS_USR_AIX_ENV */
1865         rc = lpioctl(0, _VICEIOCTL(8), &iob, 0);
1866 #endif
1867         if (rc < 0) {
1868             usr_assert(errno == EDOM || errno == ENOSYS || errno == ERANGE);
1869             break;
1870         }
1871
1872         /*
1873          * Now pass the token into the user space kernel
1874          */
1875         rc = uafs_SetTokens(tbuffer, iob.out_size);
1876         usr_assert(rc == 0);
1877     }
1878 #endif /* !NETSCAPE_NSAPI */
1879
1880     /*
1881      * All the necessary info has been passed into the kernel to run an AFS
1882      * system.  Give the kernel our go-ahead.
1883      */
1884     if (afsd_debug)
1885         printf("%s: Calling AFSOP_GO\n", rn);
1886     call_syscall(AFSCALL_CALL, AFSOP_GO, FALSE, 0, 0, 0);
1887
1888     /*
1889      * At this point, we have finished passing the kernel all the info 
1890      * it needs to set up the AFS.  Mount the AFS root.
1891      */
1892     printf("%s: All AFS daemons started.\n", rn);
1893
1894     if (afsd_verbose)
1895         printf("%s: Forking trunc-cache daemon.\n", rn);
1896     fork_syscall(AFSCALL_CALL, AFSOP_START_TRUNCDAEMON, 0, 0, 0, 0);
1897
1898     /*
1899      * Mount the AFS filesystem
1900      */
1901     AFS_GLOCK();
1902     rc = afs_mount(&afs_RootVfs, NULL, NULL);
1903     usr_assert(rc == 0);
1904     rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1905     usr_assert(rc == 0);
1906     AFS_GUNLOCK();
1907
1908     /*
1909      * initialize the current directory to the AFS root
1910      */
1911     afs_CurrentDir = afs_RootVnode;
1912     VN_HOLD(afs_CurrentDir);
1913
1914     return;
1915 }
1916
1917 void
1918 uafs_Shutdown(void)
1919 {
1920     int rc;
1921
1922     printf("\n");
1923
1924     AFS_GLOCK();
1925     VN_RELE(afs_CurrentDir);
1926     rc = afs_unmount(&afs_RootVfs);
1927     usr_assert(rc == 0);
1928     AFS_GUNLOCK();
1929
1930     printf("\n");
1931 }
1932
1933 /*
1934  * Donate the current thread to the RX server pool.
1935  */
1936 void
1937 uafs_RxServerProc(void)
1938 {
1939     osi_socket sock;
1940     int threadID;
1941     struct rx_call *newcall = NULL;
1942
1943     rxi_MorePackets(2);         /* alloc more packets */
1944     threadID = rxi_availProcs++;
1945
1946     while (1) {
1947         sock = OSI_NULLSOCKET;
1948         rxi_ServerProc(threadID, newcall, &sock);
1949         if (sock == OSI_NULLSOCKET) {
1950             break;
1951         }
1952         newcall = NULL;
1953         threadID = -1;
1954         rxi_ListenerProc(sock, &threadID, &newcall);
1955         /* assert(threadID != -1); */
1956         /* assert(newcall != NULL); */
1957     }
1958 }
1959
1960 struct syscallThreadArgs {
1961     long syscall;
1962     long afscall;
1963     long param1;
1964     long param2;
1965     long param3;
1966     long param4;
1967 };
1968
1969 #ifdef NETSCAPE_NSAPI
1970 void
1971 syscallThread(void *argp)
1972 #else /* NETSCAPE_NSAPI */
1973 void *
1974 syscallThread(void *argp)
1975 #endif                          /* NETSCAPE_NSAPI */
1976 {
1977     int i;
1978     struct usr_ucred *crp;
1979     struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1980
1981     /*
1982      * AFS daemons run authenticated
1983      */
1984     u.u_viceid = getuid();
1985     crp = u.u_cred;
1986     crp->cr_uid = getuid();
1987     crp->cr_ruid = getuid();
1988     crp->cr_suid = getuid();
1989     crp->cr_groups[0] = getgid();
1990     crp->cr_ngroups = 1;
1991     for (i = 1; i < NGROUPS; i++) {
1992         crp->cr_groups[i] = NOGROUP;
1993     }
1994
1995     call_syscall(sysArgsP->syscall, sysArgsP->afscall, sysArgsP->param1,
1996                  sysArgsP->param2, sysArgsP->param3, sysArgsP->param4);
1997
1998     afs_osi_Free(argp, -1);
1999     return 0;
2000 }
2001
2002 int
2003 fork_syscall(long syscall, long afscall, long param1, long param2,
2004              long param3, long param4)
2005 {
2006     usr_thread_t tid;
2007     struct syscallThreadArgs *sysArgsP;
2008
2009     sysArgsP = (struct syscallThreadArgs *)
2010         afs_osi_Alloc(sizeof(struct syscallThreadArgs));
2011     usr_assert(sysArgsP != NULL);
2012     sysArgsP->syscall = syscall;
2013     sysArgsP->afscall = afscall;
2014     sysArgsP->param1 = param1;
2015     sysArgsP->param2 = param2;
2016     sysArgsP->param3 = param3;
2017     sysArgsP->param4 = param4;
2018
2019     usr_thread_create(&tid, syscallThread, sysArgsP);
2020     usr_thread_detach(tid);
2021     return 0;
2022 }
2023
2024 int
2025 call_syscall(long syscall, long afscall, long param1, long param2,
2026              long param3, long param4)
2027 {
2028     int code = 0;
2029     struct a {
2030         long syscall;
2031         long afscall;
2032         long parm1;
2033         long parm2;
2034         long parm3;
2035         long parm4;
2036     } a;
2037
2038     a.syscall = syscall;
2039     a.afscall = afscall;
2040     a.parm1 = param1;
2041     a.parm2 = param2;
2042     a.parm3 = param3;
2043     a.parm4 = param4;
2044
2045     u.u_error = 0;
2046     u.u_ap = (char *)&a;
2047
2048     code = Afs_syscall();
2049     return code;
2050 }
2051
2052 int
2053 uafs_SetTokens(char *tbuffer, int tlen)
2054 {
2055     int rc;
2056     struct afs_ioctl iob;
2057     char outbuf[1024];
2058
2059     iob.in = tbuffer;
2060     iob.in_size = tlen;
2061     iob.out = &outbuf[0];
2062     iob.out_size = sizeof(outbuf);
2063
2064     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
2065     if (rc != 0) {
2066         errno = rc;
2067         return -1;
2068     }
2069     return 0;
2070 }
2071
2072 int
2073 uafs_RPCStatsEnableProc(void)
2074 {
2075     int rc;
2076     struct afs_ioctl iob;
2077     afs_int32 flag;
2078
2079     flag = AFSCALL_RXSTATS_ENABLE;
2080     iob.in = (char *)&flag;
2081     iob.in_size = sizeof(afs_int32);
2082     iob.out = NULL;
2083     iob.out_size = 0;
2084     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2085     if (rc != 0) {
2086         errno = rc;
2087         return -1;
2088     }
2089     return rc;
2090 }
2091
2092 int
2093 uafs_RPCStatsDisableProc(void)
2094 {
2095     int rc;
2096     struct afs_ioctl iob;
2097     afs_int32 flag;
2098
2099     flag = AFSCALL_RXSTATS_DISABLE;
2100     iob.in = (char *)&flag;
2101     iob.in_size = sizeof(afs_int32);
2102     iob.out = NULL;
2103     iob.out_size = 0;
2104     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2105     if (rc != 0) {
2106         errno = rc;
2107         return -1;
2108     }
2109     return rc;
2110 }
2111
2112 int
2113 uafs_RPCStatsClearProc(void)
2114 {
2115     int rc;
2116     struct afs_ioctl iob;
2117     afs_int32 flag;
2118
2119     flag = AFSCALL_RXSTATS_CLEAR;
2120     iob.in = (char *)&flag;
2121     iob.in_size = sizeof(afs_int32);
2122     iob.out = NULL;
2123     iob.out_size = 0;
2124     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
2125     if (rc != 0) {
2126         errno = rc;
2127         return -1;
2128     }
2129     return rc;
2130 }
2131
2132 int
2133 uafs_RPCStatsEnablePeer(void)
2134 {
2135     int rc;
2136     struct afs_ioctl iob;
2137     afs_int32 flag;
2138
2139     flag = AFSCALL_RXSTATS_ENABLE;
2140     iob.in = (char *)&flag;
2141     iob.in_size = sizeof(afs_int32);
2142     iob.out = NULL;
2143     iob.out_size = 0;
2144     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2145     if (rc != 0) {
2146         errno = rc;
2147         return -1;
2148     }
2149     return rc;
2150 }
2151
2152 int
2153 uafs_RPCStatsDisablePeer(void)
2154 {
2155     int rc;
2156     struct afs_ioctl iob;
2157     afs_int32 flag;
2158
2159     flag = AFSCALL_RXSTATS_DISABLE;
2160     iob.in = (char *)&flag;
2161     iob.in_size = sizeof(afs_int32);
2162     iob.out = NULL;
2163     iob.out_size = 0;
2164     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2165     if (rc != 0) {
2166         errno = rc;
2167         return -1;
2168     }
2169     return rc;
2170 }
2171
2172 int
2173 uafs_RPCStatsClearPeer(void)
2174 {
2175     int rc;
2176     struct afs_ioctl iob;
2177     afs_int32 flag;
2178
2179     flag = AFSCALL_RXSTATS_CLEAR;
2180     iob.in = (char *)&flag;
2181     iob.in_size = sizeof(afs_int32);
2182     iob.out = NULL;
2183     iob.out_size = 0;
2184     rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
2185     if (rc != 0) {
2186         errno = rc;
2187         return -1;
2188     }
2189     return rc;
2190 }
2191
2192 /*
2193  * Lookup a file or directory given its path.
2194  * Call VN_HOLD on the output vnode if successful.
2195  * Returns zero on success, error code on failure.
2196  *
2197  * Note: Caller must hold the AFS global lock.
2198  */
2199 int
2200 uafs_LookupName(char *path, struct usr_vnode *parentVp,
2201                 struct usr_vnode **vpp, int follow, int no_eval_mtpt)
2202 {
2203     int code = 0;
2204     int linkCount;
2205     struct usr_vnode *vp;
2206     struct usr_vnode *nextVp;
2207     struct usr_vnode *linkVp;
2208     struct vcache *nextVc;
2209     char *tmpPath;
2210     char *pathP;
2211     char *nextPathP = NULL;
2212
2213     AFS_ASSERT_GLOCK();
2214
2215     /*
2216      * Absolute paths must start with the AFS mount point.
2217      */
2218     if (path[0] != '/') {
2219         vp = parentVp;
2220     } else {
2221         path = uafs_afsPathName(path);
2222         if (path == NULL) {
2223             return ENOENT;
2224         }
2225         vp = afs_RootVnode;
2226     }
2227
2228     /*
2229      * Loop through the path looking for the new directory
2230      */
2231     tmpPath = afs_osi_Alloc(strlen(path) + 1);
2232     usr_assert(tmpPath != NULL);
2233     strcpy(tmpPath, path);
2234     VN_HOLD(vp);
2235     pathP = tmpPath;
2236     while (pathP != NULL && *pathP != '\0') {
2237         usr_assert(*pathP != '/');
2238
2239         /*
2240          * terminate the current component and skip over slashes
2241          */
2242         nextPathP = afs_strchr(pathP, '/');
2243         if (nextPathP != NULL) {
2244             while (*nextPathP == '/') {
2245                 *(nextPathP++) = '\0';
2246             }
2247         }
2248
2249         /*
2250          * Don't call afs_lookup on non-directories
2251          */
2252         if (vp->v_type != VDIR) {
2253             VN_RELE(vp);
2254             afs_osi_Free(tmpPath, strlen(path) + 1);
2255             return ENOTDIR;
2256         }
2257
2258         if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
2259             /*
2260              * The AFS root is its own parent
2261              */
2262             nextVp = afs_RootVnode;
2263         } else {
2264             /*
2265              * We need execute permission to search a directory
2266              */
2267             code = afs_access(VTOAFS(vp), VEXEC, u.u_cred);
2268             if (code != 0) {
2269                 VN_RELE(vp);
2270                 afs_osi_Free(tmpPath, strlen(path) + 1);
2271                 return code;
2272             }
2273
2274             /*
2275              * lookup the next component in the path, we can release the
2276              * subdirectory since we hold the global lock
2277              */
2278             nextVc = NULL;
2279             nextVp = NULL;
2280 #ifdef AFS_WEB_ENHANCEMENTS
2281             if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
2282                 code = afs_lookup(VTOAFS(vp), pathP, &nextVc, u.u_cred, 0);
2283             else
2284                 code =
2285                     afs_lookup(VTOAFS(vp), pathP, &nextVc, u.u_cred,
2286                                AFS_LOOKUP_NOEVAL);
2287 #else
2288             code = afs_lookup(VTOAFS(vp), pathP, &nextVc, u.u_cred, 0);
2289 #endif /* AFS_WEB_ENHANCEMENTS */
2290             if (nextVc)
2291                 nextVp=AFSTOV(nextVc);
2292             if (code != 0) {
2293                 VN_RELE(vp);
2294                 afs_osi_Free(tmpPath, strlen(path) + 1);
2295                 return code;
2296             }
2297         }
2298
2299         /*
2300          * Follow symbolic links for parent directories and
2301          * for leaves when the follow flag is set.
2302          */
2303         if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
2304             linkCount = 0;
2305             while (nextVp->v_type == VLNK) {
2306                 if (++linkCount > MAX_OSI_LINKS) {
2307                     VN_RELE(vp);
2308                     VN_RELE(nextVp);
2309                     afs_osi_Free(tmpPath, strlen(path) + 1);
2310                     return code;
2311                 }
2312                 code = uafs_LookupLink(nextVp, vp, &linkVp);
2313                 if (code) {
2314                     VN_RELE(vp);
2315                     VN_RELE(nextVp);
2316                     afs_osi_Free(tmpPath, strlen(path) + 1);
2317                     return code;
2318                 }
2319                 VN_RELE(nextVp);
2320                 nextVp = linkVp;
2321             }
2322         }
2323
2324         VN_RELE(vp);
2325         vp = nextVp;
2326         pathP = nextPathP;
2327     }
2328
2329     /*
2330      * Special case, nextPathP is non-null if pathname ends in slash
2331      */
2332     if (nextPathP != NULL && vp->v_type != VDIR) {
2333         VN_RELE(vp);
2334         afs_osi_Free(tmpPath, strlen(path) + 1);
2335         return ENOTDIR;
2336     }
2337
2338     afs_osi_Free(tmpPath, strlen(path) + 1);
2339     *vpp = vp;
2340     return 0;
2341 }
2342
2343 /*
2344  * Lookup the target of a symbolic link
2345  * Call VN_HOLD on the output vnode if successful.
2346  * Returns zero on success, error code on failure.
2347  *
2348  * Note: Caller must hold the AFS global lock.
2349  */
2350 int
2351 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
2352                 struct usr_vnode **vpp)
2353 {
2354     int code;
2355     int len;
2356     char *pathP;
2357     struct usr_vnode *linkVp;
2358     struct usr_uio uio;
2359     struct iovec iov[1];
2360
2361     AFS_ASSERT_GLOCK();
2362
2363     pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
2364     usr_assert(pathP != NULL);
2365
2366     /*
2367      * set up the uio buffer
2368      */
2369     iov[0].iov_base = pathP;
2370     iov[0].iov_len = MAX_OSI_PATH + 1;
2371     uio.uio_iov = &iov[0];
2372     uio.uio_iovcnt = 1;
2373     uio.uio_offset = 0;
2374     uio.uio_segflg = 0;
2375     uio.uio_fmode = FREAD;
2376     uio.uio_resid = MAX_OSI_PATH + 1;
2377
2378     /*
2379      * Read the link data
2380      */
2381     code = afs_readlink(VTOAFS(vp), &uio, u.u_cred);
2382     if (code) {
2383         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
2384         return code;
2385     }
2386     len = MAX_OSI_PATH + 1 - uio.uio_resid;
2387     pathP[len] = '\0';
2388
2389     /*
2390      * Find the target of the symbolic link
2391      */
2392     code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
2393     if (code) {
2394         afs_osi_Free(pathP, MAX_OSI_PATH + 1);
2395         return code;
2396     }
2397
2398     afs_osi_Free(pathP, MAX_OSI_PATH + 1);
2399     *vpp = linkVp;
2400     return 0;
2401 }
2402
2403 /*
2404  * Lookup the parent of a file or directory given its path
2405  * Call VN_HOLD on the output vnode if successful.
2406  * Returns zero on success, error code on failure.
2407  *
2408  * Note: Caller must hold the AFS global lock.
2409  */
2410 int
2411 uafs_LookupParent(char *path, struct usr_vnode **vpp)
2412 {
2413     int len;
2414     int code;
2415     char *pathP;
2416     struct usr_vnode *parentP;
2417
2418     AFS_ASSERT_GLOCK();
2419
2420     /*
2421      * Absolute path names must start with the AFS mount point.
2422      */
2423     if (*path == '/') {
2424         pathP = uafs_afsPathName(path);
2425         if (pathP == NULL) {
2426             return ENOENT;
2427         }
2428     }
2429
2430     /*
2431      * Find the length of the parent path
2432      */
2433     len = strlen(path);
2434     while (len > 0 && path[len - 1] == '/') {
2435         len--;
2436     }
2437     if (len == 0) {
2438         return EINVAL;
2439     }
2440     while (len > 0 && path[len - 1] != '/') {
2441         len--;
2442     }
2443     if (len == 0) {
2444         return EINVAL;
2445     }
2446
2447     pathP = afs_osi_Alloc(len);
2448     usr_assert(pathP != NULL);
2449     memcpy(pathP, path, len - 1);
2450     pathP[len - 1] = '\0';
2451
2452     /*
2453      * look up the parent
2454      */
2455     code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
2456     afs_osi_Free(pathP, len);
2457     if (code != 0) {
2458         return code;
2459     }
2460     if (parentP->v_type != VDIR) {
2461         VN_RELE(parentP);
2462         return ENOTDIR;
2463     }
2464
2465     *vpp = parentP;
2466     return 0;
2467 }
2468
2469 /*
2470  * Return a pointer to the first character in the last component
2471  * of a pathname
2472  */
2473 char *
2474 uafs_LastPath(char *path)
2475 {
2476     int len;
2477
2478     len = strlen(path);
2479     while (len > 0 && path[len - 1] == '/') {
2480         len--;
2481     }
2482     while (len > 0 && path[len - 1] != '/') {
2483         len--;
2484     }
2485     if (len == 0) {
2486         return NULL;
2487     }
2488     return path + len;
2489 }
2490
2491 /*
2492  * Set the working directory.
2493  */
2494 int
2495 uafs_chdir(char *path)
2496 {
2497     int retval;
2498     AFS_GLOCK();
2499     retval = uafs_chdir_r(path);
2500     AFS_GUNLOCK();
2501     return retval;
2502 }
2503
2504 int
2505 uafs_chdir_r(char *path)
2506 {
2507     int code;
2508     struct vnode *dirP;
2509
2510     code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
2511     if (code != 0) {
2512         errno = code;
2513         return -1;
2514     }
2515     if (dirP->v_type != VDIR) {
2516         VN_RELE(dirP);
2517         errno = ENOTDIR;
2518         return -1;
2519     }
2520     VN_RELE(afs_CurrentDir);
2521     afs_CurrentDir = dirP;
2522     return 0;
2523 }
2524
2525 /*
2526  * Create a directory.
2527  */
2528 int
2529 uafs_mkdir(char *path, int mode)
2530 {
2531     int retval;
2532     AFS_GLOCK();
2533     retval = uafs_mkdir_r(path, mode);
2534     AFS_GUNLOCK();
2535     return retval;
2536 }
2537
2538 int
2539 uafs_mkdir_r(char *path, int mode)
2540 {
2541     int code;
2542     char *nameP;
2543     struct vnode *parentP;
2544     struct vcache *dirP;
2545     struct usr_vattr attrs;
2546
2547     if (uafs_IsRoot(path)) {
2548         return EACCES;
2549     }
2550
2551     /*
2552      * Look up the parent directory.
2553      */
2554     nameP = uafs_LastPath(path);
2555     if (nameP != NULL) {
2556         code = uafs_LookupParent(path, &parentP);
2557         if (code != 0) {
2558             errno = code;
2559             return -1;
2560         }
2561     } else {
2562         parentP = afs_CurrentDir;
2563         nameP = path;
2564         VN_HOLD(parentP);
2565     }
2566
2567     /*
2568      * Make sure the directory has at least one character
2569      */
2570     if (*nameP == '\0') {
2571         VN_RELE(parentP);
2572         errno = EINVAL;
2573         return -1;
2574     }
2575
2576     /*
2577      * Create the directory
2578      */
2579     usr_vattr_null(&attrs);
2580     attrs.va_type = VREG;
2581     attrs.va_mode = mode;
2582     attrs.va_uid = u.u_cred->cr_uid;
2583     attrs.va_gid = u.u_cred->cr_gid;
2584     dirP = NULL;
2585     code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, u.u_cred);
2586     VN_RELE(parentP);
2587     if (code != 0) {
2588         errno = code;
2589         return -1;
2590     }
2591     VN_RELE(AFSTOV(dirP));
2592     return 0;
2593 }
2594
2595 /*
2596  * Return 1 if path is the AFS root, otherwise return 0
2597  */
2598 int
2599 uafs_IsRoot(char *path)
2600 {
2601     while (*path == '/' && *(path + 1) == '/') {
2602         path++;
2603     }
2604     if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2605         return 0;
2606     }
2607     path += afs_mountDirLen;
2608     while (*path == '/') {
2609         path++;
2610     }
2611     if (*path != '\0') {
2612         return 0;
2613     }
2614     return 1;
2615 }
2616
2617 /*
2618  * Open a file
2619  * Note: file name may not end in a slash.
2620  */
2621 int
2622 uafs_open(char *path, int flags, int mode)
2623 {
2624     int retval;
2625     AFS_GLOCK();
2626     retval = uafs_open_r(path, flags, mode);
2627     AFS_GUNLOCK();
2628     return retval;
2629 }
2630
2631 int
2632 uafs_open_r(char *path, int flags, int mode)
2633 {
2634     int fd;
2635     int code;
2636     int openFlags;
2637     int fileMode;
2638     struct usr_vnode *fileP;
2639     struct usr_vnode *dirP;
2640     struct usr_vattr attrs;
2641     char *nameP;
2642
2643     struct vcache* vc;
2644
2645     if (uafs_IsRoot(path)) {
2646         fileP = afs_RootVnode;
2647         VN_HOLD(fileP);
2648     } else {
2649         /*
2650          * Look up the parent directory.
2651          */
2652         nameP = uafs_LastPath(path);
2653         if (nameP != NULL) {
2654             code = uafs_LookupParent(path, &dirP);
2655             if (code != 0) {
2656                 errno = code;
2657                 return -1;
2658             }
2659         } else {
2660             dirP = afs_CurrentDir;
2661             nameP = path;
2662             VN_HOLD(dirP);
2663         }
2664
2665         /*
2666          * Make sure the filename has at least one character
2667          */
2668         if (*nameP == '\0') {
2669             VN_RELE(dirP);
2670             errno = EINVAL;
2671             return -1;
2672         }
2673
2674         /*
2675          * Get the VNODE for this file
2676          */
2677         if (flags & O_CREAT) {
2678             usr_vattr_null(&attrs);
2679             attrs.va_type = VREG;
2680             attrs.va_mode = mode;
2681             attrs.va_uid = u.u_cred->cr_uid;
2682             attrs.va_gid = u.u_cred->cr_gid;
2683             if (flags & O_TRUNC) {
2684                 attrs.va_size = 0;
2685             }
2686             fileP = NULL;
2687             vc=VTOAFS(fileP);
2688             code =
2689                 afs_create(VTOAFS(dirP), nameP, &attrs,
2690                            (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2691                            &vc, u.u_cred);
2692             VN_RELE(dirP);
2693             if (code != 0) {
2694                 errno = code;
2695                 return -1;
2696             }
2697             fileP = AFSTOV(vc);
2698         } else {
2699             fileP = NULL;
2700             code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2701             VN_RELE(dirP);
2702             if (code != 0) {
2703                 errno = code;
2704                 return -1;
2705             }
2706
2707             /*
2708              * Check whether we have access to this file
2709              */
2710             fileMode = 0;
2711             if (flags & (O_RDONLY | O_RDWR)) {
2712                 fileMode |= VREAD;
2713             }
2714             if (flags & (O_WRONLY | O_RDWR)) {
2715                 fileMode |= VWRITE;
2716             }
2717             if (!fileMode)
2718                 fileMode = VREAD;       /* since O_RDONLY is 0 */
2719             code = afs_access(VTOAFS(fileP), fileMode, u.u_cred);
2720             if (code != 0) {
2721                 VN_RELE(fileP);
2722                 errno = code;
2723                 return -1;
2724             }
2725
2726             /*
2727              * Get the file attributes, all we need is the size
2728              */
2729             code = afs_getattr(VTOAFS(fileP), &attrs, u.u_cred);
2730             if (code != 0) {
2731                 VN_RELE(fileP);
2732                 errno = code;
2733                 return -1;
2734             }
2735         }
2736     }
2737
2738     /*
2739      * Setup the open flags
2740      */
2741     openFlags = 0;
2742     if (flags & O_TRUNC) {
2743         openFlags |= FTRUNC;
2744     }
2745     if (flags & O_APPEND) {
2746         openFlags |= FAPPEND;
2747     }
2748     if (flags & O_SYNC) {
2749         openFlags |= FSYNC;
2750     }
2751     if (flags & O_SYNC) {
2752         openFlags |= FSYNC;
2753     }
2754     if (flags & (O_RDONLY | O_RDWR)) {
2755         openFlags |= FREAD;
2756     }
2757     if (flags & (O_WRONLY | O_RDWR)) {
2758         openFlags |= FWRITE;
2759     }
2760     if ((openFlags & (FREAD | FWRITE)) == 0) {
2761         /* O_RDONLY is 0, so ... */
2762         openFlags |= FREAD;
2763     }
2764
2765     /*
2766      * Truncate if necessary
2767      */
2768     if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2769         usr_vattr_null(&attrs);
2770         attrs.va_mask = ATTR_SIZE;
2771         attrs.va_size = 0;
2772         code = afs_setattr(VTOAFS(fileP), &attrs, u.u_cred);
2773         if (code != 0) {
2774             VN_RELE(fileP);
2775             errno = code;
2776             return -1;
2777         }
2778     }
2779
2780     vc=VTOAFS(fileP);   
2781     /*
2782      * do the open
2783      */
2784     code = afs_open(&vc, openFlags, u.u_cred);
2785     if (code != 0) {
2786         VN_RELE(fileP);
2787         errno = code;
2788         return -1;
2789     }
2790
2791     /*
2792      * Put the vnode pointer into the file table
2793      */
2794     for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2795         if (afs_FileTable[fd] == NULL) {
2796             afs_FileTable[fd] = fileP;
2797             afs_FileFlags[fd] = openFlags;
2798             if (flags & O_APPEND) {
2799                 afs_FileOffsets[fd] = attrs.va_size;
2800             } else {
2801                 afs_FileOffsets[fd] = 0;
2802             }
2803             break;
2804         }
2805     }
2806     if (fd == MAX_OSI_FILES) {
2807         VN_RELE(fileP);
2808         errno = ENFILE;
2809         return -1;
2810     }
2811
2812     return fd;
2813 }
2814
2815 /*
2816  * Create a file
2817  */
2818 int
2819 uafs_creat(char *path, int mode)
2820 {
2821     int rc;
2822     rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2823     return rc;
2824 }
2825
2826 int
2827 uafs_creat_r(char *path, int mode)
2828 {
2829     int rc;
2830     rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2831     return rc;
2832 }
2833
2834 /*
2835  * Write to a file
2836  */
2837 int
2838 uafs_write(int fd, char *buf, int len)
2839 {
2840     int retval;
2841     AFS_GLOCK();
2842     retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
2843     AFS_GUNLOCK();
2844     return retval;
2845 }
2846
2847 int
2848 uafs_pwrite(int fd, char *buf, int len, off_t offset)
2849 {
2850     int retval;
2851     AFS_GLOCK();
2852     retval = uafs_pwrite_r(fd, buf, len, offset);
2853     AFS_GUNLOCK();
2854     return retval;
2855 }
2856
2857 int
2858 uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
2859 {
2860     int code;
2861     struct usr_uio uio;
2862     struct iovec iov[1];
2863     struct usr_vnode *fileP;
2864
2865     /*
2866      * Make sure this is an open file
2867      */
2868     fileP = afs_FileTable[fd];
2869     if (fileP == NULL) {
2870         errno = EBADF;
2871         return -1;
2872     }
2873
2874     /*
2875      * set up the uio buffer
2876      */
2877     iov[0].iov_base = buf;
2878     iov[0].iov_len = len;
2879     uio.uio_iov = &iov[0];
2880     uio.uio_iovcnt = 1;
2881     uio.uio_offset = offset;
2882     uio.uio_segflg = 0;
2883     uio.uio_fmode = FWRITE;
2884     uio.uio_resid = len;
2885
2886     /*
2887      * do the write
2888      */
2889
2890     code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], u.u_cred, 0);
2891     if (code) {
2892         errno = code;
2893         return -1;
2894     }
2895
2896     afs_FileOffsets[fd] = uio.uio_offset;
2897     return (len - uio.uio_resid);
2898 }
2899
2900 /*
2901  * Read from a file
2902  */
2903 int
2904 uafs_read(int fd, char *buf, int len)
2905 {
2906     int retval;
2907     AFS_GLOCK();
2908     retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
2909     AFS_GUNLOCK();
2910     return retval;
2911 }
2912
2913 int
2914 uafs_pread(int fd, char *buf, int len, off_t offset)
2915 {
2916     int retval;
2917     AFS_GLOCK();
2918     retval = uafs_pread_r(fd, buf, len, offset);
2919     AFS_GUNLOCK();
2920     return retval;
2921 }
2922
2923 int
2924 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2925 {
2926     int code;
2927     struct usr_uio uio;
2928     struct iovec iov[1];
2929     struct usr_vnode *fileP;
2930     struct usr_buf *bufP;
2931
2932     /*
2933      * Make sure this is an open file
2934      */
2935     fileP = afs_FileTable[fd];
2936     if (fileP == NULL) {
2937         errno = EBADF;
2938         return -1;
2939     }
2940
2941     /*
2942      * set up the uio buffer
2943      */
2944     iov[0].iov_base = buf;
2945     iov[0].iov_len = len;
2946     uio.uio_iov = &iov[0];
2947     uio.uio_iovcnt = 1;
2948     uio.uio_offset = offset;
2949     uio.uio_segflg = 0;
2950     uio.uio_fmode = FREAD;
2951     uio.uio_resid = len;
2952
2953     /*
2954      * do the read
2955      */
2956     code = afs_read(VTOAFS(fileP), &uio, u.u_cred, 0, &bufP, 0);
2957     if (code) {
2958         errno = code;
2959         return -1;
2960     }
2961
2962     afs_FileOffsets[fd] = uio.uio_offset;
2963     return (len - uio.uio_resid);
2964 }
2965
2966 /*
2967  * Copy the attributes of a file into a stat structure.
2968  *
2969  * NOTE: Caller must hold the global AFS lock.
2970  */
2971 int
2972 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2973 {
2974     int code;
2975     struct usr_vattr attrs;
2976
2977     AFS_ASSERT_GLOCK();
2978
2979     /*
2980      * Get the attributes
2981      */
2982     code = afs_getattr(VTOAFS(vp), &attrs, u.u_cred);
2983     if (code != 0) {
2984         return code;
2985     }
2986
2987     /*
2988      * Copy the attributes, zero fields that aren't set
2989      */
2990     memset((void *)stats, 0, sizeof(struct stat));
2991     stats->st_dev = -1;
2992     stats->st_ino = attrs.va_nodeid;
2993     stats->st_mode = attrs.va_mode;
2994     stats->st_nlink = attrs.va_nlink;
2995     stats->st_uid = attrs.va_uid;
2996     stats->st_gid = attrs.va_gid;
2997     stats->st_rdev = attrs.va_rdev;
2998     stats->st_size = attrs.va_size;
2999     stats->st_atime = attrs.va_atime.tv_sec;
3000     stats->st_mtime = attrs.va_mtime.tv_sec;
3001     stats->st_ctime = attrs.va_ctime.tv_sec;
3002     stats->st_blksize = attrs.va_blocksize;
3003     stats->st_blocks = attrs.va_blocks;
3004
3005     return 0;
3006 }
3007
3008 /*
3009  * Get the attributes of a file, do follow links
3010  */
3011 int
3012 uafs_stat(char *path, struct stat *buf)
3013 {
3014     int retval;
3015     AFS_GLOCK();
3016     retval = uafs_stat_r(path, buf);
3017     AFS_GUNLOCK();
3018     return retval;
3019 }
3020
3021 int
3022 uafs_stat_r(char *path, struct stat *buf)
3023 {
3024     int code;
3025     struct vnode *vp;
3026
3027     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3028     if (code != 0) {
3029         errno = code;
3030         return -1;
3031     }
3032     code = uafs_GetAttr(vp, buf);
3033     VN_RELE(vp);
3034     if (code) {
3035         errno = code;
3036         return -1;
3037     }
3038     return 0;
3039 }
3040
3041 /*
3042  * Get the attributes of a file, don't follow links
3043  */
3044 int
3045 uafs_lstat(char *path, struct stat *buf)
3046 {
3047     int retval;
3048     AFS_GLOCK();
3049     retval = uafs_lstat_r(path, buf);
3050     AFS_GUNLOCK();
3051     return retval;
3052 }
3053
3054 int
3055 uafs_lstat_r(char *path, struct stat *buf)
3056 {
3057     int code;
3058     struct vnode *vp;
3059
3060     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3061     if (code != 0) {
3062         errno = code;
3063         return -1;
3064     }
3065     code = uafs_GetAttr(vp, buf);
3066     VN_RELE(vp);
3067     if (code) {
3068         errno = code;
3069         return -1;
3070     }
3071     return 0;
3072 }
3073
3074 /*
3075  * Get the attributes of an open file
3076  */
3077 int
3078 uafs_fstat(int fd, struct stat *buf)
3079 {
3080     int retval;
3081     AFS_GLOCK();
3082     retval = uafs_fstat_r(fd, buf);
3083     AFS_GUNLOCK();
3084     return retval;
3085 }
3086
3087 int
3088 uafs_fstat_r(int fd, struct stat *buf)
3089 {
3090     int code;
3091     struct vnode *vp;
3092
3093     vp = afs_FileTable[fd];
3094     if (vp == NULL) {
3095         errno = EBADF;
3096         return -1;
3097     }
3098     code = uafs_GetAttr(vp, buf);
3099     if (code) {
3100         errno = code;
3101         return -1;
3102     }
3103     return 0;
3104 }
3105
3106 /*
3107  * change the permissions on a file
3108  */
3109 int
3110 uafs_chmod(char *path, int mode)
3111 {
3112     int retval;
3113     AFS_GLOCK();
3114     retval = uafs_chmod_r(path, mode);
3115     AFS_GUNLOCK();
3116     return retval;
3117 }
3118
3119 int
3120 uafs_chmod_r(char *path, int mode)
3121 {
3122     int code;
3123     struct vnode *vp;
3124     struct usr_vattr attrs;
3125
3126     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3127     if (code != 0) {
3128         errno = code;
3129         return -1;
3130     }
3131     usr_vattr_null(&attrs);
3132     attrs.va_mask = ATTR_MODE;
3133     attrs.va_mode = mode;
3134     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3135     VN_RELE(vp);
3136     if (code != 0) {
3137         errno = code;
3138         return -1;
3139     }
3140     return 0;
3141 }
3142
3143 /*
3144  * change the permissions on an open file
3145  */
3146 int
3147 uafs_fchmod(int fd, int mode)
3148 {
3149     int retval;
3150     AFS_GLOCK();
3151     retval = uafs_fchmod_r(fd, mode);
3152     AFS_GUNLOCK();
3153     return retval;
3154 }
3155
3156 int
3157 uafs_fchmod_r(int fd, int mode)
3158 {
3159     int code;
3160     struct vnode *vp;
3161     struct usr_vattr attrs;
3162
3163     vp = afs_FileTable[fd];
3164     if (vp == NULL) {
3165         errno = EBADF;
3166         return -1;
3167     }
3168     usr_vattr_null(&attrs);
3169     attrs.va_mask = ATTR_MODE;
3170     attrs.va_mode = mode;
3171     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3172     if (code != 0) {
3173         errno = code;
3174         return -1;
3175     }
3176     return 0;
3177 }
3178
3179 /*
3180  * truncate a file
3181  */
3182 int
3183 uafs_truncate(char *path, int length)
3184 {
3185     int retval;
3186     AFS_GLOCK();
3187     retval = uafs_truncate_r(path, length);
3188     AFS_GUNLOCK();
3189     return retval;
3190 }
3191
3192 int
3193 uafs_truncate_r(char *path, int length)
3194 {
3195     int code;
3196     struct vnode *vp;
3197     struct usr_vattr attrs;
3198
3199     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3200     if (code != 0) {
3201         errno = code;
3202         return -1;
3203     }
3204     usr_vattr_null(&attrs);
3205     attrs.va_mask = ATTR_SIZE;
3206     attrs.va_size = length;
3207     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3208     VN_RELE(vp);
3209     if (code != 0) {
3210         errno = code;
3211         return -1;
3212     }
3213     return 0;
3214 }
3215
3216 /*
3217  * truncate an open file
3218  */
3219 int
3220 uafs_ftruncate(int fd, int length)
3221 {
3222     int retval;
3223     AFS_GLOCK();
3224     retval = uafs_ftruncate_r(fd, length);
3225     AFS_GUNLOCK();
3226     return retval;
3227 }
3228
3229 int
3230 uafs_ftruncate_r(int fd, int length)
3231 {
3232     int code;
3233     struct vnode *vp;
3234     struct usr_vattr attrs;
3235
3236     vp = afs_FileTable[fd];
3237     if (vp == NULL) {
3238         errno = EBADF;
3239         return -1;
3240     }
3241     usr_vattr_null(&attrs);
3242     attrs.va_mask = ATTR_SIZE;
3243     attrs.va_size = length;
3244     code = afs_setattr(VTOAFS(vp), &attrs, u.u_cred);
3245     if (code != 0) {
3246         errno = code;
3247         return -1;
3248     }
3249     return 0;
3250 }
3251
3252 /*
3253  * set the read/write file pointer of an open file
3254  */
3255 int
3256 uafs_lseek(int fd, int offset, int whence)
3257 {
3258     int retval;
3259     AFS_GLOCK();
3260     retval = uafs_lseek_r(fd, offset, whence);
3261     AFS_GUNLOCK();
3262     return retval;
3263 }
3264
3265 int
3266 uafs_lseek_r(int fd, int offset, int whence)
3267 {
3268     int code;
3269     int newpos;
3270     struct usr_vattr attrs;
3271     struct usr_vnode *vp;
3272
3273     vp = afs_FileTable[fd];
3274     if (vp == NULL) {
3275         errno = EBADF;
3276         return -1;
3277     }
3278     switch (whence) {
3279     case SEEK_CUR:
3280         newpos = afs_FileOffsets[fd] + offset;
3281         break;
3282     case SEEK_SET:
3283         newpos = offset;
3284         break;
3285     case SEEK_END:
3286         code = afs_getattr(VTOAFS(vp), &attrs, u.u_cred);
3287         if (code != 0) {
3288             errno = code;
3289             return -1;
3290         }
3291         newpos = attrs.va_size + offset;
3292         break;
3293     default:
3294         errno = EINVAL;
3295         return -1;
3296     }
3297     if (newpos < 0) {
3298         errno = EINVAL;
3299         return -1;
3300     }
3301     afs_FileOffsets[fd] = newpos;
3302     return newpos;
3303 }
3304
3305 /*
3306  * sync a file
3307  */
3308 int
3309 uafs_fsync(int fd)
3310 {
3311     int retval;
3312     AFS_GLOCK();
3313     retval = uafs_fsync_r(fd);
3314     AFS_GUNLOCK();
3315     return retval;
3316 }
3317
3318 int
3319 uafs_fsync_r(int fd)
3320 {
3321     int code;
3322     struct usr_vnode *fileP;
3323
3324
3325     fileP = afs_FileTable[fd];
3326     if (fileP == NULL) {
3327         errno = EBADF;
3328         return -1;
3329     }
3330
3331     code = afs_fsync(VTOAFS(fileP), u.u_cred);
3332     if (code != 0) {
3333         errno = code;
3334         return -1;
3335     }
3336
3337     return 0;
3338 }
3339
3340 /*
3341  * Close a file
3342  */
3343 int
3344 uafs_close(int fd)
3345 {
3346     int retval;
3347     AFS_GLOCK();
3348     retval = uafs_close_r(fd);
3349     AFS_GUNLOCK();
3350     return retval;
3351 }
3352
3353 int
3354 uafs_close_r(int fd)
3355 {
3356     int code;
3357     struct usr_vnode *fileP;
3358
3359     fileP = afs_FileTable[fd];
3360     if (fileP == NULL) {
3361         errno = EBADF;
3362         return -1;
3363     }
3364     afs_FileTable[fd] = NULL;
3365
3366     code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], u.u_cred);
3367     VN_RELE(fileP);
3368     if (code != 0) {
3369         errno = code;
3370         return -1;
3371     }
3372
3373     return 0;
3374 }
3375
3376 /*
3377  * Create a hard link from the source to the target
3378  * Note: file names may not end in a slash.
3379  */
3380 int
3381 uafs_link(char *existing, char *new)
3382 {
3383     int retval;
3384     AFS_GLOCK();
3385     retval = uafs_link_r(existing, new);
3386     AFS_GUNLOCK();
3387     return retval;
3388 }
3389
3390 int
3391 uafs_link_r(char *existing, char *new)
3392 {
3393     int code;
3394     struct usr_vnode *existP;
3395     struct usr_vnode *dirP;
3396     char *nameP;
3397
3398     if (uafs_IsRoot(new)) {
3399         return EACCES;
3400     }
3401
3402     /*
3403      * Look up the existing node.
3404      */
3405     code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
3406     if (code != 0) {
3407         errno = code;
3408         return -1;
3409     }
3410
3411     /*
3412      * Look up the parent directory.
3413      */
3414     nameP = uafs_LastPath(new);
3415     if (nameP != NULL) {
3416         code = uafs_LookupParent(new, &dirP);
3417         if (code != 0) {
3418             VN_RELE(existP);
3419             errno = code;
3420             return -1;
3421         }
3422     } else {
3423         dirP = afs_CurrentDir;
3424         nameP = new;
3425         VN_HOLD(dirP);
3426     }
3427
3428     /*
3429      * Make sure the filename has at least one character
3430      */
3431     if (*nameP == '\0') {
3432         VN_RELE(existP);
3433         VN_RELE(dirP);
3434         errno = EINVAL;
3435         return -1;
3436     }
3437
3438     /*
3439      * Create the link
3440      */
3441     code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, u.u_cred);
3442     VN_RELE(existP);
3443     VN_RELE(dirP);
3444     if (code != 0) {
3445         errno = code;
3446         return -1;
3447     }
3448     return 0;
3449 }
3450
3451 /*
3452  * Create a symbolic link from the source to the target
3453  * Note: file names may not end in a slash.
3454  */
3455 int
3456 uafs_symlink(char *target, char *source)
3457 {
3458     int retval;
3459     AFS_GLOCK();
3460     retval = uafs_symlink_r(target, source);
3461     AFS_GUNLOCK();
3462     return retval;
3463 }
3464
3465 int
3466 uafs_symlink_r(char *target, char *source)
3467 {
3468     int code;
3469     struct usr_vnode *dirP;
3470     struct usr_vattr attrs;
3471     char *nameP;
3472
3473     if (uafs_IsRoot(source)) {
3474         return EACCES;
3475     }
3476
3477     /*
3478      * Look up the parent directory.
3479      */
3480     nameP = uafs_LastPath(source);
3481     if (nameP != NULL) {
3482         code = uafs_LookupParent(source, &dirP);
3483         if (code != 0) {
3484             errno = code;
3485             return -1;
3486         }
3487     } else {
3488         dirP = afs_CurrentDir;
3489         nameP = source;
3490         VN_HOLD(dirP);
3491     }
3492
3493     /*
3494      * Make sure the filename has at least one character
3495      */
3496     if (*nameP == '\0') {
3497         VN_RELE(dirP);
3498         errno = EINVAL;
3499         return -1;
3500     }
3501
3502     /*
3503      * Create the link
3504      */
3505     usr_vattr_null(&attrs);
3506     attrs.va_type = VLNK;
3507     attrs.va_mode = 0777;
3508     attrs.va_uid = u.u_cred->cr_uid;
3509     attrs.va_gid = u.u_cred->cr_gid;
3510     code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, u.u_cred);
3511     VN_RELE(dirP);
3512     if (code != 0) {
3513         errno = code;
3514         return -1;
3515     }
3516     return 0;
3517 }
3518
3519 /*
3520  * Read a symbolic link into the buffer
3521  */
3522 int
3523 uafs_readlink(char *path, char *buf, int len)
3524 {
3525     int retval;
3526     AFS_GLOCK();
3527     retval = uafs_readlink_r(path, buf, len);
3528     AFS_GUNLOCK();
3529     return retval;
3530 }
3531
3532 int
3533 uafs_readlink_r(char *path, char *buf, int len)
3534 {
3535     int code;
3536     struct usr_vnode *vp;
3537     struct usr_uio uio;
3538     struct iovec iov[1];
3539
3540     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3541     if (code != 0) {
3542         errno = code;
3543         return -1;
3544     }
3545
3546     if (vp->v_type != VLNK) {
3547         VN_RELE(vp);
3548         errno = EINVAL;
3549         return -1;
3550     }
3551
3552     /*
3553      * set up the uio buffer
3554      */
3555     iov[0].iov_base = buf;
3556     iov[0].iov_len = len;
3557     uio.uio_iov = &iov[0];
3558     uio.uio_iovcnt = 1;
3559     uio.uio_offset = 0;
3560     uio.uio_segflg = 0;
3561     uio.uio_fmode = FREAD;
3562     uio.uio_resid = len;
3563
3564     /*
3565      * Read the the link
3566      */
3567     code = afs_readlink(VTOAFS(vp), &uio, u.u_cred);
3568     VN_RELE(vp);
3569     if (code) {
3570         errno = code;
3571         return -1;
3572     }
3573
3574     /*
3575      * return the number of bytes read
3576      */
3577     return (len - uio.uio_resid);
3578 }
3579
3580 /*
3581  * Remove a file (or directory)
3582  * Note: file name may not end in a slash.
3583  */
3584 int
3585 uafs_unlink(char *path)
3586 {
3587     int retval;
3588     AFS_GLOCK();
3589     retval = uafs_unlink_r(path);
3590     AFS_GUNLOCK();
3591     return retval;
3592 }
3593
3594 int
3595 uafs_unlink_r(char *path)
3596 {
3597     int code;
3598     struct usr_vnode *dirP;
3599     char *nameP;
3600
3601     if (uafs_IsRoot(path)) {
3602         return EACCES;
3603     }
3604
3605     /*
3606      * Look up the parent directory.
3607      */
3608     nameP = uafs_LastPath(path);
3609     if (nameP != NULL) {
3610         code = uafs_LookupParent(path, &dirP);
3611         if (code != 0) {
3612             errno = code;
3613             return -1;
3614         }
3615     } else {
3616         dirP = afs_CurrentDir;
3617         nameP = path;
3618         VN_HOLD(dirP);
3619     }
3620
3621     /*
3622      * Make sure the filename has at least one character
3623      */
3624     if (*nameP == '\0') {
3625         VN_RELE(dirP);
3626         errno = EINVAL;
3627         return -1;
3628     }
3629
3630     /*
3631      * Remove the file
3632      */
3633     code = afs_remove(VTOAFS(dirP), nameP, u.u_cred);
3634     VN_RELE(dirP);
3635     if (code != 0) {
3636         errno = code;
3637         return -1;
3638     }
3639
3640     return 0;
3641 }
3642
3643 /*
3644  * Rename a file (or directory)
3645  */
3646 int
3647 uafs_rename(char *old, char *new)
3648 {
3649     int retval;
3650     AFS_GLOCK();
3651     retval = uafs_rename_r(old, new);
3652     AFS_GUNLOCK();
3653     return retval;
3654 }
3655
3656 int
3657 uafs_rename_r(char *old, char *new)
3658 {
3659     int code;
3660     char *onameP;
3661     char *nnameP;
3662     struct usr_vnode *odirP;
3663     struct usr_vnode *ndirP;
3664
3665     if (uafs_IsRoot(new)) {
3666         return EACCES;
3667     }
3668
3669     /*
3670      * Look up the parent directories.
3671      */
3672     onameP = uafs_LastPath(old);
3673     if (onameP != NULL) {
3674         code = uafs_LookupParent(old, &odirP);
3675         if (code != 0) {
3676             errno = code;
3677             return -1;
3678         }
3679     } else {
3680         odirP = afs_CurrentDir;
3681         onameP = old;
3682         VN_HOLD(odirP);
3683     }
3684     nnameP = uafs_LastPath(new);
3685     if (nnameP != NULL) {
3686         code = uafs_LookupParent(new, &ndirP);
3687         if (code != 0) {
3688             errno = code;
3689             return -1;
3690         }
3691     } else {
3692         ndirP = afs_CurrentDir;
3693         nnameP = new;
3694         VN_HOLD(ndirP);
3695     }
3696
3697     /*
3698      * Make sure the filename has at least one character
3699      */
3700     if (*onameP == '\0' || *nnameP == '\0') {
3701         VN_RELE(odirP);
3702         VN_RELE(ndirP);
3703         errno = EINVAL;
3704         return -1;
3705     }
3706
3707     /*
3708      * Rename the file
3709      */
3710     code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, u.u_cred);
3711     VN_RELE(odirP);
3712     VN_RELE(ndirP);
3713     if (code != 0) {
3714         errno = code;
3715         return -1;
3716     }
3717
3718     return 0;
3719 }
3720
3721 /*
3722  * Remove a or directory
3723  * Note: file name may not end in a slash.
3724  */
3725 int
3726 uafs_rmdir(char *path)
3727 {
3728     int retval;
3729     AFS_GLOCK();
3730     retval = uafs_rmdir_r(path);
3731     AFS_GUNLOCK();
3732     return retval;
3733 }
3734
3735 int
3736 uafs_rmdir_r(char *path)
3737 {
3738     int code;
3739     struct usr_vnode *dirP;
3740     char *nameP;
3741
3742     if (uafs_IsRoot(path)) {
3743         return EACCES;
3744     }
3745
3746     /*
3747      * Look up the parent directory.
3748      */
3749     nameP = uafs_LastPath(path);
3750     if (nameP != NULL) {
3751         code = uafs_LookupParent(path, &dirP);
3752         if (code != 0) {
3753             errno = code;
3754             return -1;
3755         }
3756     } else {
3757         dirP = afs_CurrentDir;
3758         nameP = path;
3759         VN_HOLD(dirP);
3760     }
3761
3762     /*
3763      * Make sure the directory name has at least one character
3764      */
3765     if (*nameP == '\0') {
3766         VN_RELE(dirP);
3767         errno = EINVAL;
3768         return -1;
3769     }
3770
3771     /*
3772      * Remove the directory
3773      */
3774     code = afs_rmdir(VTOAFS(dirP), nameP, u.u_cred);
3775     VN_RELE(dirP);
3776     if (code != 0) {
3777         errno = code;
3778         return -1;
3779     }
3780
3781     return 0;
3782 }
3783
3784 /*
3785  * Flush a file from the AFS cache
3786  */
3787 int
3788 uafs_FlushFile(char *path)
3789 {
3790     int code;
3791     struct afs_ioctl iob;
3792
3793     iob.in = NULL;
3794     iob.in_size = 0;
3795     iob.out = NULL;
3796     iob.out_size = 0;
3797
3798     code =
3799         call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3800                      0);
3801     if (code != 0) {
3802         errno = code;
3803         return -1;
3804     }
3805
3806     return 0;
3807 }
3808
3809 int
3810 uafs_FlushFile_r(char *path)
3811 {
3812     int retval;
3813     AFS_GUNLOCK();
3814     retval = uafs_FlushFile(path);
3815     AFS_GLOCK();
3816     return retval;
3817 }
3818
3819 /*
3820  * open a directory
3821  */
3822 usr_DIR *
3823 uafs_opendir(char *path)
3824 {
3825     usr_DIR *retval;
3826     AFS_GLOCK();
3827     retval = uafs_opendir_r(path);
3828     AFS_GUNLOCK();
3829     return retval;
3830 }
3831
3832 usr_DIR *
3833 uafs_opendir_r(char *path)
3834 {
3835     usr_DIR *dirp;
3836     struct usr_vnode *fileP;
3837     int fd;
3838
3839     /*
3840      * Open the directory for reading
3841      */
3842     fd = uafs_open_r(path, O_RDONLY, 0);
3843     if (fd < 0) {
3844         return NULL;
3845     }
3846
3847     fileP = afs_FileTable[fd];
3848     if (fileP == NULL) {
3849         return NULL;
3850     }
3851
3852     if (fileP->v_type != VDIR) {
3853         uafs_close_r(fd);
3854         errno = ENOTDIR;
3855         return NULL;
3856     }
3857
3858     /*
3859      * Set up the directory structures
3860      */
3861     dirp =
3862         (usr_DIR *) afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3863                                   sizeof(struct usr_dirent));
3864     usr_assert(dirp != NULL);
3865     dirp->dd_buf = (char *)(dirp + 1);
3866     dirp->dd_fd = fd;
3867     dirp->dd_loc = 0;
3868     dirp->dd_size = 0;
3869
3870     errno = 0;
3871     return dirp;
3872 }
3873
3874 /*
3875  * Read directory entries into a file system independent format.
3876  * This routine was developed to support AFS cache consistency testing.
3877  * You should use uafs_readdir instead.
3878  */
3879 int
3880 uafs_getdents(int fd, struct min_direct *buf, int len)
3881 {
3882     int retval;
3883     AFS_GLOCK();
3884     retval = uafs_getdents_r(fd, buf, len);
3885     AFS_GUNLOCK();
3886     return retval;
3887 }
3888
3889 int
3890 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3891 {
3892     int code;
3893     struct usr_uio uio;
3894     struct usr_vnode *vp;
3895     struct iovec iov[1];
3896
3897     /*
3898      * Make sure this is an open file
3899      */
3900     vp = afs_FileTable[fd];
3901     if (vp == NULL) {
3902         AFS_GUNLOCK();
3903         errno = EBADF;
3904         return -1;
3905     }
3906
3907     /*
3908      * set up the uio buffer
3909      */
3910     iov[0].iov_base = (char *)buf;
3911     iov[0].iov_len = len;
3912     uio.uio_iov = &iov[0];
3913     uio.uio_iovcnt = 1;
3914     uio.uio_offset = afs_FileOffsets[fd];
3915     uio.uio_segflg = 0;
3916     uio.uio_fmode = FREAD;
3917     uio.uio_resid = len;
3918
3919     /*
3920      * read the next chunk from the directory
3921      */
3922     code = afs_readdir(VTOAFS(vp), &uio, u.u_cred);
3923     if (code != 0) {
3924         errno = code;
3925         return -1;
3926     }
3927
3928     afs_FileOffsets[fd] = uio.uio_offset;
3929     return (len - uio.uio_resid);
3930 }
3931
3932 /*
3933  * read from a directory (names only)
3934  */
3935 struct usr_dirent *
3936 uafs_readdir(usr_DIR * dirp)
3937 {
3938     struct usr_dirent *retval;
3939     AFS_GLOCK();
3940     retval = uafs_readdir_r(dirp);
3941     AFS_GUNLOCK();
3942     return retval;
3943 }
3944
3945 struct usr_dirent *
3946 uafs_readdir_r(usr_DIR * dirp)
3947 {
3948     int code;
3949     int len;
3950     struct usr_uio uio;
3951     struct usr_vnode *vp;
3952     struct iovec iov[1];
3953     struct usr_dirent *direntP;
3954     struct min_direct *directP;
3955
3956     /*
3957      * Make sure this is an open file
3958      */
3959     vp = afs_FileTable[dirp->dd_fd];
3960     if (vp == NULL) {
3961         errno = EBADF;
3962         return NULL;
3963     }
3964
3965     /*
3966      * If there are no entries in the stream buffer
3967      * then read another chunk
3968      */
3969     directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3970     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3971         /*
3972          * set up the uio buffer
3973          */
3974         iov[0].iov_base = dirp->dd_buf;
3975         iov[0].iov_len = USR_DIRSIZE;
3976         uio.uio_iov = &iov[0];
3977         uio.uio_iovcnt = 1;
3978         uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3979         uio.uio_segflg = 0;
3980         uio.uio_fmode = FREAD;
3981         uio.uio_resid = USR_DIRSIZE;
3982
3983         /*
3984          * read the next chunk from the directory
3985          */
3986         code = afs_readdir(VTOAFS(vp), &uio, u.u_cred);
3987         if (code != 0) {
3988             errno = code;
3989             return NULL;
3990         }
3991         afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3992
3993         dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3994         dirp->dd_loc = 0;
3995         directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3996     }
3997
3998     /*
3999      * Check for end of file
4000      */
4001     if (dirp->dd_size == 0 || directP->d_fileno == 0) {
4002         errno = 0;
4003         return NULL;
4004     }
4005     len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
4006     usr_assert(len <= dirp->dd_size);
4007
4008     /*
4009      * Copy the next entry into the usr_dirent structure and advance
4010      */
4011     direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
4012     direntP->d_ino = directP->d_fileno;
4013     direntP->d_off = direntP->d_reclen;
4014     direntP->d_reclen =
4015         sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
4016     memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
4017     direntP->d_name[directP->d_namlen] = '\0';
4018     dirp->dd_loc += len;
4019     dirp->dd_size -= len;
4020
4021     return direntP;
4022 }
4023
4024 /*
4025  * Close a directory
4026  */
4027 int
4028 uafs_closedir(usr_DIR * dirp)
4029 {
4030     int retval;
4031     AFS_GLOCK();
4032     retval = uafs_closedir_r(dirp);
4033     AFS_GUNLOCK();
4034     return retval;
4035 }
4036
4037 int
4038 uafs_closedir_r(usr_DIR * dirp)
4039 {
4040     int fd;
4041     int rc;
4042
4043     fd = dirp->dd_fd;
4044     afs_osi_Free((char *)dirp,
4045                  sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
4046     rc = uafs_close_r(fd);
4047     return rc;
4048 }
4049
4050 /*
4051  * Do AFS authentication
4052  */
4053 int
4054 uafs_klog(char *user, char *cell, char *passwd, char **reason)
4055 {
4056     int code;
4057     afs_int32 password_expires = -1;
4058
4059     usr_mutex_lock(&osi_authenticate_lock);
4060     code =
4061         ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION +
4062                                    KA_USERAUTH_DOSETPAG2, user, NULL, cell,
4063                                    passwd, 0, &password_expires, 0, reason);
4064     usr_mutex_unlock(&osi_authenticate_lock);
4065     return code;
4066 }
4067
4068 int
4069 uafs_klog_r(char *user, char *cell, char *passwd, char **reason)
4070 {
4071     int retval;
4072     AFS_GUNLOCK();
4073     retval = uafs_klog(user, cell, passwd, reason);
4074     AFS_GLOCK();
4075     return retval;
4076 }
4077
4078 /*
4079  * Destroy AFS credentials from the kernel cache
4080  */
4081 int
4082 uafs_unlog(void)
4083 {
4084     int code;
4085
4086     usr_mutex_lock(&osi_authenticate_lock);
4087     code = ktc_ForgetAllTokens();
4088     usr_mutex_unlock(&osi_authenticate_lock);
4089     return code;
4090 }
4091
4092 int
4093 uafs_unlog_r(void)
4094 {
4095     int retval;
4096     AFS_GUNLOCK();
4097     retval = uafs_unlog();
4098     AFS_GLOCK();
4099     return retval;
4100 }
4101
4102 /*
4103  * Strip the AFS mount point from a pathname string. Return
4104  * NULL if the path is a relative pathname or if the path
4105  * doesn't start with the AFS mount point string.
4106  */
4107 char *
4108 uafs_afsPathName(char *path)
4109 {
4110     char *p;
4111     char lastchar;
4112     int i;
4113
4114     if (path[0] != '/')
4115         return NULL;
4116     lastchar = '/';
4117     for (i = 1, p = path + 1; *p != '\0'; p++) {
4118         /* Ignore duplicate slashes */
4119         if (*p == '/' && lastchar == '/')
4120             continue;
4121         /* Is this a subdirectory of the AFS mount point? */
4122         if (afs_mountDir[i] == '\0' && *p == '/') {
4123             /* strip leading slashes */
4124             while (*(++p) == '/');
4125             return p;
4126         }
4127         /* Reject paths that are not within AFS */
4128         if (*p != afs_mountDir[i])
4129             return NULL;
4130         lastchar = *p;
4131         i++;
4132     }
4133     /* Is this the AFS mount point? */
4134     if (afs_mountDir[i] == '\0') {
4135         usr_assert(*p == '\0');
4136         return p;
4137     }
4138     return NULL;
4139 }
4140
4141 #ifdef AFS_WEB_ENHANCEMENTS
4142 /*
4143  * uafs_klog_nopag
4144  * klog but don't allocate a new pag
4145  */
4146 int
4147 uafs_klog_nopag(char *user, char *cell, char *passwd, char **reason)
4148 {
4149     int code;
4150     afs_int32 password_expires = -1;
4151
4152     usr_mutex_lock(&osi_authenticate_lock);
4153     code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
4154                                       /*+KA_USERAUTH_DOSETPAG2 */ , user,
4155                                       NULL, cell, passwd, 0,
4156                                       &password_expires, 0, reason);
4157     usr_mutex_unlock(&osi_authenticate_lock);
4158     return code;
4159 }
4160
4161 /*
4162  * uafs_getcellstatus
4163  * get the cell status
4164  */
4165 int
4166 uafs_getcellstatus(char *cell, afs_int32 * status)
4167 {
4168     int rc;
4169     struct afs_ioctl iob;
4170
4171     iob.in = cell;
4172     iob.in_size = strlen(cell) + 1;
4173     iob.out = 0;
4174     iob.out_size = 0;
4175
4176     rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
4177                       (long)&iob, 0, 0);
4178
4179     if (rc < 0) {
4180         errno = rc;
4181         return -1;
4182     }
4183
4184     *status = (intptr_t)iob.out;
4185     return 0;
4186 }
4187
4188 /*
4189  * uafs_getvolquota
4190  * Get quota of volume associated with path
4191  */
4192 int
4193 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
4194 {
4195     int rc;
4196     struct afs_ioctl iob;
4197     VolumeStatus *status;
4198     char buf[1024];
4199
4200     iob.in = 0;
4201     iob.in_size = 0;
4202     iob.out = buf;
4203     iob.out_size = 1024;
4204
4205     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
4206                       0, 0);
4207
4208     if (rc != 0) {
4209         errno = rc;
4210         return -1;
4211     }
4212
4213     status = (VolumeStatus *) buf;
4214     *BlocksInUse = status->BlocksInUse;
4215     *MaxQuota = status->MaxQuota;
4216     return 0;
4217 }
4218
4219 /*
4220  * uafs_setvolquota
4221  * Set quota of volume associated with path
4222  */
4223 int
4224 uafs_setvolquota(char *path, afs_int32 MaxQuota)
4225 {
4226     int rc;
4227     struct afs_ioctl iob;
4228     VolumeStatus *status;
4229     char buf[1024];
4230
4231     iob.in = buf;
4232     iob.in_size = 1024;
4233     iob.out = 0;
4234     iob.out_size = 0;
4235
4236     memset(buf, 0, sizeof(VolumeStatus));
4237     status = (VolumeStatus *) buf;
4238     status->MaxQuota = MaxQuota;
4239     status->MinQuota = -1;
4240
4241     rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
4242                       0, 0);
4243
4244     if (rc != 0) {
4245         errno = rc;
4246         return -1;
4247     }
4248
4249     return 0;
4250 }
4251
4252 /*
4253  * uafs_statmountpoint
4254  * Determine whether a dir. is a mount point or not
4255  * return 1 if mount point, 0 if not
4256  */
4257 int
4258 uafs_statmountpoint(char *path)
4259 {
4260     int retval;
4261
4262     AFS_GLOCK();
4263     retval = uafs_statmountpoint_r(path);
4264     AFS_GUNLOCK();
4265     return retval;
4266 }
4267
4268 int
4269 uafs_statmountpoint_r(char *path)
4270 {
4271     int code;
4272     struct vnode *vp;
4273     struct vcache *avc;
4274     int r;
4275
4276     code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
4277     if (code != 0) {
4278         errno = code;
4279         return -1;
4280     }
4281
4282     avc = VTOAFS(vp);
4283
4284     r = avc->mvstat;
4285     VN_RELE(vp);
4286     return r;
4287 }
4288
4289 /*
4290  * uafs_getRights
4291  * Get a list of rights for the current user on path.
4292  */
4293 int
4294 uafs_getRights(char *path)
4295 {
4296     int code;
4297     struct vnode *vp;
4298     int afs_rights;
4299
4300     AFS_GLOCK();
4301     code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
4302     if (code != 0) {
4303         errno = code;
4304         AFS_GUNLOCK();
4305         return -1;
4306     }
4307
4308     afs_rights =
4309         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
4310         | PRSFS_LOCK | PRSFS_ADMINISTER;
4311
4312     afs_rights = afs_getRights(VTOAFS(vp), afs_rights, u.u_cred);
4313
4314     AFS_GUNLOCK();
4315     return afs_rights;
4316 }
4317 #endif /* AFS_WEB_ENHANCEMENTS */
4318
4319 #endif /* UKERNEL */