vfs_lookup.c revision 140714
1139804Simp/*- 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 * 4. Neither the name of the University nor the names of its contributors 191541Srgrimes * may be used to endorse or promote products derived from this software 201541Srgrimes * without specific prior written permission. 211541Srgrimes * 221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321541Srgrimes * SUCH DAMAGE. 331541Srgrimes * 341541Srgrimes * @(#)vfs_lookup.c 8.4 (Berkeley) 2/16/94 351541Srgrimes */ 361541Srgrimes 37116182Sobrien#include <sys/cdefs.h> 38116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_lookup.c 140714 2005-01-24 10:27:05Z jeff $"); 39116182Sobrien 4013203Swollman#include "opt_ktrace.h" 41101127Srwatson#include "opt_mac.h" 4213203Swollman 431541Srgrimes#include <sys/param.h> 442112Swollman#include <sys/systm.h> 4569664Speter#include <sys/kernel.h> 4676166Smarkm#include <sys/lock.h> 47101127Srwatson#include <sys/mac.h> 4889316Salfred#include <sys/mutex.h> 491541Srgrimes#include <sys/namei.h> 501541Srgrimes#include <sys/vnode.h> 511541Srgrimes#include <sys/mount.h> 521541Srgrimes#include <sys/filedesc.h> 531541Srgrimes#include <sys/proc.h> 541541Srgrimes#ifdef KTRACE 551541Srgrimes#include <sys/ktrace.h> 561541Srgrimes#endif 571541Srgrimes 5892751Sjeff#include <vm/uma.h> 5932011Sbde 60138345Sphk#define NAMEI_DIAGNOSTIC 1 61138345Sphk#undef NAMEI_DIAGNOSTIC 62138345Sphk 631541Srgrimes/* 6469664Speter * Allocation zone for namei 6569664Speter */ 6692751Sjeffuma_zone_t namei_zone; 6769664Speter 6869664Speterstatic void 6969664Speternameiinit(void *dummy __unused) 7069664Speter{ 7192654Sjeff namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, 7292654Sjeff UMA_ALIGN_PTR, 0); 7369664Speter 7469664Speter} 7569664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 7669664Speter 7769664Speter/* 781541Srgrimes * Convert a pathname into a pointer to a locked inode. 791541Srgrimes * 801541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 811541Srgrimes * when they occur at the end of the name translation process. 821541Srgrimes * Symbolic links are always followed for all other pathname 831541Srgrimes * components other than the last. 841541Srgrimes * 851541Srgrimes * The segflg defines whether the name is to be copied from user 861541Srgrimes * space or kernel space. 871541Srgrimes * 881541Srgrimes * Overall outline of namei: 891541Srgrimes * 901541Srgrimes * copy in name 911541Srgrimes * get starting directory 921541Srgrimes * while (!done && !error) { 931541Srgrimes * call lookup to search path. 941541Srgrimes * if symbolic link, massage name in buffer and continue 951541Srgrimes * } 961541Srgrimes */ 971541Srgrimesint 981541Srgrimesnamei(ndp) 991541Srgrimes register struct nameidata *ndp; 1001541Srgrimes{ 1011541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 1021541Srgrimes register char *cp; /* pointer into pathname argument */ 1031541Srgrimes register struct vnode *dp; /* the directory we are searching */ 1041541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1051541Srgrimes struct uio auio; 1061541Srgrimes int error, linklen; 1071541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 10883366Sjulian struct thread *td = cnp->cn_thread; 10983366Sjulian struct proc *p = td->td_proc; 110140714Sjeff struct mount *mp; 111140714Sjeff int vfslocked; 1121541Srgrimes 11391419Sjhb ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; 11483366Sjulian KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); 11542408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 11642453Seivind ("namei: nameiop contaminated with flags")); 11742408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 11842453Seivind ("namei: flags contaminated with nameiops")); 11983366Sjulian fdp = p->p_fd; 1201541Srgrimes 1211541Srgrimes /* 1221541Srgrimes * Get a buffer for the name to be translated, and copy the 1231541Srgrimes * name into the buffer. 1241541Srgrimes */ 1251541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 126111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 1271541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1281541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 12936735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1301541Srgrimes else 1311541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 13236735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 13320069Sbde 13420069Sbde /* 13520069Sbde * Don't allow empty pathnames. 13620069Sbde */ 13720069Sbde if (!error && *cnp->cn_pnbuf == '\0') 13820069Sbde error = ENOENT; 13920069Sbde 1401541Srgrimes if (error) { 14192751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 142100613Srwatson#ifdef DIAGNOSTIC 143100613Srwatson cnp->cn_pnbuf = NULL; 144100613Srwatson cnp->cn_nameptr = NULL; 145100613Srwatson#endif 1461541Srgrimes ndp->ni_vp = NULL; 1471541Srgrimes return (error); 1481541Srgrimes } 1491541Srgrimes ndp->ni_loopcnt = 0; 1501541Srgrimes#ifdef KTRACE 15197994Sjhb if (KTRPOINT(td, KTR_NAMEI)) { 15297994Sjhb KASSERT(cnp->cn_thread == curthread, 15397994Sjhb ("namei not using curthread")); 15497994Sjhb ktrnamei(cnp->cn_pnbuf); 15597994Sjhb } 1561541Srgrimes#endif 1571541Srgrimes 1581541Srgrimes /* 1591541Srgrimes * Get starting point for the translation. 1601541Srgrimes */ 16189306Salfred FILEDESC_LOCK(fdp); 16233360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 16351649Sphk ndp->ni_topdir = fdp->fd_jdir; 16433360Sdyson 1651541Srgrimes dp = fdp->fd_cdir; 166140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1671541Srgrimes VREF(dp); 16889306Salfred FILEDESC_UNLOCK(fdp); 1691541Srgrimes for (;;) { 1701541Srgrimes /* 1711541Srgrimes * Check if root directory should replace current directory. 1721541Srgrimes * Done at start of translation and after symbolic link. 1731541Srgrimes */ 1741541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1751541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1761541Srgrimes vrele(dp); 177140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 1781541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1791541Srgrimes cnp->cn_nameptr++; 1801541Srgrimes ndp->ni_pathlen--; 1811541Srgrimes } 1821541Srgrimes dp = ndp->ni_rootdir; 183140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1841541Srgrimes VREF(dp); 1851541Srgrimes } 186140714Sjeff if (vfslocked) 187140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 1881541Srgrimes ndp->ni_startdir = dp; 1893148Sphk error = lookup(ndp); 1903148Sphk if (error) { 19192751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 192100613Srwatson#ifdef DIAGNOSTIC 193100613Srwatson cnp->cn_pnbuf = NULL; 194100613Srwatson cnp->cn_nameptr = NULL; 195100613Srwatson#endif 1961541Srgrimes return (error); 1971541Srgrimes } 198140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 199140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 2001541Srgrimes /* 2011541Srgrimes * Check for symbolic link 2021541Srgrimes */ 2031541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 204100613Srwatson if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 20592751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 206100613Srwatson#ifdef DIAGNOSTIC 207100613Srwatson cnp->cn_pnbuf = NULL; 208100613Srwatson cnp->cn_nameptr = NULL; 209100613Srwatson#endif 210100613Srwatson } else 2111541Srgrimes cnp->cn_flags |= HASBUF; 21232286Sdyson 21349101Salc if (vn_canvmio(ndp->ni_vp) == TRUE && 21432286Sdyson (cnp->cn_nameiop != DELETE) && 21542315Seivind ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == 21642315Seivind LOCKLEAF)) 217140181Sphk VOP_CREATEVOBJECT(ndp->ni_vp, 218140181Sphk ndp->ni_cnd.cn_cred, td); 219140714Sjeff if ((cnp->cn_flags & MPSAFE) == 0) { 220140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 221140714Sjeff } else if (vfslocked) 222140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 2231541Srgrimes return (0); 2241541Srgrimes } 2251541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 22683366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 2271541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2281541Srgrimes error = ELOOP; 2291541Srgrimes break; 2301541Srgrimes } 231101127Srwatson#ifdef MAC 232105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 233105479Srwatson error = mac_check_vnode_readlink(td->td_ucred, 234105479Srwatson ndp->ni_vp); 235105479Srwatson if (error) 236105479Srwatson break; 237105479Srwatson } 238101127Srwatson#endif 2391541Srgrimes if (ndp->ni_pathlen > 1) 240111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 2411541Srgrimes else 2421541Srgrimes cp = cnp->cn_pnbuf; 2431541Srgrimes aiov.iov_base = cp; 2441541Srgrimes aiov.iov_len = MAXPATHLEN; 2451541Srgrimes auio.uio_iov = &aiov; 2461541Srgrimes auio.uio_iovcnt = 1; 2471541Srgrimes auio.uio_offset = 0; 2481541Srgrimes auio.uio_rw = UIO_READ; 2491541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 25083366Sjulian auio.uio_td = (struct thread *)0; 2511541Srgrimes auio.uio_resid = MAXPATHLEN; 2523148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2533148Sphk if (error) { 2541541Srgrimes if (ndp->ni_pathlen > 1) 25592751Sjeff uma_zfree(namei_zone, cp); 2561541Srgrimes break; 2571541Srgrimes } 2581541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 25978692Sdillon if (linklen == 0) { 26078692Sdillon if (ndp->ni_pathlen > 1) 26192751Sjeff uma_zfree(namei_zone, cp); 26278692Sdillon error = ENOENT; 26378692Sdillon break; 26478692Sdillon } 2651541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2661541Srgrimes if (ndp->ni_pathlen > 1) 26792751Sjeff uma_zfree(namei_zone, cp); 2681541Srgrimes error = ENAMETOOLONG; 2691541Srgrimes break; 2701541Srgrimes } 2711541Srgrimes if (ndp->ni_pathlen > 1) { 2721541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 27392751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 2741541Srgrimes cnp->cn_pnbuf = cp; 2751541Srgrimes } else 2761541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2771541Srgrimes ndp->ni_pathlen += linklen; 2781541Srgrimes vput(ndp->ni_vp); 2791541Srgrimes dp = ndp->ni_dvp; 2801541Srgrimes } 28192751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 282100613Srwatson#ifdef DIAGNOSTIC 283100613Srwatson cnp->cn_pnbuf = NULL; 284100613Srwatson cnp->cn_nameptr = NULL; 285100613Srwatson#endif 2861541Srgrimes vrele(ndp->ni_dvp); 287140714Sjeff mp = ndp->ni_vp->v_mount; 2881541Srgrimes vput(ndp->ni_vp); 289140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 2901541Srgrimes ndp->ni_vp = NULL; 2911541Srgrimes return (error); 2921541Srgrimes} 2931541Srgrimes 2941541Srgrimes/* 2951541Srgrimes * Search a pathname. 2961541Srgrimes * This is a very central and rather complicated routine. 2971541Srgrimes * 2981541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2991541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 3001541Srgrimes * descended until done, or a symbolic link is encountered. The variable 3011541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 3021541Srgrimes * symbolic link needing interpretation is encountered. 3031541Srgrimes * 3041541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 3051541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 3061541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 3071541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 3081541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 3091541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 3101541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 3111541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 3121541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 3131541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 3141541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 3158876Srgrimes * 3161541Srgrimes * Overall outline of lookup: 3171541Srgrimes * 3181541Srgrimes * dirloop: 3191541Srgrimes * identify next component of name at ndp->ni_ptr 3201541Srgrimes * handle degenerate case where name is null string 3211541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 3221541Srgrimes * call VOP_LOOKUP routine for next component name 3231541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 3241541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 3251541Srgrimes * if result vnode is mounted on and crossing mount points, 3261541Srgrimes * find mounted on vnode 3271541Srgrimes * if more components of name, do next level at dirloop 3281541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 3291541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 3301541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 3311541Srgrimes */ 3321541Srgrimesint 3331541Srgrimeslookup(ndp) 3341541Srgrimes register struct nameidata *ndp; 3351541Srgrimes{ 3361541Srgrimes register char *cp; /* pointer into pathname argument */ 3371541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 3381541Srgrimes struct vnode *tdp; /* saved dp */ 3391541Srgrimes struct mount *mp; /* mount table entry */ 3401541Srgrimes int docache; /* == 0 do not cache last component */ 3411541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 3421541Srgrimes int rdonly; /* lookup read-only flag bit */ 3439804Sbde int trailing_slash; 3441541Srgrimes int error = 0; 34565805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 3461541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 34783366Sjulian struct thread *td = cnp->cn_thread; 348140714Sjeff int vfslocked; 349140714Sjeff int tvfslocked; 3501541Srgrimes 3511541Srgrimes /* 3521541Srgrimes * Setup: break out flag bits into variables. 3531541Srgrimes */ 354140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 355140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 3561541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 3571541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3581541Srgrimes if (cnp->cn_nameiop == DELETE || 35922874Sbde (wantparent && cnp->cn_nameiop != CREATE && 36022874Sbde cnp->cn_nameiop != LOOKUP)) 3611541Srgrimes docache = 0; 3621541Srgrimes rdonly = cnp->cn_flags & RDONLY; 3631541Srgrimes ndp->ni_dvp = NULL; 3641541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 3651541Srgrimes dp = ndp->ni_startdir; 3661541Srgrimes ndp->ni_startdir = NULLVP; 36783366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 3681541Srgrimes 3691541Srgrimesdirloop: 3701541Srgrimes /* 3711541Srgrimes * Search a new directory. 3721541Srgrimes * 3731541Srgrimes * The last component of the filename is left accessible via 3741541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3751541Srgrimes * the name set the SAVENAME flag. When done, they assume 3761541Srgrimes * responsibility for freeing the pathname buffer. 3771541Srgrimes */ 3781541Srgrimes cnp->cn_consume = 0; 3791541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 38051906Sphk continue; 3811541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3821541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3831541Srgrimes error = ENAMETOOLONG; 3841541Srgrimes goto bad; 3851541Srgrimes } 3861541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3871541Srgrimes { char c = *cp; 3881541Srgrimes *cp = '\0'; 3891541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3901541Srgrimes *cp = c; } 3911541Srgrimes#endif 3921541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3931541Srgrimes ndp->ni_next = cp; 3949804Sbde 3959804Sbde /* 3969804Sbde * Replace multiple slashes by a single slash and trailing slashes 3979804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3989804Sbde * fs's don't know about trailing slashes. Remember if there were 3999804Sbde * trailing slashes to handle symlinks, existing non-directories 4009804Sbde * and non-existing files that won't be directories specially later. 4019804Sbde */ 4029804Sbde trailing_slash = 0; 4039804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 4049804Sbde cp++; 4059804Sbde ndp->ni_pathlen--; 4069804Sbde if (*cp == '\0') { 4079804Sbde trailing_slash = 1; 4089804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 4099804Sbde } 4109804Sbde } 4119804Sbde ndp->ni_next = cp; 4129804Sbde 4131541Srgrimes cnp->cn_flags |= MAKEENTRY; 4141541Srgrimes if (*cp == '\0' && docache == 0) 4151541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 4161541Srgrimes if (cnp->cn_namelen == 2 && 4171541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 4181541Srgrimes cnp->cn_flags |= ISDOTDOT; 4191541Srgrimes else 4201541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 4211541Srgrimes if (*ndp->ni_next == 0) 4221541Srgrimes cnp->cn_flags |= ISLASTCN; 4231541Srgrimes else 4241541Srgrimes cnp->cn_flags &= ~ISLASTCN; 4251541Srgrimes 4261541Srgrimes 4271541Srgrimes /* 4281541Srgrimes * Check for degenerate name (e.g. / or "") 4291541Srgrimes * which is a way of talking about a directory, 4301541Srgrimes * e.g. like "/." or ".". 4311541Srgrimes */ 4321541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 43322521Sdyson if (dp->v_type != VDIR) { 43422521Sdyson error = ENOTDIR; 43522521Sdyson goto bad; 43622521Sdyson } 4371541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 4381541Srgrimes error = EISDIR; 4391541Srgrimes goto bad; 4401541Srgrimes } 4411541Srgrimes if (wantparent) { 4421541Srgrimes ndp->ni_dvp = dp; 4431541Srgrimes VREF(dp); 4441541Srgrimes } 4451541Srgrimes ndp->ni_vp = dp; 4461541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 44783366Sjulian VOP_UNLOCK(dp, 0, td); 44854655Seivind /* XXX This should probably move to the top of function. */ 4491541Srgrimes if (cnp->cn_flags & SAVESTART) 4501541Srgrimes panic("lookup: SAVESTART"); 451140714Sjeff goto success; 4521541Srgrimes } 4531541Srgrimes 4541541Srgrimes /* 4551541Srgrimes * Handle "..": two special cases. 4561541Srgrimes * 1. If at root directory (e.g. after chroot) 4571541Srgrimes * or at absolute root directory 4581541Srgrimes * then ignore it so can't get out. 4591541Srgrimes * 2. If this vnode is the root of a mounted 4601541Srgrimes * filesystem, then replace it with the 4611541Srgrimes * vnode which was mounted on so we take the 46296755Strhodes * .. in the other filesystem. 46351649Sphk * 3. If the vnode is the top directory of 46451649Sphk * the jail or chroot, don't let them out. 4651541Srgrimes */ 4661541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 4671541Srgrimes for (;;) { 46851649Sphk if (dp == ndp->ni_rootdir || 46951649Sphk dp == ndp->ni_topdir || 47051649Sphk dp == rootvnode) { 4711541Srgrimes ndp->ni_dvp = dp; 4721541Srgrimes ndp->ni_vp = dp; 4731541Srgrimes VREF(dp); 4741541Srgrimes goto nextname; 4751541Srgrimes } 476101308Sjeff if ((dp->v_vflag & VV_ROOT) == 0 || 4771541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 4781541Srgrimes break; 47969405Salfred if (dp->v_mount == NULL) { /* forced unmount */ 48069405Salfred error = EBADF; 48169405Salfred goto bad; 48269405Salfred } 4831541Srgrimes tdp = dp; 484140714Sjeff tvfslocked = vfslocked; 4851541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4861541Srgrimes vput(tdp); 487140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 488140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 4891541Srgrimes VREF(dp); 49083366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 4911541Srgrimes } 4921541Srgrimes } 4931541Srgrimes 4941541Srgrimes /* 4951541Srgrimes * We now have a segment name to search for, and a directory to search. 4961541Srgrimes */ 4971541Srgrimesunionlookup: 498101127Srwatson#ifdef MAC 499105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 500105479Srwatson error = mac_check_vnode_lookup(td->td_ucred, dp, cnp); 501105479Srwatson if (error) 502105479Srwatson goto bad; 503105479Srwatson } 504101127Srwatson#endif 5051541Srgrimes ndp->ni_dvp = dp; 50622521Sdyson ndp->ni_vp = NULL; 50765973Sbp cnp->cn_flags &= ~PDIRUNLOCK; 50824624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 509138345Sphk#ifdef NAMEI_DIAGNOSTIC 510138345Sphk vprint("lookup in", dp); 511138345Sphk#endif 51243301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 51342408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 5141541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5151541Srgrimes printf("not found\n"); 5161541Srgrimes#endif 5171541Srgrimes if ((error == ENOENT) && 518101308Sjeff (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && 5191541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 5201541Srgrimes tdp = dp; 521140714Sjeff tvfslocked = vfslocked; 5221541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 52365973Sbp if (cnp->cn_flags & PDIRUNLOCK) 52465973Sbp vrele(tdp); 52565973Sbp else 52665973Sbp vput(tdp); 527140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 528140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 5291541Srgrimes VREF(dp); 53083366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 5311541Srgrimes goto unionlookup; 5321541Srgrimes } 5331541Srgrimes 5341541Srgrimes if (error != EJUSTRETURN) 5351541Srgrimes goto bad; 5361541Srgrimes /* 5371541Srgrimes * If creating and at end of pathname, then can consider 5381541Srgrimes * allowing file to be created. 5391541Srgrimes */ 54011644Sdg if (rdonly) { 5411541Srgrimes error = EROFS; 5421541Srgrimes goto bad; 5431541Srgrimes } 5449804Sbde if (*cp == '\0' && trailing_slash && 5459804Sbde !(cnp->cn_flags & WILLBEDIR)) { 5469804Sbde error = ENOENT; 5479804Sbde goto bad; 5489804Sbde } 5491541Srgrimes /* 5501541Srgrimes * We return with ni_vp NULL to indicate that the entry 5511541Srgrimes * doesn't currently exist, leaving a pointer to the 5521541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 5531541Srgrimes */ 5541541Srgrimes if (cnp->cn_flags & SAVESTART) { 5551541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5561541Srgrimes VREF(ndp->ni_startdir); 5571541Srgrimes } 558140714Sjeff goto success; 5591541Srgrimes } 5601541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5611541Srgrimes printf("found\n"); 5621541Srgrimes#endif 5631541Srgrimes 56424624Sdfr ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); 56524624Sdfr 5661541Srgrimes /* 5671541Srgrimes * Take into account any additional components consumed by 5681541Srgrimes * the underlying filesystem. 5691541Srgrimes */ 5701541Srgrimes if (cnp->cn_consume > 0) { 5711541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 5721541Srgrimes ndp->ni_next += cnp->cn_consume; 5731541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 5741541Srgrimes cnp->cn_consume = 0; 5751541Srgrimes } 5761541Srgrimes 5771541Srgrimes dp = ndp->ni_vp; 5781541Srgrimes 5791541Srgrimes /* 5801541Srgrimes * Check to see if the vnode has been mounted on; 58196755Strhodes * if so find the root of the mounted filesystem. 5821541Srgrimes */ 5831541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 5841541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 58583366Sjulian if (vfs_busy(mp, 0, 0, td)) 5861541Srgrimes continue; 58783366Sjulian VOP_UNLOCK(dp, 0, td); 588140714Sjeff tvfslocked = VFS_LOCK_GIANT(mp); 589132023Salfred error = VFS_ROOT(mp, &tdp, td); 59083366Sjulian vfs_unbusy(mp, td); 59165805Sbp if (error) { 592140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 59365805Sbp dpunlocked = 1; 5941541Srgrimes goto bad2; 59565805Sbp } 59665805Sbp vrele(dp); 597140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 5981541Srgrimes ndp->ni_vp = dp = tdp; 599140714Sjeff vfslocked = tvfslocked; 6001541Srgrimes } 6011541Srgrimes 60210219Sdfr /* 60310219Sdfr * Check for symbolic link 60410219Sdfr */ 60510219Sdfr if ((dp->v_type == VLNK) && 60610219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 60710219Sdfr *ndp->ni_next == '/')) { 60810219Sdfr cnp->cn_flags |= ISSYMLINK; 60969405Salfred if (dp->v_mount == NULL) { 61069405Salfred /* We can't know whether the directory was mounted with 61169405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 61269405Salfred error = EBADF; 61369405Salfred goto bad2; 61469405Salfred } 61535105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 61635105Swosch error = EACCES; 61735105Swosch goto bad2; 61835105Swosch } 619140714Sjeff goto success; 62010219Sdfr } 62110219Sdfr 62210219Sdfr /* 62310219Sdfr * Check for bogus trailing slashes. 62410219Sdfr */ 62510219Sdfr if (trailing_slash && dp->v_type != VDIR) { 62610219Sdfr error = ENOTDIR; 62710219Sdfr goto bad2; 62810219Sdfr } 62910219Sdfr 6301541Srgrimesnextname: 6311541Srgrimes /* 6321541Srgrimes * Not a symbolic link. If more pathname, 6331541Srgrimes * continue at next component, else return. 6341541Srgrimes */ 6351541Srgrimes if (*ndp->ni_next == '/') { 6361541Srgrimes cnp->cn_nameptr = ndp->ni_next; 6371541Srgrimes while (*cnp->cn_nameptr == '/') { 6381541Srgrimes cnp->cn_nameptr++; 6391541Srgrimes ndp->ni_pathlen--; 6401541Srgrimes } 64154655Seivind if (ndp->ni_dvp != ndp->ni_vp) 64254655Seivind ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); 6431541Srgrimes vrele(ndp->ni_dvp); 6441541Srgrimes goto dirloop; 6451541Srgrimes } 6461541Srgrimes /* 64796755Strhodes * Disallow directory write attempts on read-only filesystems. 6481541Srgrimes */ 64911644Sdg if (rdonly && 65011644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 65111644Sdg error = EROFS; 65211644Sdg goto bad2; 6531541Srgrimes } 6541541Srgrimes if (cnp->cn_flags & SAVESTART) { 6551541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 6561541Srgrimes VREF(ndp->ni_startdir); 6571541Srgrimes } 6581541Srgrimes if (!wantparent) 6591541Srgrimes vrele(ndp->ni_dvp); 66032071Sdyson 6611541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 66283366Sjulian VOP_UNLOCK(dp, 0, td); 663140714Sjeffsuccess: 664140714Sjeff if (vfslocked) 665140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 6661541Srgrimes return (0); 6671541Srgrimes 6681541Srgrimesbad2: 66965973Sbp if ((cnp->cn_flags & (LOCKPARENT | PDIRUNLOCK)) == LOCKPARENT && 67065973Sbp *ndp->ni_next == '\0') 67183366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 6721541Srgrimes vrele(ndp->ni_dvp); 6731541Srgrimesbad: 67465805Sbp if (dpunlocked) 67565805Sbp vrele(dp); 67665805Sbp else 67765805Sbp vput(dp); 678140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 679140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 6801541Srgrimes ndp->ni_vp = NULL; 6811541Srgrimes return (error); 6821541Srgrimes} 6831541Srgrimes 6843148Sphk/* 6853148Sphk * relookup - lookup a path name component 6863148Sphk * Used by lookup to re-aquire things. 6873148Sphk */ 6883148Sphkint 6893148Sphkrelookup(dvp, vpp, cnp) 6903148Sphk struct vnode *dvp, **vpp; 6913148Sphk struct componentname *cnp; 6923148Sphk{ 69383366Sjulian struct thread *td = cnp->cn_thread; 69422521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 6953148Sphk int docache; /* == 0 do not cache last component */ 6963148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 6973148Sphk int rdonly; /* lookup read-only flag bit */ 6983148Sphk int error = 0; 6991541Srgrimes 7003148Sphk /* 7013148Sphk * Setup: break out flag bits into variables. 7023148Sphk */ 7033148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 7043148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 7053148Sphk if (cnp->cn_nameiop == DELETE || 7063148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 7073148Sphk docache = 0; 7083148Sphk rdonly = cnp->cn_flags & RDONLY; 7093148Sphk cnp->cn_flags &= ~ISSYMLINK; 7103148Sphk dp = dvp; 71183366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 7123148Sphk 7133148Sphk/* dirloop: */ 7143148Sphk /* 7153148Sphk * Search a new directory. 7163148Sphk * 7173148Sphk * The last component of the filename is left accessible via 7183148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 7193148Sphk * the name set the SAVENAME flag. When done, they assume 7203148Sphk * responsibility for freeing the pathname buffer. 7213148Sphk */ 7223148Sphk#ifdef NAMEI_DIAGNOSTIC 7233148Sphk printf("{%s}: ", cnp->cn_nameptr); 7243148Sphk#endif 7253148Sphk 7263148Sphk /* 7273148Sphk * Check for degenerate name (e.g. / or "") 7283148Sphk * which is a way of talking about a directory, 7293148Sphk * e.g. like "/." or ".". 7303148Sphk */ 7313148Sphk if (cnp->cn_nameptr[0] == '\0') { 7323148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 7333148Sphk error = EISDIR; 7343148Sphk goto bad; 7353148Sphk } 7363148Sphk if (dp->v_type != VDIR) { 7373148Sphk error = ENOTDIR; 7383148Sphk goto bad; 7393148Sphk } 7403148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 74183366Sjulian VOP_UNLOCK(dp, 0, td); 7423148Sphk *vpp = dp; 74354655Seivind /* XXX This should probably move to the top of function. */ 7443148Sphk if (cnp->cn_flags & SAVESTART) 7453148Sphk panic("lookup: SAVESTART"); 7463148Sphk return (0); 7473148Sphk } 7483148Sphk 7493148Sphk if (cnp->cn_flags & ISDOTDOT) 7503148Sphk panic ("relookup: lookup on dot-dot"); 7513148Sphk 7523148Sphk /* 7533148Sphk * We now have a segment name to search for, and a directory to search. 7543148Sphk */ 755138345Sphk#ifdef NAMEI_DIAGNOSTIC 756138345Sphk vprint("search in:", dp); 757138345Sphk#endif 75843311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 75942408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 7603148Sphk if (error != EJUSTRETURN) 7613148Sphk goto bad; 7623148Sphk /* 7633148Sphk * If creating and at end of pathname, then can consider 7643148Sphk * allowing file to be created. 7653148Sphk */ 76611644Sdg if (rdonly) { 7673148Sphk error = EROFS; 7683148Sphk goto bad; 7693148Sphk } 7703148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7713148Sphk if (cnp->cn_flags & SAVESTART) 7723148Sphk VREF(dvp); 7733148Sphk /* 7743148Sphk * We return with ni_vp NULL to indicate that the entry 7753148Sphk * doesn't currently exist, leaving a pointer to the 7763148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 7773148Sphk */ 7783148Sphk return (0); 7793148Sphk } 7803148Sphk dp = *vpp; 7813148Sphk 7823148Sphk /* 7833148Sphk * Check for symbolic link 7843148Sphk */ 78542408Seivind KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 78642453Seivind ("relookup: symlink found.\n")); 7873148Sphk 7883148Sphk /* 78996755Strhodes * Disallow directory write attempts on read-only filesystems. 7903148Sphk */ 79111644Sdg if (rdonly && 79211644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 79311644Sdg error = EROFS; 79411644Sdg goto bad2; 7953148Sphk } 7963148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7973148Sphk if (cnp->cn_flags & SAVESTART) 7983148Sphk VREF(dvp); 79922521Sdyson 8003148Sphk if (!wantparent) 8013148Sphk vrele(dvp); 80232071Sdyson 80349101Salc if (vn_canvmio(dp) == TRUE && 80432286Sdyson ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF)) 805140181Sphk VOP_CREATEVOBJECT(dp, cnp->cn_cred, td); 80632071Sdyson 8073148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 80883366Sjulian VOP_UNLOCK(dp, 0, td); 8093148Sphk return (0); 8103148Sphk 8113148Sphkbad2: 8123148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 81383366Sjulian VOP_UNLOCK(dvp, 0, td); 8143148Sphk vrele(dvp); 8153148Sphkbad: 8163148Sphk vput(dp); 8173148Sphk *vpp = NULL; 8183148Sphk return (error); 8193148Sphk} 820