vfs_lookup.c revision 116182
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 391541Srgrimes */ 401541Srgrimes 41116182Sobrien#include <sys/cdefs.h> 42116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_lookup.c 116182 2003-06-11 00:56:59Z obrien $"); 43116182Sobrien 4413203Swollman#include "opt_ktrace.h" 45101127Srwatson#include "opt_mac.h" 4613203Swollman 471541Srgrimes#include <sys/param.h> 482112Swollman#include <sys/systm.h> 4969664Speter#include <sys/kernel.h> 5076166Smarkm#include <sys/lock.h> 51101127Srwatson#include <sys/mac.h> 5289316Salfred#include <sys/mutex.h> 531541Srgrimes#include <sys/namei.h> 541541Srgrimes#include <sys/vnode.h> 551541Srgrimes#include <sys/mount.h> 561541Srgrimes#include <sys/filedesc.h> 571541Srgrimes#include <sys/proc.h> 581541Srgrimes#ifdef KTRACE 591541Srgrimes#include <sys/ktrace.h> 601541Srgrimes#endif 611541Srgrimes 6292751Sjeff#include <vm/uma.h> 6332011Sbde 641541Srgrimes/* 6569664Speter * Allocation zone for namei 6669664Speter */ 6792751Sjeffuma_zone_t namei_zone; 6869664Speter 6969664Speterstatic void 7069664Speternameiinit(void *dummy __unused) 7169664Speter{ 7292654Sjeff namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, 7392654Sjeff UMA_ALIGN_PTR, 0); 7469664Speter 7569664Speter} 7669664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 7769664Speter 7869664Speter/* 791541Srgrimes * Convert a pathname into a pointer to a locked inode. 801541Srgrimes * 811541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 821541Srgrimes * when they occur at the end of the name translation process. 831541Srgrimes * Symbolic links are always followed for all other pathname 841541Srgrimes * components other than the last. 851541Srgrimes * 861541Srgrimes * The segflg defines whether the name is to be copied from user 871541Srgrimes * space or kernel space. 881541Srgrimes * 891541Srgrimes * Overall outline of namei: 901541Srgrimes * 911541Srgrimes * copy in name 921541Srgrimes * get starting directory 931541Srgrimes * while (!done && !error) { 941541Srgrimes * call lookup to search path. 951541Srgrimes * if symbolic link, massage name in buffer and continue 961541Srgrimes * } 971541Srgrimes */ 981541Srgrimesint 991541Srgrimesnamei(ndp) 1001541Srgrimes register struct nameidata *ndp; 1011541Srgrimes{ 1021541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 1031541Srgrimes register char *cp; /* pointer into pathname argument */ 1041541Srgrimes register struct vnode *dp; /* the directory we are searching */ 1051541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1061541Srgrimes struct uio auio; 1071541Srgrimes int error, linklen; 1081541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 10983366Sjulian struct thread *td = cnp->cn_thread; 11083366Sjulian struct proc *p = td->td_proc; 1111541Srgrimes 11291419Sjhb ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; 11383366Sjulian KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); 11442408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 11542453Seivind ("namei: nameiop contaminated with flags")); 11642408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 11742453Seivind ("namei: flags contaminated with nameiops")); 11883366Sjulian fdp = p->p_fd; 1191541Srgrimes 1201541Srgrimes /* 1211541Srgrimes * Get a buffer for the name to be translated, and copy the 1221541Srgrimes * name into the buffer. 1231541Srgrimes */ 1241541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 125111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 1261541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1271541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 12836735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1291541Srgrimes else 1301541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 13136735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 13220069Sbde 13320069Sbde /* 13420069Sbde * Don't allow empty pathnames. 13520069Sbde */ 13620069Sbde if (!error && *cnp->cn_pnbuf == '\0') 13720069Sbde error = ENOENT; 13820069Sbde 1391541Srgrimes if (error) { 14092751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 141100613Srwatson#ifdef DIAGNOSTIC 142100613Srwatson cnp->cn_pnbuf = NULL; 143100613Srwatson cnp->cn_nameptr = NULL; 144100613Srwatson#endif 1451541Srgrimes ndp->ni_vp = NULL; 1461541Srgrimes return (error); 1471541Srgrimes } 1481541Srgrimes ndp->ni_loopcnt = 0; 1491541Srgrimes#ifdef KTRACE 15097994Sjhb if (KTRPOINT(td, KTR_NAMEI)) { 15197994Sjhb KASSERT(cnp->cn_thread == curthread, 15297994Sjhb ("namei not using curthread")); 15397994Sjhb ktrnamei(cnp->cn_pnbuf); 15497994Sjhb } 1551541Srgrimes#endif 1561541Srgrimes 1571541Srgrimes /* 1581541Srgrimes * Get starting point for the translation. 1591541Srgrimes */ 16089306Salfred FILEDESC_LOCK(fdp); 16133360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 16251649Sphk ndp->ni_topdir = fdp->fd_jdir; 16333360Sdyson 1641541Srgrimes dp = fdp->fd_cdir; 1651541Srgrimes VREF(dp); 16689306Salfred FILEDESC_UNLOCK(fdp); 1671541Srgrimes for (;;) { 1681541Srgrimes /* 1691541Srgrimes * Check if root directory should replace current directory. 1701541Srgrimes * Done at start of translation and after symbolic link. 1711541Srgrimes */ 1721541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1731541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1741541Srgrimes vrele(dp); 1751541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1761541Srgrimes cnp->cn_nameptr++; 1771541Srgrimes ndp->ni_pathlen--; 1781541Srgrimes } 1791541Srgrimes dp = ndp->ni_rootdir; 1801541Srgrimes VREF(dp); 1811541Srgrimes } 1821541Srgrimes ndp->ni_startdir = dp; 1833148Sphk error = lookup(ndp); 1843148Sphk if (error) { 18592751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 186100613Srwatson#ifdef DIAGNOSTIC 187100613Srwatson cnp->cn_pnbuf = NULL; 188100613Srwatson cnp->cn_nameptr = NULL; 189100613Srwatson#endif 1901541Srgrimes return (error); 1911541Srgrimes } 1921541Srgrimes /* 1931541Srgrimes * Check for symbolic link 1941541Srgrimes */ 1951541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 196100613Srwatson if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 19792751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 198100613Srwatson#ifdef DIAGNOSTIC 199100613Srwatson cnp->cn_pnbuf = NULL; 200100613Srwatson cnp->cn_nameptr = NULL; 201100613Srwatson#endif 202100613Srwatson } else 2031541Srgrimes cnp->cn_flags |= HASBUF; 20432286Sdyson 20549101Salc if (vn_canvmio(ndp->ni_vp) == TRUE && 20632286Sdyson (cnp->cn_nameiop != DELETE) && 20742315Seivind ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == 20842315Seivind LOCKLEAF)) 20983366Sjulian vfs_object_create(ndp->ni_vp, td, 21042315Seivind ndp->ni_cnd.cn_cred); 21132286Sdyson 2121541Srgrimes return (0); 2131541Srgrimes } 2141541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 21583366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 2161541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2171541Srgrimes error = ELOOP; 2181541Srgrimes break; 2191541Srgrimes } 220101127Srwatson#ifdef MAC 221105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 222105479Srwatson error = mac_check_vnode_readlink(td->td_ucred, 223105479Srwatson ndp->ni_vp); 224105479Srwatson if (error) 225105479Srwatson break; 226105479Srwatson } 227101127Srwatson#endif 2281541Srgrimes if (ndp->ni_pathlen > 1) 229111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 2301541Srgrimes else 2311541Srgrimes cp = cnp->cn_pnbuf; 2321541Srgrimes aiov.iov_base = cp; 2331541Srgrimes aiov.iov_len = MAXPATHLEN; 2341541Srgrimes auio.uio_iov = &aiov; 2351541Srgrimes auio.uio_iovcnt = 1; 2361541Srgrimes auio.uio_offset = 0; 2371541Srgrimes auio.uio_rw = UIO_READ; 2381541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 23983366Sjulian auio.uio_td = (struct thread *)0; 2401541Srgrimes auio.uio_resid = MAXPATHLEN; 2413148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2423148Sphk if (error) { 2431541Srgrimes if (ndp->ni_pathlen > 1) 24492751Sjeff uma_zfree(namei_zone, cp); 2451541Srgrimes break; 2461541Srgrimes } 2471541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 24878692Sdillon if (linklen == 0) { 24978692Sdillon if (ndp->ni_pathlen > 1) 25092751Sjeff uma_zfree(namei_zone, cp); 25178692Sdillon error = ENOENT; 25278692Sdillon break; 25378692Sdillon } 2541541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2551541Srgrimes if (ndp->ni_pathlen > 1) 25692751Sjeff uma_zfree(namei_zone, cp); 2571541Srgrimes error = ENAMETOOLONG; 2581541Srgrimes break; 2591541Srgrimes } 2601541Srgrimes if (ndp->ni_pathlen > 1) { 2611541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 26292751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 2631541Srgrimes cnp->cn_pnbuf = cp; 2641541Srgrimes } else 2651541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2661541Srgrimes ndp->ni_pathlen += linklen; 2671541Srgrimes vput(ndp->ni_vp); 2681541Srgrimes dp = ndp->ni_dvp; 2691541Srgrimes } 27092751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 271100613Srwatson#ifdef DIAGNOSTIC 272100613Srwatson cnp->cn_pnbuf = NULL; 273100613Srwatson cnp->cn_nameptr = NULL; 274100613Srwatson#endif 2751541Srgrimes vrele(ndp->ni_dvp); 2761541Srgrimes vput(ndp->ni_vp); 2771541Srgrimes ndp->ni_vp = NULL; 2781541Srgrimes return (error); 2791541Srgrimes} 2801541Srgrimes 2811541Srgrimes/* 2821541Srgrimes * Search a pathname. 2831541Srgrimes * This is a very central and rather complicated routine. 2841541Srgrimes * 2851541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2861541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2871541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2881541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2891541Srgrimes * symbolic link needing interpretation is encountered. 2901541Srgrimes * 2911541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 2921541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 2931541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 2941541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 2951541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 2961541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 2971541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 2981541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 2991541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 3001541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 3011541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 3028876Srgrimes * 3031541Srgrimes * Overall outline of lookup: 3041541Srgrimes * 3051541Srgrimes * dirloop: 3061541Srgrimes * identify next component of name at ndp->ni_ptr 3071541Srgrimes * handle degenerate case where name is null string 3081541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 3091541Srgrimes * call VOP_LOOKUP routine for next component name 3101541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 3111541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 3121541Srgrimes * if result vnode is mounted on and crossing mount points, 3131541Srgrimes * find mounted on vnode 3141541Srgrimes * if more components of name, do next level at dirloop 3151541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 3161541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 3171541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 3181541Srgrimes */ 3191541Srgrimesint 3201541Srgrimeslookup(ndp) 3211541Srgrimes register struct nameidata *ndp; 3221541Srgrimes{ 3231541Srgrimes register char *cp; /* pointer into pathname argument */ 3241541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 3251541Srgrimes struct vnode *tdp; /* saved dp */ 3261541Srgrimes struct mount *mp; /* mount table entry */ 3271541Srgrimes int docache; /* == 0 do not cache last component */ 3281541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 3291541Srgrimes int rdonly; /* lookup read-only flag bit */ 3309804Sbde int trailing_slash; 3311541Srgrimes int error = 0; 33265805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 3331541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 33483366Sjulian struct thread *td = cnp->cn_thread; 3351541Srgrimes 3361541Srgrimes /* 3371541Srgrimes * Setup: break out flag bits into variables. 3381541Srgrimes */ 3391541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 3401541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3411541Srgrimes if (cnp->cn_nameiop == DELETE || 34222874Sbde (wantparent && cnp->cn_nameiop != CREATE && 34322874Sbde cnp->cn_nameiop != LOOKUP)) 3441541Srgrimes docache = 0; 3451541Srgrimes rdonly = cnp->cn_flags & RDONLY; 3461541Srgrimes ndp->ni_dvp = NULL; 3471541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 3481541Srgrimes dp = ndp->ni_startdir; 3491541Srgrimes ndp->ni_startdir = NULLVP; 35083366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 3511541Srgrimes 3521541Srgrimesdirloop: 3531541Srgrimes /* 3541541Srgrimes * Search a new directory. 3551541Srgrimes * 3561541Srgrimes * The last component of the filename is left accessible via 3571541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3581541Srgrimes * the name set the SAVENAME flag. When done, they assume 3591541Srgrimes * responsibility for freeing the pathname buffer. 3601541Srgrimes */ 3611541Srgrimes cnp->cn_consume = 0; 3621541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 36351906Sphk continue; 3641541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3651541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3661541Srgrimes error = ENAMETOOLONG; 3671541Srgrimes goto bad; 3681541Srgrimes } 3691541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3701541Srgrimes { char c = *cp; 3711541Srgrimes *cp = '\0'; 3721541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3731541Srgrimes *cp = c; } 3741541Srgrimes#endif 3751541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3761541Srgrimes ndp->ni_next = cp; 3779804Sbde 3789804Sbde /* 3799804Sbde * Replace multiple slashes by a single slash and trailing slashes 3809804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3819804Sbde * fs's don't know about trailing slashes. Remember if there were 3829804Sbde * trailing slashes to handle symlinks, existing non-directories 3839804Sbde * and non-existing files that won't be directories specially later. 3849804Sbde */ 3859804Sbde trailing_slash = 0; 3869804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 3879804Sbde cp++; 3889804Sbde ndp->ni_pathlen--; 3899804Sbde if (*cp == '\0') { 3909804Sbde trailing_slash = 1; 3919804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 3929804Sbde } 3939804Sbde } 3949804Sbde ndp->ni_next = cp; 3959804Sbde 3961541Srgrimes cnp->cn_flags |= MAKEENTRY; 3971541Srgrimes if (*cp == '\0' && docache == 0) 3981541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 3991541Srgrimes if (cnp->cn_namelen == 2 && 4001541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 4011541Srgrimes cnp->cn_flags |= ISDOTDOT; 4021541Srgrimes else 4031541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 4041541Srgrimes if (*ndp->ni_next == 0) 4051541Srgrimes cnp->cn_flags |= ISLASTCN; 4061541Srgrimes else 4071541Srgrimes cnp->cn_flags &= ~ISLASTCN; 4081541Srgrimes 4091541Srgrimes 4101541Srgrimes /* 4111541Srgrimes * Check for degenerate name (e.g. / or "") 4121541Srgrimes * which is a way of talking about a directory, 4131541Srgrimes * e.g. like "/." or ".". 4141541Srgrimes */ 4151541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 41622521Sdyson if (dp->v_type != VDIR) { 41722521Sdyson error = ENOTDIR; 41822521Sdyson goto bad; 41922521Sdyson } 4201541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 4211541Srgrimes error = EISDIR; 4221541Srgrimes goto bad; 4231541Srgrimes } 4241541Srgrimes if (wantparent) { 4251541Srgrimes ndp->ni_dvp = dp; 4261541Srgrimes VREF(dp); 4271541Srgrimes } 4281541Srgrimes ndp->ni_vp = dp; 4291541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 43083366Sjulian VOP_UNLOCK(dp, 0, td); 43154655Seivind /* XXX This should probably move to the top of function. */ 4321541Srgrimes if (cnp->cn_flags & SAVESTART) 4331541Srgrimes panic("lookup: SAVESTART"); 4341541Srgrimes return (0); 4351541Srgrimes } 4361541Srgrimes 4371541Srgrimes /* 4381541Srgrimes * Handle "..": two special cases. 4391541Srgrimes * 1. If at root directory (e.g. after chroot) 4401541Srgrimes * or at absolute root directory 4411541Srgrimes * then ignore it so can't get out. 4421541Srgrimes * 2. If this vnode is the root of a mounted 4431541Srgrimes * filesystem, then replace it with the 4441541Srgrimes * vnode which was mounted on so we take the 44596755Strhodes * .. in the other filesystem. 44651649Sphk * 3. If the vnode is the top directory of 44751649Sphk * the jail or chroot, don't let them out. 4481541Srgrimes */ 4491541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 4501541Srgrimes for (;;) { 45151649Sphk if (dp == ndp->ni_rootdir || 45251649Sphk dp == ndp->ni_topdir || 45351649Sphk dp == rootvnode) { 4541541Srgrimes ndp->ni_dvp = dp; 4551541Srgrimes ndp->ni_vp = dp; 4561541Srgrimes VREF(dp); 4571541Srgrimes goto nextname; 4581541Srgrimes } 459101308Sjeff if ((dp->v_vflag & VV_ROOT) == 0 || 4601541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 4611541Srgrimes break; 46269405Salfred if (dp->v_mount == NULL) { /* forced unmount */ 46369405Salfred error = EBADF; 46469405Salfred goto bad; 46569405Salfred } 4661541Srgrimes tdp = dp; 4671541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4681541Srgrimes vput(tdp); 4691541Srgrimes VREF(dp); 47083366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 4711541Srgrimes } 4721541Srgrimes } 4731541Srgrimes 4741541Srgrimes /* 4751541Srgrimes * We now have a segment name to search for, and a directory to search. 4761541Srgrimes */ 4771541Srgrimesunionlookup: 478101127Srwatson#ifdef MAC 479105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 480105479Srwatson error = mac_check_vnode_lookup(td->td_ucred, dp, cnp); 481105479Srwatson if (error) 482105479Srwatson goto bad; 483105479Srwatson } 484101127Srwatson#endif 4851541Srgrimes ndp->ni_dvp = dp; 48622521Sdyson ndp->ni_vp = NULL; 48765973Sbp cnp->cn_flags &= ~PDIRUNLOCK; 48824624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 48943301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 49042408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 4911541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4921541Srgrimes printf("not found\n"); 4931541Srgrimes#endif 4941541Srgrimes if ((error == ENOENT) && 495101308Sjeff (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && 4961541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 4971541Srgrimes tdp = dp; 4981541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 49965973Sbp if (cnp->cn_flags & PDIRUNLOCK) 50065973Sbp vrele(tdp); 50165973Sbp else 50265973Sbp vput(tdp); 5031541Srgrimes VREF(dp); 50483366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 5051541Srgrimes goto unionlookup; 5061541Srgrimes } 5071541Srgrimes 5081541Srgrimes if (error != EJUSTRETURN) 5091541Srgrimes goto bad; 5101541Srgrimes /* 5111541Srgrimes * If creating and at end of pathname, then can consider 5121541Srgrimes * allowing file to be created. 5131541Srgrimes */ 51411644Sdg if (rdonly) { 5151541Srgrimes error = EROFS; 5161541Srgrimes goto bad; 5171541Srgrimes } 5189804Sbde if (*cp == '\0' && trailing_slash && 5199804Sbde !(cnp->cn_flags & WILLBEDIR)) { 5209804Sbde error = ENOENT; 5219804Sbde goto bad; 5229804Sbde } 5231541Srgrimes /* 5241541Srgrimes * We return with ni_vp NULL to indicate that the entry 5251541Srgrimes * doesn't currently exist, leaving a pointer to the 5261541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 5271541Srgrimes */ 5281541Srgrimes if (cnp->cn_flags & SAVESTART) { 5291541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5301541Srgrimes VREF(ndp->ni_startdir); 5311541Srgrimes } 5321541Srgrimes return (0); 5331541Srgrimes } 5341541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5351541Srgrimes printf("found\n"); 5361541Srgrimes#endif 5371541Srgrimes 53824624Sdfr ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); 53924624Sdfr 5401541Srgrimes /* 5411541Srgrimes * Take into account any additional components consumed by 5421541Srgrimes * the underlying filesystem. 5431541Srgrimes */ 5441541Srgrimes if (cnp->cn_consume > 0) { 5451541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 5461541Srgrimes ndp->ni_next += cnp->cn_consume; 5471541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 5481541Srgrimes cnp->cn_consume = 0; 5491541Srgrimes } 5501541Srgrimes 5511541Srgrimes dp = ndp->ni_vp; 5521541Srgrimes 5531541Srgrimes /* 5541541Srgrimes * Check to see if the vnode has been mounted on; 55596755Strhodes * if so find the root of the mounted filesystem. 5561541Srgrimes */ 5571541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 5581541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 55983366Sjulian if (vfs_busy(mp, 0, 0, td)) 5601541Srgrimes continue; 56183366Sjulian VOP_UNLOCK(dp, 0, td); 56222521Sdyson error = VFS_ROOT(mp, &tdp); 56383366Sjulian vfs_unbusy(mp, td); 56465805Sbp if (error) { 56565805Sbp dpunlocked = 1; 5661541Srgrimes goto bad2; 56765805Sbp } 56865805Sbp vrele(dp); 5691541Srgrimes ndp->ni_vp = dp = tdp; 5701541Srgrimes } 5711541Srgrimes 57210219Sdfr /* 57310219Sdfr * Check for symbolic link 57410219Sdfr */ 57510219Sdfr if ((dp->v_type == VLNK) && 57610219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 57710219Sdfr *ndp->ni_next == '/')) { 57810219Sdfr cnp->cn_flags |= ISSYMLINK; 57969405Salfred if (dp->v_mount == NULL) { 58069405Salfred /* We can't know whether the directory was mounted with 58169405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 58269405Salfred error = EBADF; 58369405Salfred goto bad2; 58469405Salfred } 58535105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 58635105Swosch error = EACCES; 58735105Swosch goto bad2; 58835105Swosch } 58910219Sdfr return (0); 59010219Sdfr } 59110219Sdfr 59210219Sdfr /* 59310219Sdfr * Check for bogus trailing slashes. 59410219Sdfr */ 59510219Sdfr if (trailing_slash && dp->v_type != VDIR) { 59610219Sdfr error = ENOTDIR; 59710219Sdfr goto bad2; 59810219Sdfr } 59910219Sdfr 6001541Srgrimesnextname: 6011541Srgrimes /* 6021541Srgrimes * Not a symbolic link. If more pathname, 6031541Srgrimes * continue at next component, else return. 6041541Srgrimes */ 6051541Srgrimes if (*ndp->ni_next == '/') { 6061541Srgrimes cnp->cn_nameptr = ndp->ni_next; 6071541Srgrimes while (*cnp->cn_nameptr == '/') { 6081541Srgrimes cnp->cn_nameptr++; 6091541Srgrimes ndp->ni_pathlen--; 6101541Srgrimes } 61154655Seivind if (ndp->ni_dvp != ndp->ni_vp) 61254655Seivind ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); 6131541Srgrimes vrele(ndp->ni_dvp); 6141541Srgrimes goto dirloop; 6151541Srgrimes } 6161541Srgrimes /* 61796755Strhodes * Disallow directory write attempts on read-only filesystems. 6181541Srgrimes */ 61911644Sdg if (rdonly && 62011644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 62111644Sdg error = EROFS; 62211644Sdg goto bad2; 6231541Srgrimes } 6241541Srgrimes if (cnp->cn_flags & SAVESTART) { 6251541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 6261541Srgrimes VREF(ndp->ni_startdir); 6271541Srgrimes } 6281541Srgrimes if (!wantparent) 6291541Srgrimes vrele(ndp->ni_dvp); 63032071Sdyson 6311541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 63283366Sjulian VOP_UNLOCK(dp, 0, td); 6331541Srgrimes return (0); 6341541Srgrimes 6351541Srgrimesbad2: 63665973Sbp if ((cnp->cn_flags & (LOCKPARENT | PDIRUNLOCK)) == LOCKPARENT && 63765973Sbp *ndp->ni_next == '\0') 63883366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 6391541Srgrimes vrele(ndp->ni_dvp); 6401541Srgrimesbad: 64165805Sbp if (dpunlocked) 64265805Sbp vrele(dp); 64365805Sbp else 64465805Sbp vput(dp); 6451541Srgrimes ndp->ni_vp = NULL; 6461541Srgrimes return (error); 6471541Srgrimes} 6481541Srgrimes 6493148Sphk/* 6503148Sphk * relookup - lookup a path name component 6513148Sphk * Used by lookup to re-aquire things. 6523148Sphk */ 6533148Sphkint 6543148Sphkrelookup(dvp, vpp, cnp) 6553148Sphk struct vnode *dvp, **vpp; 6563148Sphk struct componentname *cnp; 6573148Sphk{ 65883366Sjulian struct thread *td = cnp->cn_thread; 65922521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 6603148Sphk int docache; /* == 0 do not cache last component */ 6613148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 6623148Sphk int rdonly; /* lookup read-only flag bit */ 6633148Sphk int error = 0; 6643148Sphk#ifdef NAMEI_DIAGNOSTIC 6653148Sphk int newhash; /* DEBUG: check name hash */ 6663148Sphk char *cp; /* DEBUG: check name ptr/len */ 6673148Sphk#endif 6681541Srgrimes 6693148Sphk /* 6703148Sphk * Setup: break out flag bits into variables. 6713148Sphk */ 6723148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 6733148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 6743148Sphk if (cnp->cn_nameiop == DELETE || 6753148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 6763148Sphk docache = 0; 6773148Sphk rdonly = cnp->cn_flags & RDONLY; 6783148Sphk cnp->cn_flags &= ~ISSYMLINK; 6793148Sphk dp = dvp; 68083366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 6813148Sphk 6823148Sphk/* dirloop: */ 6833148Sphk /* 6843148Sphk * Search a new directory. 6853148Sphk * 6863148Sphk * The last component of the filename is left accessible via 6873148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 6883148Sphk * the name set the SAVENAME flag. When done, they assume 6893148Sphk * responsibility for freeing the pathname buffer. 6903148Sphk */ 6913148Sphk#ifdef NAMEI_DIAGNOSTIC 6923148Sphk if (cnp->cn_namelen != cp - cnp->cn_nameptr) 6933148Sphk panic ("relookup: bad len"); 6943148Sphk if (*cp != 0) 6953148Sphk panic("relookup: not last component"); 6963148Sphk printf("{%s}: ", cnp->cn_nameptr); 6973148Sphk#endif 6983148Sphk 6993148Sphk /* 7003148Sphk * Check for degenerate name (e.g. / or "") 7013148Sphk * which is a way of talking about a directory, 7023148Sphk * e.g. like "/." or ".". 7033148Sphk */ 7043148Sphk if (cnp->cn_nameptr[0] == '\0') { 7053148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 7063148Sphk error = EISDIR; 7073148Sphk goto bad; 7083148Sphk } 7093148Sphk if (dp->v_type != VDIR) { 7103148Sphk error = ENOTDIR; 7113148Sphk goto bad; 7123148Sphk } 7133148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 71483366Sjulian VOP_UNLOCK(dp, 0, td); 7153148Sphk *vpp = dp; 71654655Seivind /* XXX This should probably move to the top of function. */ 7173148Sphk if (cnp->cn_flags & SAVESTART) 7183148Sphk panic("lookup: SAVESTART"); 7193148Sphk return (0); 7203148Sphk } 7213148Sphk 7223148Sphk if (cnp->cn_flags & ISDOTDOT) 7233148Sphk panic ("relookup: lookup on dot-dot"); 7243148Sphk 7253148Sphk /* 7263148Sphk * We now have a segment name to search for, and a directory to search. 7273148Sphk */ 72843311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 72942408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 7303148Sphk if (error != EJUSTRETURN) 7313148Sphk goto bad; 7323148Sphk /* 7333148Sphk * If creating and at end of pathname, then can consider 7343148Sphk * allowing file to be created. 7353148Sphk */ 73611644Sdg if (rdonly) { 7373148Sphk error = EROFS; 7383148Sphk goto bad; 7393148Sphk } 7403148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7413148Sphk if (cnp->cn_flags & SAVESTART) 7423148Sphk VREF(dvp); 7433148Sphk /* 7443148Sphk * We return with ni_vp NULL to indicate that the entry 7453148Sphk * doesn't currently exist, leaving a pointer to the 7463148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 7473148Sphk */ 7483148Sphk return (0); 7493148Sphk } 7503148Sphk dp = *vpp; 7513148Sphk 7523148Sphk /* 7533148Sphk * Check for symbolic link 7543148Sphk */ 75542408Seivind KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 75642453Seivind ("relookup: symlink found.\n")); 7573148Sphk 7583148Sphk /* 75996755Strhodes * Disallow directory write attempts on read-only filesystems. 7603148Sphk */ 76111644Sdg if (rdonly && 76211644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 76311644Sdg error = EROFS; 76411644Sdg goto bad2; 7653148Sphk } 7663148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7673148Sphk if (cnp->cn_flags & SAVESTART) 7683148Sphk VREF(dvp); 76922521Sdyson 7703148Sphk if (!wantparent) 7713148Sphk vrele(dvp); 77232071Sdyson 77349101Salc if (vn_canvmio(dp) == TRUE && 77432286Sdyson ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF)) 77583366Sjulian vfs_object_create(dp, td, cnp->cn_cred); 77632071Sdyson 7773148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 77883366Sjulian VOP_UNLOCK(dp, 0, td); 7793148Sphk return (0); 7803148Sphk 7813148Sphkbad2: 7823148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 78383366Sjulian VOP_UNLOCK(dvp, 0, td); 7843148Sphk vrele(dvp); 7853148Sphkbad: 7863148Sphk vput(dp); 7873148Sphk *vpp = NULL; 7883148Sphk return (error); 7893148Sphk} 790