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