vfs_lookup.c revision 51649
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 51649 1999-09-25 14:14:21Z phk $ 401541Srgrimes */ 411541Srgrimes 4213203Swollman#include "opt_ktrace.h" 4313203Swollman 441541Srgrimes#include <sys/param.h> 452112Swollman#include <sys/systm.h> 461541Srgrimes#include <sys/namei.h> 471541Srgrimes#include <sys/vnode.h> 481541Srgrimes#include <sys/mount.h> 491541Srgrimes#include <sys/filedesc.h> 501541Srgrimes#include <sys/proc.h> 511541Srgrimes 521541Srgrimes#ifdef KTRACE 531541Srgrimes#include <sys/ktrace.h> 541541Srgrimes#endif 551541Srgrimes 5632011Sbde#include <vm/vm_zone.h> 5732011Sbde 581541Srgrimes/* 591541Srgrimes * Convert a pathname into a pointer to a locked inode. 601541Srgrimes * 611541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 621541Srgrimes * when they occur at the end of the name translation process. 631541Srgrimes * Symbolic links are always followed for all other pathname 641541Srgrimes * components other than the last. 651541Srgrimes * 661541Srgrimes * The segflg defines whether the name is to be copied from user 671541Srgrimes * space or kernel space. 681541Srgrimes * 691541Srgrimes * Overall outline of namei: 701541Srgrimes * 711541Srgrimes * copy in name 721541Srgrimes * get starting directory 731541Srgrimes * while (!done && !error) { 741541Srgrimes * call lookup to search path. 751541Srgrimes * if symbolic link, massage name in buffer and continue 761541Srgrimes * } 771541Srgrimes */ 781541Srgrimesint 791541Srgrimesnamei(ndp) 801541Srgrimes register struct nameidata *ndp; 811541Srgrimes{ 821541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 831541Srgrimes register char *cp; /* pointer into pathname argument */ 841541Srgrimes register struct vnode *dp; /* the directory we are searching */ 851541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 861541Srgrimes struct uio auio; 871541Srgrimes int error, linklen; 881541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 8922521Sdyson struct proc *p = cnp->cn_proc; 901541Srgrimes 911541Srgrimes ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 9242408Seivind KASSERT(cnp->cn_cred && cnp->cn_proc, ("namei: bad cred/proc")); 9342408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 9442453Seivind ("namei: nameiop contaminated with flags")); 9542408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 9642453Seivind ("namei: flags contaminated with nameiops")); 971541Srgrimes fdp = cnp->cn_proc->p_fd; 981541Srgrimes 991541Srgrimes /* 1001541Srgrimes * Get a buffer for the name to be translated, and copy the 1011541Srgrimes * name into the buffer. 1021541Srgrimes */ 1031541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 10429653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 1051541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1061541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 10736735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1081541Srgrimes else 1091541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 11036735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 11120069Sbde 11220069Sbde /* 11320069Sbde * Don't allow empty pathnames. 11420069Sbde */ 11520069Sbde if (!error && *cnp->cn_pnbuf == '\0') 11620069Sbde error = ENOENT; 11720069Sbde 1181541Srgrimes if (error) { 11929653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 1201541Srgrimes ndp->ni_vp = NULL; 1211541Srgrimes return (error); 1221541Srgrimes } 1231541Srgrimes ndp->ni_loopcnt = 0; 1241541Srgrimes#ifdef KTRACE 1251541Srgrimes if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 1261541Srgrimes ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 1271541Srgrimes#endif 1281541Srgrimes 1291541Srgrimes /* 1301541Srgrimes * Get starting point for the translation. 1311541Srgrimes */ 13233360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 13351649Sphk ndp->ni_topdir = fdp->fd_jdir; 13433360Sdyson 1351541Srgrimes dp = fdp->fd_cdir; 1361541Srgrimes VREF(dp); 1371541Srgrimes for (;;) { 1381541Srgrimes /* 1391541Srgrimes * Check if root directory should replace current directory. 1401541Srgrimes * Done at start of translation and after symbolic link. 1411541Srgrimes */ 1421541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1431541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1441541Srgrimes vrele(dp); 1451541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1461541Srgrimes cnp->cn_nameptr++; 1471541Srgrimes ndp->ni_pathlen--; 1481541Srgrimes } 1491541Srgrimes dp = ndp->ni_rootdir; 1501541Srgrimes VREF(dp); 1511541Srgrimes } 1521541Srgrimes ndp->ni_startdir = dp; 1533148Sphk error = lookup(ndp); 1543148Sphk if (error) { 15529653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 1561541Srgrimes return (error); 1571541Srgrimes } 1581541Srgrimes /* 1591541Srgrimes * Check for symbolic link 1601541Srgrimes */ 1611541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 1621541Srgrimes if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 16329653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 1641541Srgrimes else 1651541Srgrimes cnp->cn_flags |= HASBUF; 16632286Sdyson 16749101Salc if (vn_canvmio(ndp->ni_vp) == TRUE && 16832286Sdyson (cnp->cn_nameiop != DELETE) && 16942315Seivind ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == 17042315Seivind LOCKLEAF)) 17132286Sdyson vfs_object_create(ndp->ni_vp, 17242315Seivind ndp->ni_cnd.cn_proc, 17342315Seivind ndp->ni_cnd.cn_cred); 17432286Sdyson 1751541Srgrimes return (0); 1761541Srgrimes } 1771541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 17822521Sdyson VOP_UNLOCK(ndp->ni_dvp, 0, p); 1791541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1801541Srgrimes error = ELOOP; 1811541Srgrimes break; 1821541Srgrimes } 1831541Srgrimes if (ndp->ni_pathlen > 1) 18429653Sdyson cp = zalloc(namei_zone); 1851541Srgrimes else 1861541Srgrimes cp = cnp->cn_pnbuf; 1871541Srgrimes aiov.iov_base = cp; 1881541Srgrimes aiov.iov_len = MAXPATHLEN; 1891541Srgrimes auio.uio_iov = &aiov; 1901541Srgrimes auio.uio_iovcnt = 1; 1911541Srgrimes auio.uio_offset = 0; 1921541Srgrimes auio.uio_rw = UIO_READ; 1931541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 1941541Srgrimes auio.uio_procp = (struct proc *)0; 1951541Srgrimes auio.uio_resid = MAXPATHLEN; 1963148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 1973148Sphk if (error) { 1981541Srgrimes if (ndp->ni_pathlen > 1) 19929653Sdyson zfree(namei_zone, cp); 2001541Srgrimes break; 2011541Srgrimes } 2021541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 2031541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2041541Srgrimes if (ndp->ni_pathlen > 1) 20529653Sdyson zfree(namei_zone, cp); 2061541Srgrimes error = ENAMETOOLONG; 2071541Srgrimes break; 2081541Srgrimes } 2091541Srgrimes if (ndp->ni_pathlen > 1) { 2101541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 21129653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 2121541Srgrimes cnp->cn_pnbuf = cp; 2131541Srgrimes } else 2141541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2151541Srgrimes ndp->ni_pathlen += linklen; 2161541Srgrimes vput(ndp->ni_vp); 2171541Srgrimes dp = ndp->ni_dvp; 2181541Srgrimes } 21929653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 2201541Srgrimes vrele(ndp->ni_dvp); 2211541Srgrimes vput(ndp->ni_vp); 2221541Srgrimes ndp->ni_vp = NULL; 2231541Srgrimes return (error); 2241541Srgrimes} 2251541Srgrimes 2261541Srgrimes/* 2271541Srgrimes * Search a pathname. 2281541Srgrimes * This is a very central and rather complicated routine. 2291541Srgrimes * 2301541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2311541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2321541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2331541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2341541Srgrimes * symbolic link needing interpretation is encountered. 2351541Srgrimes * 2361541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 2371541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 2381541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 2391541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 2401541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 2411541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 2421541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 2431541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 2441541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 2451541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 2461541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 2478876Srgrimes * 2481541Srgrimes * Overall outline of lookup: 2491541Srgrimes * 2501541Srgrimes * dirloop: 2511541Srgrimes * identify next component of name at ndp->ni_ptr 2521541Srgrimes * handle degenerate case where name is null string 2531541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 2541541Srgrimes * call VOP_LOOKUP routine for next component name 2551541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 2561541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 2571541Srgrimes * if result vnode is mounted on and crossing mount points, 2581541Srgrimes * find mounted on vnode 2591541Srgrimes * if more components of name, do next level at dirloop 2601541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 2611541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 2621541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 2631541Srgrimes */ 2641541Srgrimesint 2651541Srgrimeslookup(ndp) 2661541Srgrimes register struct nameidata *ndp; 2671541Srgrimes{ 2681541Srgrimes register char *cp; /* pointer into pathname argument */ 2691541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 2701541Srgrimes struct vnode *tdp; /* saved dp */ 2711541Srgrimes struct mount *mp; /* mount table entry */ 2721541Srgrimes int docache; /* == 0 do not cache last component */ 2731541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 2741541Srgrimes int rdonly; /* lookup read-only flag bit */ 2759804Sbde int trailing_slash; 2761541Srgrimes int error = 0; 2771541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 27822521Sdyson struct proc *p = cnp->cn_proc; 2791541Srgrimes 2801541Srgrimes /* 2811541Srgrimes * Setup: break out flag bits into variables. 2821541Srgrimes */ 2831541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 2841541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 2851541Srgrimes if (cnp->cn_nameiop == DELETE || 28622874Sbde (wantparent && cnp->cn_nameiop != CREATE && 28722874Sbde cnp->cn_nameiop != LOOKUP)) 2881541Srgrimes docache = 0; 2891541Srgrimes rdonly = cnp->cn_flags & RDONLY; 2901541Srgrimes ndp->ni_dvp = NULL; 2911541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 2921541Srgrimes dp = ndp->ni_startdir; 2931541Srgrimes ndp->ni_startdir = NULLVP; 29422521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 2951541Srgrimes 2961541Srgrimesdirloop: 2971541Srgrimes /* 2981541Srgrimes * Search a new directory. 2991541Srgrimes * 3001541Srgrimes * The cn_hash value is for use by vfs_cache. 3011541Srgrimes * The last component of the filename is left accessible via 3021541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3031541Srgrimes * the name set the SAVENAME flag. When done, they assume 3041541Srgrimes * responsibility for freeing the pathname buffer. 3051541Srgrimes */ 3061541Srgrimes cnp->cn_consume = 0; 3071541Srgrimes cnp->cn_hash = 0; 3081541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 3091541Srgrimes cnp->cn_hash += (unsigned char)*cp; 3101541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3111541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3121541Srgrimes error = ENAMETOOLONG; 3131541Srgrimes goto bad; 3141541Srgrimes } 3151541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3161541Srgrimes { char c = *cp; 3171541Srgrimes *cp = '\0'; 3181541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3191541Srgrimes *cp = c; } 3201541Srgrimes#endif 3211541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3221541Srgrimes ndp->ni_next = cp; 3239804Sbde 3249804Sbde /* 3259804Sbde * Replace multiple slashes by a single slash and trailing slashes 3269804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3279804Sbde * fs's don't know about trailing slashes. Remember if there were 3289804Sbde * trailing slashes to handle symlinks, existing non-directories 3299804Sbde * and non-existing files that won't be directories specially later. 3309804Sbde */ 3319804Sbde trailing_slash = 0; 3329804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 3339804Sbde cp++; 3349804Sbde ndp->ni_pathlen--; 3359804Sbde if (*cp == '\0') { 3369804Sbde trailing_slash = 1; 3379804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 3389804Sbde } 3399804Sbde } 3409804Sbde ndp->ni_next = cp; 3419804Sbde 3421541Srgrimes cnp->cn_flags |= MAKEENTRY; 3431541Srgrimes if (*cp == '\0' && docache == 0) 3441541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 3451541Srgrimes if (cnp->cn_namelen == 2 && 3461541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 3471541Srgrimes cnp->cn_flags |= ISDOTDOT; 3481541Srgrimes else 3491541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 3501541Srgrimes if (*ndp->ni_next == 0) 3511541Srgrimes cnp->cn_flags |= ISLASTCN; 3521541Srgrimes else 3531541Srgrimes cnp->cn_flags &= ~ISLASTCN; 3541541Srgrimes 3551541Srgrimes 3561541Srgrimes /* 3571541Srgrimes * Check for degenerate name (e.g. / or "") 3581541Srgrimes * which is a way of talking about a directory, 3591541Srgrimes * e.g. like "/." or ".". 3601541Srgrimes */ 3611541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 36222521Sdyson if (dp->v_type != VDIR) { 36322521Sdyson error = ENOTDIR; 36422521Sdyson goto bad; 36522521Sdyson } 3661541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 3671541Srgrimes error = EISDIR; 3681541Srgrimes goto bad; 3691541Srgrimes } 3701541Srgrimes if (wantparent) { 3711541Srgrimes ndp->ni_dvp = dp; 3721541Srgrimes VREF(dp); 3731541Srgrimes } 3741541Srgrimes ndp->ni_vp = dp; 3751541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 37622521Sdyson VOP_UNLOCK(dp, 0, p); 3771541Srgrimes if (cnp->cn_flags & SAVESTART) 3781541Srgrimes panic("lookup: SAVESTART"); 3791541Srgrimes return (0); 3801541Srgrimes } 3811541Srgrimes 3821541Srgrimes /* 3831541Srgrimes * Handle "..": two special cases. 3841541Srgrimes * 1. If at root directory (e.g. after chroot) 3851541Srgrimes * or at absolute root directory 3861541Srgrimes * then ignore it so can't get out. 3871541Srgrimes * 2. If this vnode is the root of a mounted 3881541Srgrimes * filesystem, then replace it with the 3891541Srgrimes * vnode which was mounted on so we take the 3901541Srgrimes * .. in the other file system. 39151649Sphk * 3. If the vnode is the top directory of 39251649Sphk * the jail or chroot, don't let them out. 3931541Srgrimes */ 3941541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 3951541Srgrimes for (;;) { 39651649Sphk if (dp == ndp->ni_rootdir || 39751649Sphk dp == ndp->ni_topdir || 39851649Sphk dp == rootvnode) { 3991541Srgrimes ndp->ni_dvp = dp; 4001541Srgrimes ndp->ni_vp = dp; 4011541Srgrimes VREF(dp); 4021541Srgrimes goto nextname; 4031541Srgrimes } 4041541Srgrimes if ((dp->v_flag & VROOT) == 0 || 4051541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 4061541Srgrimes break; 4071541Srgrimes tdp = dp; 4081541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4091541Srgrimes vput(tdp); 4101541Srgrimes VREF(dp); 41122521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 4121541Srgrimes } 4131541Srgrimes } 4141541Srgrimes 4151541Srgrimes /* 4161541Srgrimes * We now have a segment name to search for, and a directory to search. 4171541Srgrimes */ 4181541Srgrimesunionlookup: 4191541Srgrimes ndp->ni_dvp = dp; 42022521Sdyson ndp->ni_vp = NULL; 42124624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 42243301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 42342408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 4241541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4251541Srgrimes printf("not found\n"); 4261541Srgrimes#endif 4271541Srgrimes if ((error == ENOENT) && 4281541Srgrimes (dp->v_flag & VROOT) && 4291541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 4301541Srgrimes tdp = dp; 4311541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4321541Srgrimes vput(tdp); 4331541Srgrimes VREF(dp); 43422521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 4351541Srgrimes goto unionlookup; 4361541Srgrimes } 4371541Srgrimes 4381541Srgrimes if (error != EJUSTRETURN) 4391541Srgrimes goto bad; 4401541Srgrimes /* 4411541Srgrimes * If creating and at end of pathname, then can consider 4421541Srgrimes * allowing file to be created. 4431541Srgrimes */ 44411644Sdg if (rdonly) { 4451541Srgrimes error = EROFS; 4461541Srgrimes goto bad; 4471541Srgrimes } 4489804Sbde if (*cp == '\0' && trailing_slash && 4499804Sbde !(cnp->cn_flags & WILLBEDIR)) { 4509804Sbde error = ENOENT; 4519804Sbde goto bad; 4529804Sbde } 4531541Srgrimes /* 4541541Srgrimes * We return with ni_vp NULL to indicate that the entry 4551541Srgrimes * doesn't currently exist, leaving a pointer to the 4561541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 4571541Srgrimes */ 4581541Srgrimes if (cnp->cn_flags & SAVESTART) { 4591541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 4601541Srgrimes VREF(ndp->ni_startdir); 4611541Srgrimes } 4621541Srgrimes return (0); 4631541Srgrimes } 4641541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4651541Srgrimes printf("found\n"); 4661541Srgrimes#endif 4671541Srgrimes 46824624Sdfr ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); 46924624Sdfr 4701541Srgrimes /* 4711541Srgrimes * Take into account any additional components consumed by 4721541Srgrimes * the underlying filesystem. 4731541Srgrimes */ 4741541Srgrimes if (cnp->cn_consume > 0) { 4751541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 4761541Srgrimes ndp->ni_next += cnp->cn_consume; 4771541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 4781541Srgrimes cnp->cn_consume = 0; 4791541Srgrimes } 4801541Srgrimes 4811541Srgrimes dp = ndp->ni_vp; 4821541Srgrimes 4831541Srgrimes /* 4841541Srgrimes * Check to see if the vnode has been mounted on; 4851541Srgrimes * if so find the root of the mounted file system. 4861541Srgrimes */ 4871541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 4881541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 48922521Sdyson if (vfs_busy(mp, 0, 0, p)) 4901541Srgrimes continue; 49122521Sdyson error = VFS_ROOT(mp, &tdp); 49222521Sdyson vfs_unbusy(mp, p); 4933148Sphk if (error) 4941541Srgrimes goto bad2; 4951541Srgrimes vput(dp); 4961541Srgrimes ndp->ni_vp = dp = tdp; 4971541Srgrimes } 4981541Srgrimes 49910219Sdfr /* 50010219Sdfr * Check for symbolic link 50110219Sdfr */ 50210219Sdfr if ((dp->v_type == VLNK) && 50310219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 50410219Sdfr *ndp->ni_next == '/')) { 50510219Sdfr cnp->cn_flags |= ISSYMLINK; 50635105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 50735105Swosch error = EACCES; 50835105Swosch goto bad2; 50935105Swosch } 51010219Sdfr return (0); 51110219Sdfr } 51210219Sdfr 51310219Sdfr /* 51410219Sdfr * Check for bogus trailing slashes. 51510219Sdfr */ 51610219Sdfr if (trailing_slash && dp->v_type != VDIR) { 51710219Sdfr error = ENOTDIR; 51810219Sdfr goto bad2; 51910219Sdfr } 52010219Sdfr 5211541Srgrimesnextname: 5221541Srgrimes /* 5231541Srgrimes * Not a symbolic link. If more pathname, 5241541Srgrimes * continue at next component, else return. 5251541Srgrimes */ 5261541Srgrimes if (*ndp->ni_next == '/') { 5271541Srgrimes cnp->cn_nameptr = ndp->ni_next; 5281541Srgrimes while (*cnp->cn_nameptr == '/') { 5291541Srgrimes cnp->cn_nameptr++; 5301541Srgrimes ndp->ni_pathlen--; 5311541Srgrimes } 53224624Sdfr if (ndp->ni_dvp != ndp->ni_vp) { 53324624Sdfr ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); 53424624Sdfr } 5351541Srgrimes vrele(ndp->ni_dvp); 5361541Srgrimes goto dirloop; 5371541Srgrimes } 5381541Srgrimes /* 53911644Sdg * Disallow directory write attempts on read-only file systems. 5401541Srgrimes */ 54111644Sdg if (rdonly && 54211644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 54311644Sdg error = EROFS; 54411644Sdg goto bad2; 5451541Srgrimes } 5461541Srgrimes if (cnp->cn_flags & SAVESTART) { 5471541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5481541Srgrimes VREF(ndp->ni_startdir); 5491541Srgrimes } 5501541Srgrimes if (!wantparent) 5511541Srgrimes vrele(ndp->ni_dvp); 55232071Sdyson 5531541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 55422521Sdyson VOP_UNLOCK(dp, 0, p); 5551541Srgrimes return (0); 5561541Srgrimes 5571541Srgrimesbad2: 5581541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 55922521Sdyson VOP_UNLOCK(ndp->ni_dvp, 0, p); 5601541Srgrimes vrele(ndp->ni_dvp); 5611541Srgrimesbad: 5621541Srgrimes vput(dp); 5631541Srgrimes ndp->ni_vp = NULL; 5641541Srgrimes return (error); 5651541Srgrimes} 5661541Srgrimes 5673148Sphk/* 5683148Sphk * relookup - lookup a path name component 5693148Sphk * Used by lookup to re-aquire things. 5703148Sphk */ 5713148Sphkint 5723148Sphkrelookup(dvp, vpp, cnp) 5733148Sphk struct vnode *dvp, **vpp; 5743148Sphk struct componentname *cnp; 5753148Sphk{ 57622521Sdyson struct proc *p = cnp->cn_proc; 57722521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 5783148Sphk int docache; /* == 0 do not cache last component */ 5793148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 5803148Sphk int rdonly; /* lookup read-only flag bit */ 5813148Sphk int error = 0; 5823148Sphk#ifdef NAMEI_DIAGNOSTIC 5833148Sphk int newhash; /* DEBUG: check name hash */ 5843148Sphk char *cp; /* DEBUG: check name ptr/len */ 5853148Sphk#endif 5861541Srgrimes 5873148Sphk /* 5883148Sphk * Setup: break out flag bits into variables. 5893148Sphk */ 5903148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 5913148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 5923148Sphk if (cnp->cn_nameiop == DELETE || 5933148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 5943148Sphk docache = 0; 5953148Sphk rdonly = cnp->cn_flags & RDONLY; 5963148Sphk cnp->cn_flags &= ~ISSYMLINK; 5973148Sphk dp = dvp; 59822521Sdyson vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); 5993148Sphk 6003148Sphk/* dirloop: */ 6013148Sphk /* 6023148Sphk * Search a new directory. 6033148Sphk * 6043148Sphk * The cn_hash value is for use by vfs_cache. 6053148Sphk * The last component of the filename is left accessible via 6063148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 6073148Sphk * the name set the SAVENAME flag. When done, they assume 6083148Sphk * responsibility for freeing the pathname buffer. 6093148Sphk */ 6103148Sphk#ifdef NAMEI_DIAGNOSTIC 6113148Sphk for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 6123148Sphk newhash += (unsigned char)*cp; 6133148Sphk if (newhash != cnp->cn_hash) 6143148Sphk panic("relookup: bad hash"); 6153148Sphk if (cnp->cn_namelen != cp - cnp->cn_nameptr) 6163148Sphk panic ("relookup: bad len"); 6173148Sphk if (*cp != 0) 6183148Sphk panic("relookup: not last component"); 6193148Sphk printf("{%s}: ", cnp->cn_nameptr); 6203148Sphk#endif 6213148Sphk 6223148Sphk /* 6233148Sphk * Check for degenerate name (e.g. / or "") 6243148Sphk * which is a way of talking about a directory, 6253148Sphk * e.g. like "/." or ".". 6263148Sphk */ 6273148Sphk if (cnp->cn_nameptr[0] == '\0') { 6283148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 6293148Sphk error = EISDIR; 6303148Sphk goto bad; 6313148Sphk } 6323148Sphk if (dp->v_type != VDIR) { 6333148Sphk error = ENOTDIR; 6343148Sphk goto bad; 6353148Sphk } 6363148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 63722521Sdyson VOP_UNLOCK(dp, 0, p); 6383148Sphk *vpp = dp; 6393148Sphk if (cnp->cn_flags & SAVESTART) 6403148Sphk panic("lookup: SAVESTART"); 6413148Sphk return (0); 6423148Sphk } 6433148Sphk 6443148Sphk if (cnp->cn_flags & ISDOTDOT) 6453148Sphk panic ("relookup: lookup on dot-dot"); 6463148Sphk 6473148Sphk /* 6483148Sphk * We now have a segment name to search for, and a directory to search. 6493148Sphk */ 65043311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 65142408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 6523148Sphk if (error != EJUSTRETURN) 6533148Sphk goto bad; 6543148Sphk /* 6553148Sphk * If creating and at end of pathname, then can consider 6563148Sphk * allowing file to be created. 6573148Sphk */ 65811644Sdg if (rdonly) { 6593148Sphk error = EROFS; 6603148Sphk goto bad; 6613148Sphk } 6623148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 6633148Sphk if (cnp->cn_flags & SAVESTART) 6643148Sphk VREF(dvp); 6653148Sphk /* 6663148Sphk * We return with ni_vp NULL to indicate that the entry 6673148Sphk * doesn't currently exist, leaving a pointer to the 6683148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 6693148Sphk */ 6703148Sphk return (0); 6713148Sphk } 6723148Sphk dp = *vpp; 6733148Sphk 6743148Sphk /* 6753148Sphk * Check for symbolic link 6763148Sphk */ 67742408Seivind KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 67842453Seivind ("relookup: symlink found.\n")); 6793148Sphk 6803148Sphk /* 68111644Sdg * Disallow directory write attempts on read-only file systems. 6823148Sphk */ 68311644Sdg if (rdonly && 68411644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 68511644Sdg error = EROFS; 68611644Sdg goto bad2; 6873148Sphk } 6883148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 6893148Sphk if (cnp->cn_flags & SAVESTART) 6903148Sphk VREF(dvp); 69122521Sdyson 6923148Sphk if (!wantparent) 6933148Sphk vrele(dvp); 69432071Sdyson 69549101Salc if (vn_canvmio(dp) == TRUE && 69632286Sdyson ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF)) 69742315Seivind vfs_object_create(dp, cnp->cn_proc, cnp->cn_cred); 69832071Sdyson 6993148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 70022521Sdyson VOP_UNLOCK(dp, 0, p); 7013148Sphk return (0); 7023148Sphk 7033148Sphkbad2: 7043148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 70522521Sdyson VOP_UNLOCK(dvp, 0, p); 7063148Sphk vrele(dvp); 7073148Sphkbad: 7083148Sphk vput(dp); 7093148Sphk *vpp = NULL; 7103148Sphk return (error); 7113148Sphk} 712