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