vfs_lookup.c revision 78692
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 51541Srgrimes * All or some portions of this file are derived from material licensed 61541Srgrimes * to the University of California by American Telephone and Telegraph 71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81541Srgrimes * the permission of UNIX System Laboratories, Inc. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 3. All advertising materials mentioning features or use of this software 191541Srgrimes * must display the following acknowledgement: 201541Srgrimes * This product includes software developed by the University of 211541Srgrimes * California, Berkeley and its contributors. 221541Srgrimes * 4. Neither the name of the University nor the names of its contributors 231541Srgrimes * may be used to endorse or promote products derived from this software 241541Srgrimes * without specific prior written permission. 251541Srgrimes * 261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361541Srgrimes * SUCH DAMAGE. 371541Srgrimes * 381541Srgrimes * @(#)vfs_lookup.c 8.4 (Berkeley) 2/16/94 3950477Speter * $FreeBSD: head/sys/kern/vfs_lookup.c 78692 2001-06-24 05:24:41Z dillon $ 401541Srgrimes */ 411541Srgrimes 4213203Swollman#include "opt_ktrace.h" 4313203Swollman 441541Srgrimes#include <sys/param.h> 452112Swollman#include <sys/systm.h> 4669664Speter#include <sys/kernel.h> 4776166Smarkm#include <sys/lock.h> 481541Srgrimes#include <sys/namei.h> 491541Srgrimes#include <sys/vnode.h> 501541Srgrimes#include <sys/mount.h> 511541Srgrimes#include <sys/filedesc.h> 521541Srgrimes#include <sys/proc.h> 531541Srgrimes#ifdef KTRACE 541541Srgrimes#include <sys/ktrace.h> 551541Srgrimes#endif 561541Srgrimes 5732011Sbde#include <vm/vm_zone.h> 5832011Sbde 591541Srgrimes/* 6069664Speter * Allocation zone for namei 6169664Speter */ 6269664Speterstruct vm_zone *namei_zone; 6369664Speter 6469664Speterstatic void 6569664Speternameiinit(void *dummy __unused) 6669664Speter{ 6769664Speter 6869664Speter namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2); 6969664Speter} 7069664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 7169664Speter 7269664Speter/* 731541Srgrimes * Convert a pathname into a pointer to a locked inode. 741541Srgrimes * 751541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 761541Srgrimes * when they occur at the end of the name translation process. 771541Srgrimes * Symbolic links are always followed for all other pathname 781541Srgrimes * components other than the last. 791541Srgrimes * 801541Srgrimes * The segflg defines whether the name is to be copied from user 811541Srgrimes * space or kernel space. 821541Srgrimes * 831541Srgrimes * Overall outline of namei: 841541Srgrimes * 851541Srgrimes * copy in name 861541Srgrimes * get starting directory 871541Srgrimes * while (!done && !error) { 881541Srgrimes * call lookup to search path. 891541Srgrimes * if symbolic link, massage name in buffer and continue 901541Srgrimes * } 911541Srgrimes */ 921541Srgrimesint 931541Srgrimesnamei(ndp) 941541Srgrimes register struct nameidata *ndp; 951541Srgrimes{ 961541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 971541Srgrimes register char *cp; /* pointer into pathname argument */ 981541Srgrimes register struct vnode *dp; /* the directory we are searching */ 991541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1001541Srgrimes struct uio auio; 1011541Srgrimes int error, linklen; 1021541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 10322521Sdyson struct proc *p = cnp->cn_proc; 1041541Srgrimes 1051541Srgrimes ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 10642408Seivind KASSERT(cnp->cn_cred && cnp->cn_proc, ("namei: bad cred/proc")); 10742408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 10842453Seivind ("namei: nameiop contaminated with flags")); 10942408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 11042453Seivind ("namei: flags contaminated with nameiops")); 1111541Srgrimes fdp = cnp->cn_proc->p_fd; 1121541Srgrimes 1131541Srgrimes /* 1141541Srgrimes * Get a buffer for the name to be translated, and copy the 1151541Srgrimes * name into the buffer. 1161541Srgrimes */ 1171541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 11829653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 1191541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1201541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 12136735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1221541Srgrimes else 1231541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 12436735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 12520069Sbde 12620069Sbde /* 12720069Sbde * Don't allow empty pathnames. 12820069Sbde */ 12920069Sbde if (!error && *cnp->cn_pnbuf == '\0') 13020069Sbde error = ENOENT; 13120069Sbde 1321541Srgrimes if (error) { 13329653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 1341541Srgrimes ndp->ni_vp = NULL; 1351541Srgrimes return (error); 1361541Srgrimes } 1371541Srgrimes ndp->ni_loopcnt = 0; 1381541Srgrimes#ifdef KTRACE 1391541Srgrimes if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 1401541Srgrimes ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 1411541Srgrimes#endif 1421541Srgrimes 1431541Srgrimes /* 1441541Srgrimes * Get starting point for the translation. 1451541Srgrimes */ 14633360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 14751649Sphk ndp->ni_topdir = fdp->fd_jdir; 14833360Sdyson 1491541Srgrimes dp = fdp->fd_cdir; 1501541Srgrimes VREF(dp); 1511541Srgrimes for (;;) { 1521541Srgrimes /* 1531541Srgrimes * Check if root directory should replace current directory. 1541541Srgrimes * Done at start of translation and after symbolic link. 1551541Srgrimes */ 1561541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1571541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1581541Srgrimes vrele(dp); 1591541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1601541Srgrimes cnp->cn_nameptr++; 1611541Srgrimes ndp->ni_pathlen--; 1621541Srgrimes } 1631541Srgrimes dp = ndp->ni_rootdir; 1641541Srgrimes VREF(dp); 1651541Srgrimes } 1661541Srgrimes ndp->ni_startdir = dp; 1673148Sphk error = lookup(ndp); 1683148Sphk if (error) { 16929653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 1701541Srgrimes return (error); 1711541Srgrimes } 1721541Srgrimes /* 1731541Srgrimes * Check for symbolic link 1741541Srgrimes */ 1751541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 1761541Srgrimes if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 17729653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 1781541Srgrimes else 1791541Srgrimes cnp->cn_flags |= HASBUF; 18032286Sdyson 18149101Salc if (vn_canvmio(ndp->ni_vp) == TRUE && 18232286Sdyson (cnp->cn_nameiop != DELETE) && 18342315Seivind ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == 18442315Seivind LOCKLEAF)) 18532286Sdyson vfs_object_create(ndp->ni_vp, 18642315Seivind ndp->ni_cnd.cn_proc, 18742315Seivind ndp->ni_cnd.cn_cred); 18832286Sdyson 1891541Srgrimes return (0); 1901541Srgrimes } 1911541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 19222521Sdyson VOP_UNLOCK(ndp->ni_dvp, 0, p); 1931541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1941541Srgrimes error = ELOOP; 1951541Srgrimes break; 1961541Srgrimes } 1971541Srgrimes if (ndp->ni_pathlen > 1) 19829653Sdyson cp = zalloc(namei_zone); 1991541Srgrimes else 2001541Srgrimes cp = cnp->cn_pnbuf; 2011541Srgrimes aiov.iov_base = cp; 2021541Srgrimes aiov.iov_len = MAXPATHLEN; 2031541Srgrimes auio.uio_iov = &aiov; 2041541Srgrimes auio.uio_iovcnt = 1; 2051541Srgrimes auio.uio_offset = 0; 2061541Srgrimes auio.uio_rw = UIO_READ; 2071541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 2081541Srgrimes auio.uio_procp = (struct proc *)0; 2091541Srgrimes auio.uio_resid = MAXPATHLEN; 2103148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2113148Sphk if (error) { 2121541Srgrimes if (ndp->ni_pathlen > 1) 21329653Sdyson zfree(namei_zone, cp); 2141541Srgrimes break; 2151541Srgrimes } 2161541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 21778692Sdillon if (linklen == 0) { 21878692Sdillon if (ndp->ni_pathlen > 1) 21978692Sdillon zfree(namei_zone, cp); 22078692Sdillon error = ENOENT; 22178692Sdillon break; 22278692Sdillon } 2231541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2241541Srgrimes if (ndp->ni_pathlen > 1) 22529653Sdyson zfree(namei_zone, cp); 2261541Srgrimes error = ENAMETOOLONG; 2271541Srgrimes break; 2281541Srgrimes } 2291541Srgrimes if (ndp->ni_pathlen > 1) { 2301541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 23129653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 2321541Srgrimes cnp->cn_pnbuf = cp; 2331541Srgrimes } else 2341541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2351541Srgrimes ndp->ni_pathlen += linklen; 2361541Srgrimes vput(ndp->ni_vp); 2371541Srgrimes dp = ndp->ni_dvp; 2381541Srgrimes } 23929653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 2401541Srgrimes vrele(ndp->ni_dvp); 2411541Srgrimes vput(ndp->ni_vp); 2421541Srgrimes ndp->ni_vp = NULL; 2431541Srgrimes return (error); 2441541Srgrimes} 2451541Srgrimes 2461541Srgrimes/* 2471541Srgrimes * Search a pathname. 2481541Srgrimes * This is a very central and rather complicated routine. 2491541Srgrimes * 2501541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2511541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2521541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2531541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2541541Srgrimes * symbolic link needing interpretation is encountered. 2551541Srgrimes * 2561541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 2571541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 2581541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 2591541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 2601541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 2611541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 2621541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 2631541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 2641541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 2651541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 2661541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 2678876Srgrimes * 2681541Srgrimes * Overall outline of lookup: 2691541Srgrimes * 2701541Srgrimes * dirloop: 2711541Srgrimes * identify next component of name at ndp->ni_ptr 2721541Srgrimes * handle degenerate case where name is null string 2731541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 2741541Srgrimes * call VOP_LOOKUP routine for next component name 2751541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 2761541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 2771541Srgrimes * if result vnode is mounted on and crossing mount points, 2781541Srgrimes * find mounted on vnode 2791541Srgrimes * if more components of name, do next level at dirloop 2801541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 2811541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 2821541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 2831541Srgrimes */ 2841541Srgrimesint 2851541Srgrimeslookup(ndp) 2861541Srgrimes register struct nameidata *ndp; 2871541Srgrimes{ 2881541Srgrimes register char *cp; /* pointer into pathname argument */ 2891541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 2901541Srgrimes struct vnode *tdp; /* saved dp */ 2911541Srgrimes struct mount *mp; /* mount table entry */ 2921541Srgrimes int docache; /* == 0 do not cache last component */ 2931541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 2941541Srgrimes int rdonly; /* lookup read-only flag bit */ 2959804Sbde int trailing_slash; 2961541Srgrimes int error = 0; 29765805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 2981541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 29922521Sdyson struct proc *p = cnp->cn_proc; 3001541Srgrimes 3011541Srgrimes /* 3021541Srgrimes * Setup: break out flag bits into variables. 3031541Srgrimes */ 3041541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 3051541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3061541Srgrimes if (cnp->cn_nameiop == DELETE || 30722874Sbde (wantparent && cnp->cn_nameiop != CREATE && 30822874Sbde cnp->cn_nameiop != LOOKUP)) 3091541Srgrimes docache = 0; 3101541Srgrimes rdonly = cnp->cn_flags & RDONLY; 3111541Srgrimes ndp->ni_dvp = NULL; 3121541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 3131541Srgrimes dp = ndp->ni_startdir; 3141541Srgrimes ndp->ni_startdir = NULLVP; 31522521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 3161541Srgrimes 3171541Srgrimesdirloop: 3181541Srgrimes /* 3191541Srgrimes * Search a new directory. 3201541Srgrimes * 3211541Srgrimes * The last component of the filename is left accessible via 3221541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3231541Srgrimes * the name set the SAVENAME flag. When done, they assume 3241541Srgrimes * responsibility for freeing the pathname buffer. 3251541Srgrimes */ 3261541Srgrimes cnp->cn_consume = 0; 3271541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 32851906Sphk continue; 3291541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3301541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3311541Srgrimes error = ENAMETOOLONG; 3321541Srgrimes goto bad; 3331541Srgrimes } 3341541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3351541Srgrimes { char c = *cp; 3361541Srgrimes *cp = '\0'; 3371541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3381541Srgrimes *cp = c; } 3391541Srgrimes#endif 3401541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3411541Srgrimes ndp->ni_next = cp; 3429804Sbde 3439804Sbde /* 3449804Sbde * Replace multiple slashes by a single slash and trailing slashes 3459804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3469804Sbde * fs's don't know about trailing slashes. Remember if there were 3479804Sbde * trailing slashes to handle symlinks, existing non-directories 3489804Sbde * and non-existing files that won't be directories specially later. 3499804Sbde */ 3509804Sbde trailing_slash = 0; 3519804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 3529804Sbde cp++; 3539804Sbde ndp->ni_pathlen--; 3549804Sbde if (*cp == '\0') { 3559804Sbde trailing_slash = 1; 3569804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 3579804Sbde } 3589804Sbde } 3599804Sbde ndp->ni_next = cp; 3609804Sbde 3611541Srgrimes cnp->cn_flags |= MAKEENTRY; 3621541Srgrimes if (*cp == '\0' && docache == 0) 3631541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 3641541Srgrimes if (cnp->cn_namelen == 2 && 3651541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 3661541Srgrimes cnp->cn_flags |= ISDOTDOT; 3671541Srgrimes else 3681541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 3691541Srgrimes if (*ndp->ni_next == 0) 3701541Srgrimes cnp->cn_flags |= ISLASTCN; 3711541Srgrimes else 3721541Srgrimes cnp->cn_flags &= ~ISLASTCN; 3731541Srgrimes 3741541Srgrimes 3751541Srgrimes /* 3761541Srgrimes * Check for degenerate name (e.g. / or "") 3771541Srgrimes * which is a way of talking about a directory, 3781541Srgrimes * e.g. like "/." or ".". 3791541Srgrimes */ 3801541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 38122521Sdyson if (dp->v_type != VDIR) { 38222521Sdyson error = ENOTDIR; 38322521Sdyson goto bad; 38422521Sdyson } 3851541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 3861541Srgrimes error = EISDIR; 3871541Srgrimes goto bad; 3881541Srgrimes } 3891541Srgrimes if (wantparent) { 3901541Srgrimes ndp->ni_dvp = dp; 3911541Srgrimes VREF(dp); 3921541Srgrimes } 3931541Srgrimes ndp->ni_vp = dp; 3941541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 39522521Sdyson VOP_UNLOCK(dp, 0, p); 39654655Seivind /* XXX This should probably move to the top of function. */ 3971541Srgrimes if (cnp->cn_flags & SAVESTART) 3981541Srgrimes panic("lookup: SAVESTART"); 3991541Srgrimes return (0); 4001541Srgrimes } 4011541Srgrimes 4021541Srgrimes /* 4031541Srgrimes * Handle "..": two special cases. 4041541Srgrimes * 1. If at root directory (e.g. after chroot) 4051541Srgrimes * or at absolute root directory 4061541Srgrimes * then ignore it so can't get out. 4071541Srgrimes * 2. If this vnode is the root of a mounted 4081541Srgrimes * filesystem, then replace it with the 4091541Srgrimes * vnode which was mounted on so we take the 4101541Srgrimes * .. in the other file system. 41151649Sphk * 3. If the vnode is the top directory of 41251649Sphk * the jail or chroot, don't let them out. 4131541Srgrimes */ 4141541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 4151541Srgrimes for (;;) { 41651649Sphk if (dp == ndp->ni_rootdir || 41751649Sphk dp == ndp->ni_topdir || 41851649Sphk dp == rootvnode) { 4191541Srgrimes ndp->ni_dvp = dp; 4201541Srgrimes ndp->ni_vp = dp; 4211541Srgrimes VREF(dp); 4221541Srgrimes goto nextname; 4231541Srgrimes } 4241541Srgrimes if ((dp->v_flag & VROOT) == 0 || 4251541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 4261541Srgrimes break; 42769405Salfred if (dp->v_mount == NULL) { /* forced unmount */ 42869405Salfred error = EBADF; 42969405Salfred goto bad; 43069405Salfred } 4311541Srgrimes tdp = dp; 4321541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4331541Srgrimes vput(tdp); 4341541Srgrimes VREF(dp); 43522521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 4361541Srgrimes } 4371541Srgrimes } 4381541Srgrimes 4391541Srgrimes /* 4401541Srgrimes * We now have a segment name to search for, and a directory to search. 4411541Srgrimes */ 4421541Srgrimesunionlookup: 4431541Srgrimes ndp->ni_dvp = dp; 44422521Sdyson ndp->ni_vp = NULL; 44565973Sbp cnp->cn_flags &= ~PDIRUNLOCK; 44624624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 44743301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 44842408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 4491541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4501541Srgrimes printf("not found\n"); 4511541Srgrimes#endif 4521541Srgrimes if ((error == ENOENT) && 45369405Salfred (dp->v_flag & VROOT) && (dp->v_mount != NULL) && 4541541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 4551541Srgrimes tdp = dp; 4561541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 45765973Sbp if (cnp->cn_flags & PDIRUNLOCK) 45865973Sbp vrele(tdp); 45965973Sbp else 46065973Sbp vput(tdp); 4611541Srgrimes VREF(dp); 46222521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 4631541Srgrimes goto unionlookup; 4641541Srgrimes } 4651541Srgrimes 4661541Srgrimes if (error != EJUSTRETURN) 4671541Srgrimes goto bad; 4681541Srgrimes /* 4691541Srgrimes * If creating and at end of pathname, then can consider 4701541Srgrimes * allowing file to be created. 4711541Srgrimes */ 47211644Sdg if (rdonly) { 4731541Srgrimes error = EROFS; 4741541Srgrimes goto bad; 4751541Srgrimes } 4769804Sbde if (*cp == '\0' && trailing_slash && 4779804Sbde !(cnp->cn_flags & WILLBEDIR)) { 4789804Sbde error = ENOENT; 4799804Sbde goto bad; 4809804Sbde } 4811541Srgrimes /* 4821541Srgrimes * We return with ni_vp NULL to indicate that the entry 4831541Srgrimes * doesn't currently exist, leaving a pointer to the 4841541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 4851541Srgrimes */ 4861541Srgrimes if (cnp->cn_flags & SAVESTART) { 4871541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 4881541Srgrimes VREF(ndp->ni_startdir); 4891541Srgrimes } 4901541Srgrimes return (0); 4911541Srgrimes } 4921541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4931541Srgrimes printf("found\n"); 4941541Srgrimes#endif 4951541Srgrimes 49624624Sdfr ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); 49724624Sdfr 4981541Srgrimes /* 4991541Srgrimes * Take into account any additional components consumed by 5001541Srgrimes * the underlying filesystem. 5011541Srgrimes */ 5021541Srgrimes if (cnp->cn_consume > 0) { 5031541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 5041541Srgrimes ndp->ni_next += cnp->cn_consume; 5051541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 5061541Srgrimes cnp->cn_consume = 0; 5071541Srgrimes } 5081541Srgrimes 5091541Srgrimes dp = ndp->ni_vp; 5101541Srgrimes 5111541Srgrimes /* 5121541Srgrimes * Check to see if the vnode has been mounted on; 5131541Srgrimes * if so find the root of the mounted file system. 5141541Srgrimes */ 5151541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 5161541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 51722521Sdyson if (vfs_busy(mp, 0, 0, p)) 5181541Srgrimes continue; 51965805Sbp VOP_UNLOCK(dp, 0, p); 52022521Sdyson error = VFS_ROOT(mp, &tdp); 52122521Sdyson vfs_unbusy(mp, p); 52265805Sbp if (error) { 52365805Sbp dpunlocked = 1; 5241541Srgrimes goto bad2; 52565805Sbp } 52665805Sbp vrele(dp); 5271541Srgrimes ndp->ni_vp = dp = tdp; 5281541Srgrimes } 5291541Srgrimes 53010219Sdfr /* 53110219Sdfr * Check for symbolic link 53210219Sdfr */ 53310219Sdfr if ((dp->v_type == VLNK) && 53410219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 53510219Sdfr *ndp->ni_next == '/')) { 53610219Sdfr cnp->cn_flags |= ISSYMLINK; 53769405Salfred if (dp->v_mount == NULL) { 53869405Salfred /* We can't know whether the directory was mounted with 53969405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 54069405Salfred error = EBADF; 54169405Salfred goto bad2; 54269405Salfred } 54335105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 54435105Swosch error = EACCES; 54535105Swosch goto bad2; 54635105Swosch } 54710219Sdfr return (0); 54810219Sdfr } 54910219Sdfr 55010219Sdfr /* 55110219Sdfr * Check for bogus trailing slashes. 55210219Sdfr */ 55310219Sdfr if (trailing_slash && dp->v_type != VDIR) { 55410219Sdfr error = ENOTDIR; 55510219Sdfr goto bad2; 55610219Sdfr } 55710219Sdfr 5581541Srgrimesnextname: 5591541Srgrimes /* 5601541Srgrimes * Not a symbolic link. If more pathname, 5611541Srgrimes * continue at next component, else return. 5621541Srgrimes */ 5631541Srgrimes if (*ndp->ni_next == '/') { 5641541Srgrimes cnp->cn_nameptr = ndp->ni_next; 5651541Srgrimes while (*cnp->cn_nameptr == '/') { 5661541Srgrimes cnp->cn_nameptr++; 5671541Srgrimes ndp->ni_pathlen--; 5681541Srgrimes } 56954655Seivind if (ndp->ni_dvp != ndp->ni_vp) 57054655Seivind ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); 5711541Srgrimes vrele(ndp->ni_dvp); 5721541Srgrimes goto dirloop; 5731541Srgrimes } 5741541Srgrimes /* 57511644Sdg * Disallow directory write attempts on read-only file systems. 5761541Srgrimes */ 57711644Sdg if (rdonly && 57811644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 57911644Sdg error = EROFS; 58011644Sdg goto bad2; 5811541Srgrimes } 5821541Srgrimes if (cnp->cn_flags & SAVESTART) { 5831541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5841541Srgrimes VREF(ndp->ni_startdir); 5851541Srgrimes } 5861541Srgrimes if (!wantparent) 5871541Srgrimes vrele(ndp->ni_dvp); 58832071Sdyson 5891541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 59022521Sdyson VOP_UNLOCK(dp, 0, p); 5911541Srgrimes return (0); 5921541Srgrimes 5931541Srgrimesbad2: 59465973Sbp if ((cnp->cn_flags & (LOCKPARENT | PDIRUNLOCK)) == LOCKPARENT && 59565973Sbp *ndp->ni_next == '\0') 59622521Sdyson VOP_UNLOCK(ndp->ni_dvp, 0, p); 5971541Srgrimes vrele(ndp->ni_dvp); 5981541Srgrimesbad: 59965805Sbp if (dpunlocked) 60065805Sbp vrele(dp); 60165805Sbp else 60265805Sbp vput(dp); 6031541Srgrimes ndp->ni_vp = NULL; 6041541Srgrimes return (error); 6051541Srgrimes} 6061541Srgrimes 6073148Sphk/* 6083148Sphk * relookup - lookup a path name component 6093148Sphk * Used by lookup to re-aquire things. 6103148Sphk */ 6113148Sphkint 6123148Sphkrelookup(dvp, vpp, cnp) 6133148Sphk struct vnode *dvp, **vpp; 6143148Sphk struct componentname *cnp; 6153148Sphk{ 61622521Sdyson struct proc *p = cnp->cn_proc; 61722521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 6183148Sphk int docache; /* == 0 do not cache last component */ 6193148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 6203148Sphk int rdonly; /* lookup read-only flag bit */ 6213148Sphk int error = 0; 6223148Sphk#ifdef NAMEI_DIAGNOSTIC 6233148Sphk int newhash; /* DEBUG: check name hash */ 6243148Sphk char *cp; /* DEBUG: check name ptr/len */ 6253148Sphk#endif 6261541Srgrimes 6273148Sphk /* 6283148Sphk * Setup: break out flag bits into variables. 6293148Sphk */ 6303148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 6313148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 6323148Sphk if (cnp->cn_nameiop == DELETE || 6333148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 6343148Sphk docache = 0; 6353148Sphk rdonly = cnp->cn_flags & RDONLY; 6363148Sphk cnp->cn_flags &= ~ISSYMLINK; 6373148Sphk dp = dvp; 63822521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 6393148Sphk 6403148Sphk/* dirloop: */ 6413148Sphk /* 6423148Sphk * Search a new directory. 6433148Sphk * 6443148Sphk * The last component of the filename is left accessible via 6453148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 6463148Sphk * the name set the SAVENAME flag. When done, they assume 6473148Sphk * responsibility for freeing the pathname buffer. 6483148Sphk */ 6493148Sphk#ifdef NAMEI_DIAGNOSTIC 6503148Sphk if (cnp->cn_namelen != cp - cnp->cn_nameptr) 6513148Sphk panic ("relookup: bad len"); 6523148Sphk if (*cp != 0) 6533148Sphk panic("relookup: not last component"); 6543148Sphk printf("{%s}: ", cnp->cn_nameptr); 6553148Sphk#endif 6563148Sphk 6573148Sphk /* 6583148Sphk * Check for degenerate name (e.g. / or "") 6593148Sphk * which is a way of talking about a directory, 6603148Sphk * e.g. like "/." or ".". 6613148Sphk */ 6623148Sphk if (cnp->cn_nameptr[0] == '\0') { 6633148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 6643148Sphk error = EISDIR; 6653148Sphk goto bad; 6663148Sphk } 6673148Sphk if (dp->v_type != VDIR) { 6683148Sphk error = ENOTDIR; 6693148Sphk goto bad; 6703148Sphk } 6713148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 67222521Sdyson VOP_UNLOCK(dp, 0, p); 6733148Sphk *vpp = dp; 67454655Seivind /* XXX This should probably move to the top of function. */ 6753148Sphk if (cnp->cn_flags & SAVESTART) 6763148Sphk panic("lookup: SAVESTART"); 6773148Sphk return (0); 6783148Sphk } 6793148Sphk 6803148Sphk if (cnp->cn_flags & ISDOTDOT) 6813148Sphk panic ("relookup: lookup on dot-dot"); 6823148Sphk 6833148Sphk /* 6843148Sphk * We now have a segment name to search for, and a directory to search. 6853148Sphk */ 68643311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 68742408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 6883148Sphk if (error != EJUSTRETURN) 6893148Sphk goto bad; 6903148Sphk /* 6913148Sphk * If creating and at end of pathname, then can consider 6923148Sphk * allowing file to be created. 6933148Sphk */ 69411644Sdg if (rdonly) { 6953148Sphk error = EROFS; 6963148Sphk goto bad; 6973148Sphk } 6983148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 6993148Sphk if (cnp->cn_flags & SAVESTART) 7003148Sphk VREF(dvp); 7013148Sphk /* 7023148Sphk * We return with ni_vp NULL to indicate that the entry 7033148Sphk * doesn't currently exist, leaving a pointer to the 7043148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 7053148Sphk */ 7063148Sphk return (0); 7073148Sphk } 7083148Sphk dp = *vpp; 7093148Sphk 7103148Sphk /* 7113148Sphk * Check for symbolic link 7123148Sphk */ 71342408Seivind KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 71442453Seivind ("relookup: symlink found.\n")); 7153148Sphk 7163148Sphk /* 71711644Sdg * Disallow directory write attempts on read-only file systems. 7183148Sphk */ 71911644Sdg if (rdonly && 72011644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 72111644Sdg error = EROFS; 72211644Sdg goto bad2; 7233148Sphk } 7243148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7253148Sphk if (cnp->cn_flags & SAVESTART) 7263148Sphk VREF(dvp); 72722521Sdyson 7283148Sphk if (!wantparent) 7293148Sphk vrele(dvp); 73032071Sdyson 73149101Salc if (vn_canvmio(dp) == TRUE && 73232286Sdyson ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF)) 73342315Seivind vfs_object_create(dp, cnp->cn_proc, cnp->cn_cred); 73432071Sdyson 7353148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 73622521Sdyson VOP_UNLOCK(dp, 0, p); 7373148Sphk return (0); 7383148Sphk 7393148Sphkbad2: 7403148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 74122521Sdyson VOP_UNLOCK(dvp, 0, p); 7423148Sphk vrele(dvp); 7433148Sphkbad: 7443148Sphk vput(dp); 7453148Sphk *vpp = NULL; 7463148Sphk return (error); 7473148Sphk} 748