| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: vfs_lookup.c,v 1.172 2011/04/11 02:21:01 dholland Exp $ */ | | 1 | /* $NetBSD: vfs_lookup.c,v 1.173 2011/04/11 02:21:17 dholland Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1982, 1986, 1989, 1993 | | 4 | * Copyright (c) 1982, 1986, 1989, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * (c) UNIX System Laboratories, Inc. | | 6 | * (c) UNIX System Laboratories, Inc. |
7 | * All or some portions of this file are derived from material licensed | | 7 | * All or some portions of this file are derived from material licensed |
8 | * to the University of California by American Telephone and Telegraph | | 8 | * to the University of California by American Telephone and Telegraph |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | | 9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
10 | * the permission of UNIX System Laboratories, Inc. | | 10 | * the permission of UNIX System Laboratories, Inc. |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
| @@ -27,27 +27,27 @@ | | | @@ -27,27 +27,27 @@ |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. | | 34 | * SUCH DAMAGE. |
35 | * | | 35 | * |
36 | * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 | | 36 | * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | #include <sys/cdefs.h> | | 39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.172 2011/04/11 02:21:01 dholland Exp $"); | | 40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.173 2011/04/11 02:21:17 dholland Exp $"); |
41 | | | 41 | |
42 | #include "opt_magiclinks.h" | | 42 | #include "opt_magiclinks.h" |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/kernel.h> | | 46 | #include <sys/kernel.h> |
47 | #include <sys/syslimits.h> | | 47 | #include <sys/syslimits.h> |
48 | #include <sys/time.h> | | 48 | #include <sys/time.h> |
49 | #include <sys/namei.h> | | 49 | #include <sys/namei.h> |
50 | #include <sys/vnode.h> | | 50 | #include <sys/vnode.h> |
51 | #include <sys/mount.h> | | 51 | #include <sys/mount.h> |
52 | #include <sys/errno.h> | | 52 | #include <sys/errno.h> |
53 | #include <sys/filedesc.h> | | 53 | #include <sys/filedesc.h> |
| @@ -307,27 +307,30 @@ pathbuf_copyin(const char *userpath, str | | | @@ -307,27 +307,30 @@ pathbuf_copyin(const char *userpath, str |
307 | if (pb == NULL) { | | 307 | if (pb == NULL) { |
308 | return ENOMEM; | | 308 | return ENOMEM; |
309 | } | | 309 | } |
310 | error = copyinstr(userpath, pb->pb_path, PATH_MAX, NULL); | | 310 | error = copyinstr(userpath, pb->pb_path, PATH_MAX, NULL); |
311 | if (error) { | | 311 | if (error) { |
312 | pathbuf_destroy(pb); | | 312 | pathbuf_destroy(pb); |
313 | return error; | | 313 | return error; |
314 | } | | 314 | } |
315 | *ret = pb; | | 315 | *ret = pb; |
316 | return 0; | | 316 | return 0; |
317 | } | | 317 | } |
318 | | | 318 | |
319 | /* | | 319 | /* |
320 | * XXX should not exist | | 320 | * XXX should not exist: |
| | | 321 | * 1. whether a pointer is kernel or user should be statically checkable |
| | | 322 | * 2. copyin should be handled by the upper part of the syscall layer, |
| | | 323 | * not in here. |
321 | */ | | 324 | */ |
322 | int | | 325 | int |
323 | pathbuf_maybe_copyin(const char *path, enum uio_seg seg, struct pathbuf **ret) | | 326 | pathbuf_maybe_copyin(const char *path, enum uio_seg seg, struct pathbuf **ret) |
324 | { | | 327 | { |
325 | if (seg == UIO_USERSPACE) { | | 328 | if (seg == UIO_USERSPACE) { |
326 | return pathbuf_copyin(path, ret); | | 329 | return pathbuf_copyin(path, ret); |
327 | } else { | | 330 | } else { |
328 | *ret = pathbuf_create(path); | | 331 | *ret = pathbuf_create(path); |
329 | if (*ret == NULL) { | | 332 | if (*ret == NULL) { |
330 | return ENOMEM; | | 333 | return ENOMEM; |
331 | } | | 334 | } |
332 | return 0; | | 335 | return 0; |
333 | } | | 336 | } |
| @@ -366,48 +369,91 @@ pathbuf_stringcopy_put(struct pathbuf *p | | | @@ -366,48 +369,91 @@ pathbuf_stringcopy_put(struct pathbuf *p |
366 | KASSERT(str == pb->pb_pathcopy); | | 369 | KASSERT(str == pb->pb_pathcopy); |
367 | KASSERT(pb->pb_pathcopyuses > 0); | | 370 | KASSERT(pb->pb_pathcopyuses > 0); |
368 | pb->pb_pathcopyuses--; | | 371 | pb->pb_pathcopyuses--; |
369 | if (pb->pb_pathcopyuses == 0) { | | 372 | if (pb->pb_pathcopyuses == 0) { |
370 | PNBUF_PUT(pb->pb_pathcopy); | | 373 | PNBUF_PUT(pb->pb_pathcopy); |
371 | pb->pb_pathcopy = NULL; | | 374 | pb->pb_pathcopy = NULL; |
372 | } | | 375 | } |
373 | } | | 376 | } |
374 | | | 377 | |
375 | | | 378 | |
376 | //////////////////////////////////////////////////////////// | | 379 | //////////////////////////////////////////////////////////// |
377 | | | 380 | |
378 | /* | | 381 | /* |
379 | * Convert a pathname into a pointer to a locked vnode. | | 382 | * namei: convert a pathname into a pointer to a (maybe-locked) vnode, |
| | | 383 | * and maybe also its parent directory vnode, and assorted other guff. |
| | | 384 | * See namei(9) for the interface documentation. |
| | | 385 | * |
380 | * | | 386 | * |
381 | * The FOLLOW flag is set when symbolic links are to be followed | | 387 | * The FOLLOW flag is set when symbolic links are to be followed |
382 | * when they occur at the end of the name translation process. | | 388 | * when they occur at the end of the name translation process. |
383 | * Symbolic links are always followed for all other pathname | | 389 | * Symbolic links are always followed for all other pathname |
384 | * components other than the last. | | 390 | * components other than the last. |
385 | * | | 391 | * |
386 | * The segflg defines whether the name is to be copied from user | | 392 | * The segflg defines whether the name is to be copied from user |
387 | * space or kernel space. | | 393 | * space or kernel space. |
388 | * | | 394 | * |
389 | * Overall outline of namei: | | 395 | * Overall outline of namei: |
390 | * | | 396 | * |
391 | * copy in name | | 397 | * copy in name |
392 | * get starting directory | | 398 | * get starting directory |
393 | * while (!done && !error) { | | 399 | * while (!done && !error) { |
394 | * call lookup to search path. | | 400 | * call lookup to search path. |
395 | * if symbolic link, massage name in buffer and continue | | 401 | * if symbolic link, massage name in buffer and continue |
396 | * } | | 402 | * } |
397 | */ | | 403 | */ |
398 | | | 404 | |
399 | /* | | 405 | /* |
| | | 406 | * Search a pathname. |
| | | 407 | * This is a very central and rather complicated routine. |
| | | 408 | * |
| | | 409 | * The pathname is pointed to by ni_ptr and is of length ni_pathlen. |
| | | 410 | * The starting directory is passed in. The pathname is descended |
| | | 411 | * until done, or a symbolic link is encountered. The variable ni_more |
| | | 412 | * is clear if the path is completed; it is set to one if a symbolic |
| | | 413 | * link needing interpretation is encountered. |
| | | 414 | * |
| | | 415 | * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on |
| | | 416 | * whether the name is to be looked up, created, renamed, or deleted. |
| | | 417 | * When CREATE, RENAME, or DELETE is specified, information usable in |
| | | 418 | * creating, renaming, or deleting a directory entry may be calculated. |
| | | 419 | * If flag has LOCKPARENT or'ed into it, the parent directory is returned |
| | | 420 | * locked. Otherwise the parent directory is not returned. If the target |
| | | 421 | * of the pathname exists and LOCKLEAF is or'ed into the flag the target |
| | | 422 | * is returned locked, otherwise it is returned unlocked. When creating |
| | | 423 | * or renaming and LOCKPARENT is specified, the target may not be ".". |
| | | 424 | * When deleting and LOCKPARENT is specified, the target may be ".". |
| | | 425 | * |
| | | 426 | * Overall outline of lookup: |
| | | 427 | * |
| | | 428 | * dirloop: |
| | | 429 | * identify next component of name at ndp->ni_ptr |
| | | 430 | * handle degenerate case where name is null string |
| | | 431 | * if .. and crossing mount points and on mounted filesys, find parent |
| | | 432 | * call VOP_LOOKUP routine for next component name |
| | | 433 | * directory vnode returned in ni_dvp, locked. |
| | | 434 | * component vnode returned in ni_vp (if it exists), locked. |
| | | 435 | * if result vnode is mounted on and crossing mount points, |
| | | 436 | * find mounted on vnode |
| | | 437 | * if more components of name, do next level at dirloop |
| | | 438 | * return the answer in ni_vp, locked if LOCKLEAF set |
| | | 439 | * if LOCKPARENT set, return locked parent in ni_dvp |
| | | 440 | */ |
| | | 441 | |
| | | 442 | |
| | | 443 | /* |
400 | * Internal state for a namei operation. | | 444 | * Internal state for a namei operation. |
| | | 445 | * |
| | | 446 | * cnp is always equal to &ndp->ni_cnp. |
401 | */ | | 447 | */ |
402 | struct namei_state { | | 448 | struct namei_state { |
403 | struct nameidata *ndp; | | 449 | struct nameidata *ndp; |
404 | struct componentname *cnp; | | 450 | struct componentname *cnp; |
405 | | | 451 | |
406 | int docache; /* == 0 do not cache last component */ | | 452 | int docache; /* == 0 do not cache last component */ |
407 | int rdonly; /* lookup read-only flag bit */ | | 453 | int rdonly; /* lookup read-only flag bit */ |
408 | int slashes; | | 454 | int slashes; |
409 | | | 455 | |
410 | unsigned attempt_retry:1; /* true if error allows emul retry */ | | 456 | unsigned attempt_retry:1; /* true if error allows emul retry */ |
411 | }; | | 457 | }; |
412 | | | 458 | |
413 | | | 459 | |
| @@ -517,27 +563,27 @@ namei_getstartdir(struct namei_state *st | | | @@ -517,27 +563,27 @@ namei_getstartdir(struct namei_state *st |
517 | * XXX: should we hold references to rootdir and erootdir while | | 563 | * XXX: should we hold references to rootdir and erootdir while |
518 | * we're running? What happens if a multithreaded process chroots | | 564 | * we're running? What happens if a multithreaded process chroots |
519 | * during namei? | | 565 | * during namei? |
520 | */ | | 566 | */ |
521 | vref(startdir); | | 567 | vref(startdir); |
522 | | | 568 | |
523 | rw_exit(&cwdi->cwdi_lock); | | 569 | rw_exit(&cwdi->cwdi_lock); |
524 | return startdir; | | 570 | return startdir; |
525 | } | | 571 | } |
526 | | | 572 | |
527 | /* | | 573 | /* |
528 | * Get the directory context for the nfsd case, in parallel to | | 574 | * Get the directory context for the nfsd case, in parallel to |
529 | * getstartdir. Initializes the rootdir and erootdir state and | | 575 | * getstartdir. Initializes the rootdir and erootdir state and |
530 | * returns a reference to the passed-instarting dir. | | 576 | * returns a reference to the passed-in starting dir. |
531 | */ | | 577 | */ |
532 | static struct vnode * | | 578 | static struct vnode * |
533 | namei_getstartdir_for_nfsd(struct namei_state *state, struct vnode *startdir) | | 579 | namei_getstartdir_for_nfsd(struct namei_state *state, struct vnode *startdir) |
534 | { | | 580 | { |
535 | /* always use the real root, and never set an emulation root */ | | 581 | /* always use the real root, and never set an emulation root */ |
536 | state->ndp->ni_rootdir = rootvnode; | | 582 | state->ndp->ni_rootdir = rootvnode; |
537 | state->ndp->ni_erootdir = NULL; | | 583 | state->ndp->ni_erootdir = NULL; |
538 | | | 584 | |
539 | vref(startdir); | | 585 | vref(startdir); |
540 | return startdir; | | 586 | return startdir; |
541 | } | | 587 | } |
542 | | | 588 | |
543 | | | 589 | |
| @@ -603,37 +649,40 @@ namei_start(struct namei_state *state, s | | | @@ -603,37 +649,40 @@ namei_start(struct namei_state *state, s |
603 | /* no ktrace */ | | 649 | /* no ktrace */ |
604 | } else { | | 650 | } else { |
605 | startdir = namei_getstartdir(state); | | 651 | startdir = namei_getstartdir(state); |
606 | namei_ktrace(state); | | 652 | namei_ktrace(state); |
607 | } | | 653 | } |
608 | | | 654 | |
609 | vn_lock(startdir, LK_EXCLUSIVE | LK_RETRY); | | 655 | vn_lock(startdir, LK_EXCLUSIVE | LK_RETRY); |
610 | | | 656 | |
611 | *startdir_ret = startdir; | | 657 | *startdir_ret = startdir; |
612 | return 0; | | 658 | return 0; |
613 | } | | 659 | } |
614 | | | 660 | |
615 | /* | | 661 | /* |
616 | * Check for being at a symlink. | | 662 | * Check for being at a symlink that we're going to follow. |
617 | */ | | 663 | */ |
618 | static inline int | | 664 | static inline int |
619 | namei_atsymlink(struct namei_state *state, struct vnode *foundobj) | | 665 | namei_atsymlink(struct namei_state *state, struct vnode *foundobj) |
620 | { | | 666 | { |
621 | return (foundobj->v_type == VLNK) && | | 667 | return (foundobj->v_type == VLNK) && |
622 | (state->cnp->cn_flags & (FOLLOW|REQUIREDIR)); | | 668 | (state->cnp->cn_flags & (FOLLOW|REQUIREDIR)); |
623 | } | | 669 | } |
624 | | | 670 | |
625 | /* | | 671 | /* |
626 | * Follow a symlink. | | 672 | * Follow a symlink. |
| | | 673 | * |
| | | 674 | * Updates searchdir. inhibitmagic causes magic symlinks to not be |
| | | 675 | * interpreted; this is used by nfsd. |
627 | */ | | 676 | */ |
628 | static inline int | | 677 | static inline int |
629 | namei_follow(struct namei_state *state, int inhibitmagic, | | 678 | namei_follow(struct namei_state *state, int inhibitmagic, |
630 | struct vnode *searchdir, struct vnode *foundobj, | | 679 | struct vnode *searchdir, struct vnode *foundobj, |
631 | struct vnode **newsearchdir_ret) | | 680 | struct vnode **newsearchdir_ret) |
632 | { | | 681 | { |
633 | struct nameidata *ndp = state->ndp; | | 682 | struct nameidata *ndp = state->ndp; |
634 | struct componentname *cnp = state->cnp; | | 683 | struct componentname *cnp = state->cnp; |
635 | | | 684 | |
636 | struct lwp *self = curlwp; /* thread doing namei() */ | | 685 | struct lwp *self = curlwp; /* thread doing namei() */ |
637 | struct iovec aiov; /* uio for reading symbolic links */ | | 686 | struct iovec aiov; /* uio for reading symbolic links */ |
638 | struct uio auio; | | 687 | struct uio auio; |
639 | char *cp; /* pointer into pathname argument */ | | 688 | char *cp; /* pointer into pathname argument */ |
| @@ -711,62 +760,28 @@ namei_follow(struct namei_state *state, | | | @@ -711,62 +760,28 @@ namei_follow(struct namei_state *state, |
711 | searchdir = ndp->ni_rootdir; | | 760 | searchdir = ndp->ni_rootdir; |
712 | } | | 761 | } |
713 | vref(searchdir); | | 762 | vref(searchdir); |
714 | vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY); | | 763 | vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY); |
715 | } | | 764 | } |
716 | | | 765 | |
717 | *newsearchdir_ret = searchdir; | | 766 | *newsearchdir_ret = searchdir; |
718 | return 0; | | 767 | return 0; |
719 | } | | 768 | } |
720 | | | 769 | |
721 | ////////////////////////////// | | 770 | ////////////////////////////// |
722 | | | 771 | |
723 | /* | | 772 | /* |
724 | * Search a pathname. | | 773 | * Inspect the leading path component and update the state accordingly. |
725 | * This is a very central and rather complicated routine. | | | |
726 | * | | | |
727 | * The pathname is pointed to by ni_ptr and is of length ni_pathlen. | | | |
728 | * The starting directory is passed in. The pathname is descended | | | |
729 | * until done, or a symbolic link is encountered. The variable ni_more | | | |
730 | * is clear if the path is completed; it is set to one if a symbolic | | | |
731 | * link needing interpretation is encountered. | | | |
732 | * | | | |
733 | * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on | | | |
734 | * whether the name is to be looked up, created, renamed, or deleted. | | | |
735 | * When CREATE, RENAME, or DELETE is specified, information usable in | | | |
736 | * creating, renaming, or deleting a directory entry may be calculated. | | | |
737 | * If flag has LOCKPARENT or'ed into it, the parent directory is returned | | | |
738 | * locked. Otherwise the parent directory is not returned. If the target | | | |
739 | * of the pathname exists and LOCKLEAF is or'ed into the flag the target | | | |
740 | * is returned locked, otherwise it is returned unlocked. When creating | | | |
741 | * or renaming and LOCKPARENT is specified, the target may not be ".". | | | |
742 | * When deleting and LOCKPARENT is specified, the target may be ".". | | | |
743 | * | | | |
744 | * Overall outline of lookup: | | | |
745 | * | | | |
746 | * dirloop: | | | |
747 | * identify next component of name at ndp->ni_ptr | | | |
748 | * handle degenerate case where name is null string | | | |
749 | * if .. and crossing mount points and on mounted filesys, find parent | | | |
750 | * call VOP_LOOKUP routine for next component name | | | |
751 | * directory vnode returned in ni_dvp, locked. | | | |
752 | * component vnode returned in ni_vp (if it exists), locked. | | | |
753 | * if result vnode is mounted on and crossing mount points, | | | |
754 | * find mounted on vnode | | | |
755 | * if more components of name, do next level at dirloop | | | |
756 | * return the answer in ni_vp, locked if LOCKLEAF set | | | |
757 | * if LOCKPARENT set, return locked parent in ni_dvp | | | |
758 | */ | | 774 | */ |
759 | | | | |
760 | static int | | 775 | static int |
761 | lookup_parsepath(struct namei_state *state) | | 776 | lookup_parsepath(struct namei_state *state) |
762 | { | | 777 | { |
763 | const char *cp; /* pointer into pathname argument */ | | 778 | const char *cp; /* pointer into pathname argument */ |
764 | | | 779 | |
765 | struct componentname *cnp = state->cnp; | | 780 | struct componentname *cnp = state->cnp; |
766 | struct nameidata *ndp = state->ndp; | | 781 | struct nameidata *ndp = state->ndp; |
767 | | | 782 | |
768 | KASSERT(cnp == &ndp->ni_cnd); | | 783 | KASSERT(cnp == &ndp->ni_cnd); |
769 | | | 784 | |
770 | /* | | 785 | /* |
771 | * Search a new directory. | | 786 | * Search a new directory. |
772 | * | | 787 | * |
| @@ -824,26 +839,31 @@ lookup_parsepath(struct namei_state *sta | | | @@ -824,26 +839,31 @@ lookup_parsepath(struct namei_state *sta |
824 | } else { | | 839 | } else { |
825 | cnp->cn_flags |= MAKEENTRY; | | 840 | cnp->cn_flags |= MAKEENTRY; |
826 | cnp->cn_flags &= ~ISLASTCN; | | 841 | cnp->cn_flags &= ~ISLASTCN; |
827 | } | | 842 | } |
828 | if (cnp->cn_namelen == 2 && | | 843 | if (cnp->cn_namelen == 2 && |
829 | cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') | | 844 | cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') |
830 | cnp->cn_flags |= ISDOTDOT; | | 845 | cnp->cn_flags |= ISDOTDOT; |
831 | else | | 846 | else |
832 | cnp->cn_flags &= ~ISDOTDOT; | | 847 | cnp->cn_flags &= ~ISDOTDOT; |
833 | | | 848 | |
834 | return 0; | | 849 | return 0; |
835 | } | | 850 | } |
836 | | | 851 | |
| | | 852 | /* |
| | | 853 | * Call VOP_LOOKUP for a single lookup; return a new search directory |
| | | 854 | * (used when crossing mountpoints up or searching union mounts down) and |
| | | 855 | * the found object, which for create operations may be NULL on success. |
| | | 856 | */ |
837 | static int | | 857 | static int |
838 | lookup_once(struct namei_state *state, | | 858 | lookup_once(struct namei_state *state, |
839 | struct vnode *searchdir, | | 859 | struct vnode *searchdir, |
840 | struct vnode **newsearchdir_ret, | | 860 | struct vnode **newsearchdir_ret, |
841 | struct vnode **foundobj_ret) | | 861 | struct vnode **foundobj_ret) |
842 | { | | 862 | { |
843 | struct vnode *tmpvn; /* scratch vnode */ | | 863 | struct vnode *tmpvn; /* scratch vnode */ |
844 | struct vnode *foundobj; /* result */ | | 864 | struct vnode *foundobj; /* result */ |
845 | struct mount *mp; /* mount table entry */ | | 865 | struct mount *mp; /* mount table entry */ |
846 | struct lwp *l = curlwp; | | 866 | struct lwp *l = curlwp; |
847 | int error; | | 867 | int error; |
848 | | | 868 | |
849 | struct componentname *cnp = state->cnp; | | 869 | struct componentname *cnp = state->cnp; |
| @@ -955,28 +975,28 @@ unionlookup: | | | @@ -955,28 +975,28 @@ unionlookup: |
955 | } | | 975 | } |
956 | | | 976 | |
957 | /* | | 977 | /* |
958 | * If creating and at end of pathname, then can consider | | 978 | * If creating and at end of pathname, then can consider |
959 | * allowing file to be created. | | 979 | * allowing file to be created. |
960 | */ | | 980 | */ |
961 | if (state->rdonly) { | | 981 | if (state->rdonly) { |
962 | return EROFS; | | 982 | return EROFS; |
963 | } | | 983 | } |
964 | | | 984 | |
965 | /* | | 985 | /* |
966 | * We return success and a NULL foundobj to indicate | | 986 | * We return success and a NULL foundobj to indicate |
967 | * that the entry doesn't currently exist, leaving a | | 987 | * that the entry doesn't currently exist, leaving a |
968 | * pointer to the (possibly locked) directory vnode as | | 988 | * pointer to the (normally, locked) directory vnode |
969 | * searchdir. | | 989 | * as searchdir. |
970 | */ | | 990 | */ |
971 | *foundobj_ret = NULL; | | 991 | *foundobj_ret = NULL; |
972 | return (0); | | 992 | return (0); |
973 | } | | 993 | } |
974 | #ifdef NAMEI_DIAGNOSTIC | | 994 | #ifdef NAMEI_DIAGNOSTIC |
975 | printf("found\n"); | | 995 | printf("found\n"); |
976 | #endif /* NAMEI_DIAGNOSTIC */ | | 996 | #endif /* NAMEI_DIAGNOSTIC */ |
977 | | | 997 | |
978 | /* | | 998 | /* |
979 | * Take into account any additional components consumed by the | | 999 | * Take into account any additional components consumed by the |
980 | * underlying filesystem. This will include any trailing slashes after | | 1000 | * underlying filesystem. This will include any trailing slashes after |
981 | * the last component consumed. | | 1001 | * the last component consumed. |
982 | */ | | 1002 | */ |
| @@ -1015,26 +1035,30 @@ unionlookup: | | | @@ -1015,26 +1035,30 @@ unionlookup: |
1015 | return error; | | 1035 | return error; |
1016 | } | | 1036 | } |
1017 | VOP_UNLOCK(foundobj); | | 1037 | VOP_UNLOCK(foundobj); |
1018 | vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY); | | 1038 | vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY); |
1019 | vn_lock(foundobj, LK_EXCLUSIVE | LK_RETRY); | | 1039 | vn_lock(foundobj, LK_EXCLUSIVE | LK_RETRY); |
1020 | } | | 1040 | } |
1021 | | | 1041 | |
1022 | *foundobj_ret = foundobj; | | 1042 | *foundobj_ret = foundobj; |
1023 | return 0; | | 1043 | return 0; |
1024 | } | | 1044 | } |
1025 | | | 1045 | |
1026 | ////////////////////////////// | | 1046 | ////////////////////////////// |
1027 | | | 1047 | |
| | | 1048 | /* |
| | | 1049 | * Do a complete path search from a single root directory. |
| | | 1050 | * (This is called up to twice if TRYEMULROOT is in effect.) |
| | | 1051 | */ |
1028 | static int | | 1052 | static int |
1029 | namei_oneroot(struct namei_state *state, struct vnode *forcecwd, | | 1053 | namei_oneroot(struct namei_state *state, struct vnode *forcecwd, |
1030 | int neverfollow, int inhibitmagic) | | 1054 | int neverfollow, int inhibitmagic) |
1031 | { | | 1055 | { |
1032 | struct nameidata *ndp = state->ndp; | | 1056 | struct nameidata *ndp = state->ndp; |
1033 | struct componentname *cnp = state->cnp; | | 1057 | struct componentname *cnp = state->cnp; |
1034 | struct vnode *searchdir, *foundobj; | | 1058 | struct vnode *searchdir, *foundobj; |
1035 | const char *cp; | | 1059 | const char *cp; |
1036 | int error; | | 1060 | int error; |
1037 | | | 1061 | |
1038 | error = namei_start(state, forcecwd, &searchdir); | | 1062 | error = namei_start(state, forcecwd, &searchdir); |
1039 | if (error) { | | 1063 | if (error) { |
1040 | ndp->ni_dvp = NULL; | | 1064 | ndp->ni_dvp = NULL; |
| @@ -1320,26 +1344,29 @@ namei_oneroot(struct namei_state *state, | | | @@ -1320,26 +1344,29 @@ namei_oneroot(struct namei_state *state, |
1320 | if (searchdir == foundobj) { | | 1344 | if (searchdir == foundobj) { |
1321 | vrele(searchdir); | | 1345 | vrele(searchdir); |
1322 | } else { | | 1346 | } else { |
1323 | vput(searchdir); | | 1347 | vput(searchdir); |
1324 | } | | 1348 | } |
1325 | searchdir = NULL; | | 1349 | searchdir = NULL; |
1326 | } | | 1350 | } |
1327 | | | 1351 | |
1328 | ndp->ni_dvp = searchdir; | | 1352 | ndp->ni_dvp = searchdir; |
1329 | ndp->ni_vp = foundobj; | | 1353 | ndp->ni_vp = foundobj; |
1330 | return 0; | | 1354 | return 0; |
1331 | } | | 1355 | } |
1332 | | | 1356 | |
| | | 1357 | /* |
| | | 1358 | * Do namei; wrapper layer that handles TRYEMULROOT. |
| | | 1359 | */ |
1333 | static int | | 1360 | static int |
1334 | namei_tryemulroot(struct namei_state *state, struct vnode *forcecwd, | | 1361 | namei_tryemulroot(struct namei_state *state, struct vnode *forcecwd, |
1335 | int neverfollow, int inhibitmagic) | | 1362 | int neverfollow, int inhibitmagic) |
1336 | { | | 1363 | { |
1337 | int error; | | 1364 | int error; |
1338 | | | 1365 | |
1339 | struct nameidata *ndp = state->ndp; | | 1366 | struct nameidata *ndp = state->ndp; |
1340 | struct componentname *cnp = state->cnp; | | 1367 | struct componentname *cnp = state->cnp; |
1341 | const char *savepath = NULL; | | 1368 | const char *savepath = NULL; |
1342 | | | 1369 | |
1343 | KASSERT(cnp == &ndp->ni_cnd); | | 1370 | KASSERT(cnp == &ndp->ni_cnd); |
1344 | | | 1371 | |
1345 | if (cnp->cn_flags & TRYEMULROOT) { | | 1372 | if (cnp->cn_flags & TRYEMULROOT) { |
| @@ -1365,82 +1392,98 @@ namei_tryemulroot(struct namei_state *st | | | @@ -1365,82 +1392,98 @@ namei_tryemulroot(struct namei_state *st |
1365 | strcpy(ndp->ni_pathbuf->pb_path, savepath); | | 1392 | strcpy(ndp->ni_pathbuf->pb_path, savepath); |
1366 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | 1393 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); |
1367 | savepath = NULL; | | 1394 | savepath = NULL; |
1368 | | | 1395 | |
1369 | goto emul_retry; | | 1396 | goto emul_retry; |
1370 | } | | 1397 | } |
1371 | } | | 1398 | } |
1372 | if (savepath != NULL) { | | 1399 | if (savepath != NULL) { |
1373 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | 1400 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); |
1374 | } | | 1401 | } |
1375 | return error; | | 1402 | return error; |
1376 | } | | 1403 | } |
1377 | | | 1404 | |
| | | 1405 | /* |
| | | 1406 | * External interface. |
| | | 1407 | */ |
1378 | int | | 1408 | int |
1379 | namei(struct nameidata *ndp) | | 1409 | namei(struct nameidata *ndp) |
1380 | { | | 1410 | { |
1381 | struct namei_state state; | | 1411 | struct namei_state state; |
1382 | int error; | | 1412 | int error; |
1383 | | | 1413 | |
1384 | namei_init(&state, ndp); | | 1414 | namei_init(&state, ndp); |
1385 | error = namei_tryemulroot(&state, NULL, | | 1415 | error = namei_tryemulroot(&state, NULL, |
1386 | 0/*!neverfollow*/, 0/*!inhibitmagic*/); | | 1416 | 0/*!neverfollow*/, 0/*!inhibitmagic*/); |
1387 | namei_cleanup(&state); | | 1417 | namei_cleanup(&state); |
1388 | | | 1418 | |
1389 | if (error) { | | 1419 | if (error) { |
1390 | /* make sure no stray refs leak out */ | | 1420 | /* make sure no stray refs leak out */ |
1391 | KASSERT(ndp->ni_dvp == NULL); | | 1421 | KASSERT(ndp->ni_dvp == NULL); |
1392 | KASSERT(ndp->ni_vp == NULL); | | 1422 | KASSERT(ndp->ni_vp == NULL); |
1393 | } | | 1423 | } |
1394 | | | 1424 | |
1395 | return error; | | 1425 | return error; |
1396 | } | | 1426 | } |
1397 | | | 1427 | |
1398 | //////////////////////////////////////////////////////////// | | 1428 | //////////////////////////////////////////////////////////// |
1399 | | | 1429 | |
1400 | /* | | 1430 | /* |
1401 | * Externally visible interfaces used by nfsd (bletch, yuk, XXX) | | 1431 | * External interface used by nfsd. This is basically different from |
| | | 1432 | * namei only in that it has the ability to pass in the "current |
| | | 1433 | * directory", and uses an extra flag "neverfollow" for which there's |
| | | 1434 | * no physical flag defined in namei.h. (There used to be a cut&paste |
| | | 1435 | * copy of about half of namei in nfsd to allow these minor |
| | | 1436 | * adjustments to exist.) |
1402 | * | | 1437 | * |
1403 | * The "index" version differs from the "main" version in that it's | | 1438 | * XXX: the namei interface should be adjusted so nfsd can just use |
1404 | * called from a different place in a different context. For now I | | 1439 | * ordinary namei(). |
1405 | * want to be able to shuffle code in from one call site without | | | |
1406 | * affecting the other. | | | |
1407 | * | | | |
1408 | * It turns out that the "main" version was a cut and pasted copy of | | | |
1409 | * namei with a few changes; the "index" version on the other hand | | | |
1410 | * always takes a single component and is an elaborate form of calling | | | |
1411 | * VOP_LOOKUP once. | | | |
1412 | */ | | 1440 | */ |
1413 | | | | |
1414 | int | | 1441 | int |
1415 | lookup_for_nfsd(struct nameidata *ndp, struct vnode *forcecwd, int neverfollow) | | 1442 | lookup_for_nfsd(struct nameidata *ndp, struct vnode *forcecwd, int neverfollow) |
1416 | { | | 1443 | { |
1417 | struct namei_state state; | | 1444 | struct namei_state state; |
1418 | int error; | | 1445 | int error; |
1419 | | | 1446 | |
1420 | namei_init(&state, ndp); | | 1447 | namei_init(&state, ndp); |
1421 | error = namei_tryemulroot(&state, forcecwd, | | 1448 | error = namei_tryemulroot(&state, forcecwd, |
1422 | neverfollow, 1/*inhibitmagic*/); | | 1449 | neverfollow, 1/*inhibitmagic*/); |
1423 | namei_cleanup(&state); | | 1450 | namei_cleanup(&state); |
1424 | | | 1451 | |
1425 | if (error) { | | 1452 | if (error) { |
1426 | /* make sure no stray refs leak out */ | | 1453 | /* make sure no stray refs leak out */ |
1427 | KASSERT(ndp->ni_dvp == NULL); | | 1454 | KASSERT(ndp->ni_dvp == NULL); |
1428 | KASSERT(ndp->ni_vp == NULL); | | 1455 | KASSERT(ndp->ni_vp == NULL); |
1429 | } | | 1456 | } |
1430 | | | 1457 | |
1431 | return error; | | 1458 | return error; |
1432 | } | | 1459 | } |
1433 | | | 1460 | |
| | | 1461 | /* |
| | | 1462 | * A second external interface used by nfsd. This turns out to be a |
| | | 1463 | * single lookup used by the WebNFS code (ha!) to get "index.html" or |
| | | 1464 | * equivalent when asked for a directory. It should eventually evolve |
| | | 1465 | * into some kind of namei_once() call; for the time being it's kind |
| | | 1466 | * of a mess. XXX. |
| | | 1467 | * |
| | | 1468 | * dholland 20110109: I don't think it works, and I don't think it |
| | | 1469 | * worked before I started hacking and slashing either, and I doubt |
| | | 1470 | * anyone will ever notice. |
| | | 1471 | */ |
| | | 1472 | |
| | | 1473 | /* |
| | | 1474 | * Internals. This calls lookup_once() after setting up the assorted |
| | | 1475 | * pieces of state the way they ought to be. |
| | | 1476 | */ |
1434 | static int | | 1477 | static int |
1435 | do_lookup_for_nfsd_index(struct namei_state *state, struct vnode *startdir) | | 1478 | do_lookup_for_nfsd_index(struct namei_state *state, struct vnode *startdir) |
1436 | { | | 1479 | { |
1437 | int error = 0; | | 1480 | int error = 0; |
1438 | | | 1481 | |
1439 | struct componentname *cnp = state->cnp; | | 1482 | struct componentname *cnp = state->cnp; |
1440 | struct nameidata *ndp = state->ndp; | | 1483 | struct nameidata *ndp = state->ndp; |
1441 | struct vnode *foundobj; | | 1484 | struct vnode *foundobj; |
1442 | const char *cp; /* pointer into pathname argument */ | | 1485 | const char *cp; /* pointer into pathname argument */ |
1443 | | | 1486 | |
1444 | KASSERT(cnp == &ndp->ni_cnd); | | 1487 | KASSERT(cnp == &ndp->ni_cnd); |
1445 | | | 1488 | |
1446 | cnp->cn_nameptr = ndp->ni_pnbuf; | | 1489 | cnp->cn_nameptr = ndp->ni_pnbuf; |
| @@ -1484,26 +1527,32 @@ do_lookup_for_nfsd_index(struct namei_st | | | @@ -1484,26 +1527,32 @@ do_lookup_for_nfsd_index(struct namei_st |
1484 | } | | 1527 | } |
1485 | | | 1528 | |
1486 | KASSERT((cnp->cn_flags & LOCKPARENT) == 0); | | 1529 | KASSERT((cnp->cn_flags & LOCKPARENT) == 0); |
1487 | if ((cnp->cn_flags & LOCKLEAF) == 0) { | | 1530 | if ((cnp->cn_flags & LOCKLEAF) == 0) { |
1488 | VOP_UNLOCK(foundobj); | | 1531 | VOP_UNLOCK(foundobj); |
1489 | } | | 1532 | } |
1490 | return (0); | | 1533 | return (0); |
1491 | | | 1534 | |
1492 | bad: | | 1535 | bad: |
1493 | ndp->ni_vp = NULL; | | 1536 | ndp->ni_vp = NULL; |
1494 | return (error); | | 1537 | return (error); |
1495 | } | | 1538 | } |
1496 | | | 1539 | |
| | | 1540 | /* |
| | | 1541 | * External interface. The partitioning between this function and the |
| | | 1542 | * above isn't very clear - the above function exists mostly so code |
| | | 1543 | * that uses "state->" can be shuffled around without having to change |
| | | 1544 | * it to "state.". |
| | | 1545 | */ |
1497 | int | | 1546 | int |
1498 | lookup_for_nfsd_index(struct nameidata *ndp, struct vnode *startdir) | | 1547 | lookup_for_nfsd_index(struct nameidata *ndp, struct vnode *startdir) |
1499 | { | | 1548 | { |
1500 | struct namei_state state; | | 1549 | struct namei_state state; |
1501 | int error; | | 1550 | int error; |
1502 | | | 1551 | |
1503 | /* | | 1552 | /* |
1504 | * Note: the name sent in here (is not|should not be) allowed | | 1553 | * Note: the name sent in here (is not|should not be) allowed |
1505 | * to contain a slash. | | 1554 | * to contain a slash. |
1506 | */ | | 1555 | */ |
1507 | if (strlen(ndp->ni_pathbuf->pb_path) > NAME_MAX) { | | 1556 | if (strlen(ndp->ni_pathbuf->pb_path) > NAME_MAX) { |
1508 | return ENAMETOOLONG; | | 1557 | return ENAMETOOLONG; |
1509 | } | | 1558 | } |