vfs_lookup.c revision 100613
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 100613 2002-07-24 15:42:22Z rwatson $ 401541Srgrimes */ 411541Srgrimes 4213203Swollman#include "opt_ktrace.h" 4313203Swollman 441541Srgrimes#include <sys/param.h> 452112Swollman#include <sys/systm.h> 4669664Speter#include <sys/kernel.h> 4776166Smarkm#include <sys/lock.h> 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 601541Srgrimes/* 6169664Speter * Allocation zone for namei 6269664Speter */ 6392751Sjeffuma_zone_t namei_zone; 6469664Speter 6569664Speterstatic void 6669664Speternameiinit(void *dummy __unused) 6769664Speter{ 6892654Sjeff namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, 6992654Sjeff UMA_ALIGN_PTR, 0); 7069664Speter 7169664Speter} 7269664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 7369664Speter 7469664Speter/* 751541Srgrimes * Convert a pathname into a pointer to a locked inode. 761541Srgrimes * 771541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 781541Srgrimes * when they occur at the end of the name translation process. 791541Srgrimes * Symbolic links are always followed for all other pathname 801541Srgrimes * components other than the last. 811541Srgrimes * 821541Srgrimes * The segflg defines whether the name is to be copied from user 831541Srgrimes * space or kernel space. 841541Srgrimes * 851541Srgrimes * Overall outline of namei: 861541Srgrimes * 871541Srgrimes * copy in name 881541Srgrimes * get starting directory 891541Srgrimes * while (!done && !error) { 901541Srgrimes * call lookup to search path. 911541Srgrimes * if symbolic link, massage name in buffer and continue 921541Srgrimes * } 931541Srgrimes */ 941541Srgrimesint 951541Srgrimesnamei(ndp) 961541Srgrimes register struct nameidata *ndp; 971541Srgrimes{ 981541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 991541Srgrimes register char *cp; /* pointer into pathname argument */ 1001541Srgrimes register struct vnode *dp; /* the directory we are searching */ 1011541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1021541Srgrimes struct uio auio; 1031541Srgrimes int error, linklen; 1041541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 10583366Sjulian struct thread *td = cnp->cn_thread; 10683366Sjulian struct proc *p = td->td_proc; 1071541Srgrimes 10891419Sjhb ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; 10983366Sjulian KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); 11042408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 11142453Seivind ("namei: nameiop contaminated with flags")); 11242408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 11342453Seivind ("namei: flags contaminated with nameiops")); 11483366Sjulian fdp = p->p_fd; 1151541Srgrimes 1161541Srgrimes /* 1171541Srgrimes * Get a buffer for the name to be translated, and copy the 1181541Srgrimes * name into the buffer. 1191541Srgrimes */ 1201541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 12192751Sjeff cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 1221541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1231541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 12436735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1251541Srgrimes else 1261541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 12736735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 12820069Sbde 12920069Sbde /* 13020069Sbde * Don't allow empty pathnames. 13120069Sbde */ 13220069Sbde if (!error && *cnp->cn_pnbuf == '\0') 13320069Sbde error = ENOENT; 13420069Sbde 1351541Srgrimes if (error) { 13692751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 137100613Srwatson#ifdef DIAGNOSTIC 138100613Srwatson cnp->cn_pnbuf = NULL; 139100613Srwatson cnp->cn_nameptr = NULL; 140100613Srwatson#endif 1411541Srgrimes ndp->ni_vp = NULL; 1421541Srgrimes return (error); 1431541Srgrimes } 1441541Srgrimes ndp->ni_loopcnt = 0; 1451541Srgrimes#ifdef KTRACE 14697994Sjhb if (KTRPOINT(td, KTR_NAMEI)) { 14797994Sjhb KASSERT(cnp->cn_thread == curthread, 14897994Sjhb ("namei not using curthread")); 14997994Sjhb ktrnamei(cnp->cn_pnbuf); 15097994Sjhb } 1511541Srgrimes#endif 1521541Srgrimes 1531541Srgrimes /* 1541541Srgrimes * Get starting point for the translation. 1551541Srgrimes */ 15689306Salfred FILEDESC_LOCK(fdp); 15733360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 15851649Sphk ndp->ni_topdir = fdp->fd_jdir; 15933360Sdyson 1601541Srgrimes dp = fdp->fd_cdir; 1611541Srgrimes VREF(dp); 16289306Salfred FILEDESC_UNLOCK(fdp); 1631541Srgrimes for (;;) { 1641541Srgrimes /* 1651541Srgrimes * Check if root directory should replace current directory. 1661541Srgrimes * Done at start of translation and after symbolic link. 1671541Srgrimes */ 1681541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1691541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1701541Srgrimes vrele(dp); 1711541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1721541Srgrimes cnp->cn_nameptr++; 1731541Srgrimes ndp->ni_pathlen--; 1741541Srgrimes } 1751541Srgrimes dp = ndp->ni_rootdir; 1761541Srgrimes VREF(dp); 1771541Srgrimes } 1781541Srgrimes ndp->ni_startdir = dp; 1793148Sphk error = lookup(ndp); 1803148Sphk if (error) { 18192751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 182100613Srwatson#ifdef DIAGNOSTIC 183100613Srwatson cnp->cn_pnbuf = NULL; 184100613Srwatson cnp->cn_nameptr = NULL; 185100613Srwatson#endif 1861541Srgrimes return (error); 1871541Srgrimes } 1881541Srgrimes /* 1891541Srgrimes * Check for symbolic link 1901541Srgrimes */ 1911541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 192100613Srwatson if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 19392751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 194100613Srwatson#ifdef DIAGNOSTIC 195100613Srwatson cnp->cn_pnbuf = NULL; 196100613Srwatson cnp->cn_nameptr = NULL; 197100613Srwatson#endif 198100613Srwatson } else 1991541Srgrimes cnp->cn_flags |= HASBUF; 20032286Sdyson 20149101Salc if (vn_canvmio(ndp->ni_vp) == TRUE && 20232286Sdyson (cnp->cn_nameiop != DELETE) && 20342315Seivind ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == 20442315Seivind LOCKLEAF)) 20583366Sjulian vfs_object_create(ndp->ni_vp, td, 20642315Seivind ndp->ni_cnd.cn_cred); 20732286Sdyson 2081541Srgrimes return (0); 2091541Srgrimes } 2101541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 21183366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 2121541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2131541Srgrimes error = ELOOP; 2141541Srgrimes break; 2151541Srgrimes } 2161541Srgrimes if (ndp->ni_pathlen > 1) 21792751Sjeff cp = uma_zalloc(namei_zone, M_WAITOK); 2181541Srgrimes else 2191541Srgrimes cp = cnp->cn_pnbuf; 2201541Srgrimes aiov.iov_base = cp; 2211541Srgrimes aiov.iov_len = MAXPATHLEN; 2221541Srgrimes auio.uio_iov = &aiov; 2231541Srgrimes auio.uio_iovcnt = 1; 2241541Srgrimes auio.uio_offset = 0; 2251541Srgrimes auio.uio_rw = UIO_READ; 2261541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 22783366Sjulian auio.uio_td = (struct thread *)0; 2281541Srgrimes auio.uio_resid = MAXPATHLEN; 2293148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2303148Sphk if (error) { 2311541Srgrimes if (ndp->ni_pathlen > 1) 23292751Sjeff uma_zfree(namei_zone, cp); 2331541Srgrimes break; 2341541Srgrimes } 2351541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 23678692Sdillon if (linklen == 0) { 23778692Sdillon if (ndp->ni_pathlen > 1) 23892751Sjeff uma_zfree(namei_zone, cp); 23978692Sdillon error = ENOENT; 24078692Sdillon break; 24178692Sdillon } 2421541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2431541Srgrimes if (ndp->ni_pathlen > 1) 24492751Sjeff uma_zfree(namei_zone, cp); 2451541Srgrimes error = ENAMETOOLONG; 2461541Srgrimes break; 2471541Srgrimes } 2481541Srgrimes if (ndp->ni_pathlen > 1) { 2491541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 25092751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 2511541Srgrimes cnp->cn_pnbuf = cp; 2521541Srgrimes } else 2531541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2541541Srgrimes ndp->ni_pathlen += linklen; 2551541Srgrimes vput(ndp->ni_vp); 2561541Srgrimes dp = ndp->ni_dvp; 2571541Srgrimes } 25892751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 259100613Srwatson#ifdef DIAGNOSTIC 260100613Srwatson cnp->cn_pnbuf = NULL; 261100613Srwatson cnp->cn_nameptr = NULL; 262100613Srwatson#endif 2631541Srgrimes vrele(ndp->ni_dvp); 2641541Srgrimes vput(ndp->ni_vp); 2651541Srgrimes ndp->ni_vp = NULL; 2661541Srgrimes return (error); 2671541Srgrimes} 2681541Srgrimes 2691541Srgrimes/* 2701541Srgrimes * Search a pathname. 2711541Srgrimes * This is a very central and rather complicated routine. 2721541Srgrimes * 2731541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2741541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2751541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2761541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2771541Srgrimes * symbolic link needing interpretation is encountered. 2781541Srgrimes * 2791541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 2801541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 2811541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 2821541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 2831541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 2841541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 2851541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 2861541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 2871541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 2881541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 2891541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 2908876Srgrimes * 2911541Srgrimes * Overall outline of lookup: 2921541Srgrimes * 2931541Srgrimes * dirloop: 2941541Srgrimes * identify next component of name at ndp->ni_ptr 2951541Srgrimes * handle degenerate case where name is null string 2961541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 2971541Srgrimes * call VOP_LOOKUP routine for next component name 2981541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 2991541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 3001541Srgrimes * if result vnode is mounted on and crossing mount points, 3011541Srgrimes * find mounted on vnode 3021541Srgrimes * if more components of name, do next level at dirloop 3031541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 3041541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 3051541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 3061541Srgrimes */ 3071541Srgrimesint 3081541Srgrimeslookup(ndp) 3091541Srgrimes register struct nameidata *ndp; 3101541Srgrimes{ 3111541Srgrimes register char *cp; /* pointer into pathname argument */ 3121541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 3131541Srgrimes struct vnode *tdp; /* saved dp */ 3141541Srgrimes struct mount *mp; /* mount table entry */ 3151541Srgrimes int docache; /* == 0 do not cache last component */ 3161541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 3171541Srgrimes int rdonly; /* lookup read-only flag bit */ 3189804Sbde int trailing_slash; 3191541Srgrimes int error = 0; 32065805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 3211541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 32283366Sjulian struct thread *td = cnp->cn_thread; 3231541Srgrimes 3241541Srgrimes /* 3251541Srgrimes * Setup: break out flag bits into variables. 3261541Srgrimes */ 3271541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 3281541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3291541Srgrimes if (cnp->cn_nameiop == DELETE || 33022874Sbde (wantparent && cnp->cn_nameiop != CREATE && 33122874Sbde cnp->cn_nameiop != LOOKUP)) 3321541Srgrimes docache = 0; 3331541Srgrimes rdonly = cnp->cn_flags & RDONLY; 3341541Srgrimes ndp->ni_dvp = NULL; 3351541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 3361541Srgrimes dp = ndp->ni_startdir; 3371541Srgrimes ndp->ni_startdir = NULLVP; 33883366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 3391541Srgrimes 3401541Srgrimesdirloop: 3411541Srgrimes /* 3421541Srgrimes * Search a new directory. 3431541Srgrimes * 3441541Srgrimes * The last component of the filename is left accessible via 3451541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3461541Srgrimes * the name set the SAVENAME flag. When done, they assume 3471541Srgrimes * responsibility for freeing the pathname buffer. 3481541Srgrimes */ 3491541Srgrimes cnp->cn_consume = 0; 3501541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 35151906Sphk continue; 3521541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3531541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3541541Srgrimes error = ENAMETOOLONG; 3551541Srgrimes goto bad; 3561541Srgrimes } 3571541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3581541Srgrimes { char c = *cp; 3591541Srgrimes *cp = '\0'; 3601541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3611541Srgrimes *cp = c; } 3621541Srgrimes#endif 3631541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3641541Srgrimes ndp->ni_next = cp; 3659804Sbde 3669804Sbde /* 3679804Sbde * Replace multiple slashes by a single slash and trailing slashes 3689804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3699804Sbde * fs's don't know about trailing slashes. Remember if there were 3709804Sbde * trailing slashes to handle symlinks, existing non-directories 3719804Sbde * and non-existing files that won't be directories specially later. 3729804Sbde */ 3739804Sbde trailing_slash = 0; 3749804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 3759804Sbde cp++; 3769804Sbde ndp->ni_pathlen--; 3779804Sbde if (*cp == '\0') { 3789804Sbde trailing_slash = 1; 3799804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 3809804Sbde } 3819804Sbde } 3829804Sbde ndp->ni_next = cp; 3839804Sbde 3841541Srgrimes cnp->cn_flags |= MAKEENTRY; 3851541Srgrimes if (*cp == '\0' && docache == 0) 3861541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 3871541Srgrimes if (cnp->cn_namelen == 2 && 3881541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 3891541Srgrimes cnp->cn_flags |= ISDOTDOT; 3901541Srgrimes else 3911541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 3921541Srgrimes if (*ndp->ni_next == 0) 3931541Srgrimes cnp->cn_flags |= ISLASTCN; 3941541Srgrimes else 3951541Srgrimes cnp->cn_flags &= ~ISLASTCN; 3961541Srgrimes 3971541Srgrimes 3981541Srgrimes /* 3991541Srgrimes * Check for degenerate name (e.g. / or "") 4001541Srgrimes * which is a way of talking about a directory, 4011541Srgrimes * e.g. like "/." or ".". 4021541Srgrimes */ 4031541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 40422521Sdyson if (dp->v_type != VDIR) { 40522521Sdyson error = ENOTDIR; 40622521Sdyson goto bad; 40722521Sdyson } 4081541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 4091541Srgrimes error = EISDIR; 4101541Srgrimes goto bad; 4111541Srgrimes } 4121541Srgrimes if (wantparent) { 4131541Srgrimes ndp->ni_dvp = dp; 4141541Srgrimes VREF(dp); 4151541Srgrimes } 4161541Srgrimes ndp->ni_vp = dp; 4171541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 41883366Sjulian VOP_UNLOCK(dp, 0, td); 41954655Seivind /* XXX This should probably move to the top of function. */ 4201541Srgrimes if (cnp->cn_flags & SAVESTART) 4211541Srgrimes panic("lookup: SAVESTART"); 4221541Srgrimes return (0); 4231541Srgrimes } 4241541Srgrimes 4251541Srgrimes /* 4261541Srgrimes * Handle "..": two special cases. 4271541Srgrimes * 1. If at root directory (e.g. after chroot) 4281541Srgrimes * or at absolute root directory 4291541Srgrimes * then ignore it so can't get out. 4301541Srgrimes * 2. If this vnode is the root of a mounted 4311541Srgrimes * filesystem, then replace it with the 4321541Srgrimes * vnode which was mounted on so we take the 43396755Strhodes * .. in the other filesystem. 43451649Sphk * 3. If the vnode is the top directory of 43551649Sphk * the jail or chroot, don't let them out. 4361541Srgrimes */ 4371541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 4381541Srgrimes for (;;) { 43951649Sphk if (dp == ndp->ni_rootdir || 44051649Sphk dp == ndp->ni_topdir || 44151649Sphk dp == rootvnode) { 4421541Srgrimes ndp->ni_dvp = dp; 4431541Srgrimes ndp->ni_vp = dp; 4441541Srgrimes VREF(dp); 4451541Srgrimes goto nextname; 4461541Srgrimes } 4471541Srgrimes if ((dp->v_flag & VROOT) == 0 || 4481541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 4491541Srgrimes break; 45069405Salfred if (dp->v_mount == NULL) { /* forced unmount */ 45169405Salfred error = EBADF; 45269405Salfred goto bad; 45369405Salfred } 4541541Srgrimes tdp = dp; 4551541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4561541Srgrimes vput(tdp); 4571541Srgrimes VREF(dp); 45883366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 4591541Srgrimes } 4601541Srgrimes } 4611541Srgrimes 4621541Srgrimes /* 4631541Srgrimes * We now have a segment name to search for, and a directory to search. 4641541Srgrimes */ 4651541Srgrimesunionlookup: 4661541Srgrimes ndp->ni_dvp = dp; 46722521Sdyson ndp->ni_vp = NULL; 46865973Sbp cnp->cn_flags &= ~PDIRUNLOCK; 46924624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 47043301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 47142408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 4721541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4731541Srgrimes printf("not found\n"); 4741541Srgrimes#endif 4751541Srgrimes if ((error == ENOENT) && 47669405Salfred (dp->v_flag & VROOT) && (dp->v_mount != NULL) && 4771541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 4781541Srgrimes tdp = dp; 4791541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 48065973Sbp if (cnp->cn_flags & PDIRUNLOCK) 48165973Sbp vrele(tdp); 48265973Sbp else 48365973Sbp vput(tdp); 4841541Srgrimes VREF(dp); 48583366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 4861541Srgrimes goto unionlookup; 4871541Srgrimes } 4881541Srgrimes 4891541Srgrimes if (error != EJUSTRETURN) 4901541Srgrimes goto bad; 4911541Srgrimes /* 4921541Srgrimes * If creating and at end of pathname, then can consider 4931541Srgrimes * allowing file to be created. 4941541Srgrimes */ 49511644Sdg if (rdonly) { 4961541Srgrimes error = EROFS; 4971541Srgrimes goto bad; 4981541Srgrimes } 4999804Sbde if (*cp == '\0' && trailing_slash && 5009804Sbde !(cnp->cn_flags & WILLBEDIR)) { 5019804Sbde error = ENOENT; 5029804Sbde goto bad; 5039804Sbde } 5041541Srgrimes /* 5051541Srgrimes * We return with ni_vp NULL to indicate that the entry 5061541Srgrimes * doesn't currently exist, leaving a pointer to the 5071541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 5081541Srgrimes */ 5091541Srgrimes if (cnp->cn_flags & SAVESTART) { 5101541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5111541Srgrimes VREF(ndp->ni_startdir); 5121541Srgrimes } 5131541Srgrimes return (0); 5141541Srgrimes } 5151541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5161541Srgrimes printf("found\n"); 5171541Srgrimes#endif 5181541Srgrimes 51924624Sdfr ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); 52024624Sdfr 5211541Srgrimes /* 5221541Srgrimes * Take into account any additional components consumed by 5231541Srgrimes * the underlying filesystem. 5241541Srgrimes */ 5251541Srgrimes if (cnp->cn_consume > 0) { 5261541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 5271541Srgrimes ndp->ni_next += cnp->cn_consume; 5281541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 5291541Srgrimes cnp->cn_consume = 0; 5301541Srgrimes } 5311541Srgrimes 5321541Srgrimes dp = ndp->ni_vp; 5331541Srgrimes 5341541Srgrimes /* 5351541Srgrimes * Check to see if the vnode has been mounted on; 53696755Strhodes * if so find the root of the mounted filesystem. 5371541Srgrimes */ 5381541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 5391541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 54083366Sjulian if (vfs_busy(mp, 0, 0, td)) 5411541Srgrimes continue; 54283366Sjulian VOP_UNLOCK(dp, 0, td); 54322521Sdyson error = VFS_ROOT(mp, &tdp); 54483366Sjulian vfs_unbusy(mp, td); 54565805Sbp if (error) { 54665805Sbp dpunlocked = 1; 5471541Srgrimes goto bad2; 54865805Sbp } 54965805Sbp vrele(dp); 5501541Srgrimes ndp->ni_vp = dp = tdp; 5511541Srgrimes } 5521541Srgrimes 55310219Sdfr /* 55410219Sdfr * Check for symbolic link 55510219Sdfr */ 55610219Sdfr if ((dp->v_type == VLNK) && 55710219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 55810219Sdfr *ndp->ni_next == '/')) { 55910219Sdfr cnp->cn_flags |= ISSYMLINK; 56069405Salfred if (dp->v_mount == NULL) { 56169405Salfred /* We can't know whether the directory was mounted with 56269405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 56369405Salfred error = EBADF; 56469405Salfred goto bad2; 56569405Salfred } 56635105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 56735105Swosch error = EACCES; 56835105Swosch goto bad2; 56935105Swosch } 57010219Sdfr return (0); 57110219Sdfr } 57210219Sdfr 57310219Sdfr /* 57410219Sdfr * Check for bogus trailing slashes. 57510219Sdfr */ 57610219Sdfr if (trailing_slash && dp->v_type != VDIR) { 57710219Sdfr error = ENOTDIR; 57810219Sdfr goto bad2; 57910219Sdfr } 58010219Sdfr 5811541Srgrimesnextname: 5821541Srgrimes /* 5831541Srgrimes * Not a symbolic link. If more pathname, 5841541Srgrimes * continue at next component, else return. 5851541Srgrimes */ 5861541Srgrimes if (*ndp->ni_next == '/') { 5871541Srgrimes cnp->cn_nameptr = ndp->ni_next; 5881541Srgrimes while (*cnp->cn_nameptr == '/') { 5891541Srgrimes cnp->cn_nameptr++; 5901541Srgrimes ndp->ni_pathlen--; 5911541Srgrimes } 59254655Seivind if (ndp->ni_dvp != ndp->ni_vp) 59354655Seivind ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); 5941541Srgrimes vrele(ndp->ni_dvp); 5951541Srgrimes goto dirloop; 5961541Srgrimes } 5971541Srgrimes /* 59896755Strhodes * Disallow directory write attempts on read-only filesystems. 5991541Srgrimes */ 60011644Sdg if (rdonly && 60111644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 60211644Sdg error = EROFS; 60311644Sdg goto bad2; 6041541Srgrimes } 6051541Srgrimes if (cnp->cn_flags & SAVESTART) { 6061541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 6071541Srgrimes VREF(ndp->ni_startdir); 6081541Srgrimes } 6091541Srgrimes if (!wantparent) 6101541Srgrimes vrele(ndp->ni_dvp); 61132071Sdyson 6121541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 61383366Sjulian VOP_UNLOCK(dp, 0, td); 6141541Srgrimes return (0); 6151541Srgrimes 6161541Srgrimesbad2: 61765973Sbp if ((cnp->cn_flags & (LOCKPARENT | PDIRUNLOCK)) == LOCKPARENT && 61865973Sbp *ndp->ni_next == '\0') 61983366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 6201541Srgrimes vrele(ndp->ni_dvp); 6211541Srgrimesbad: 62265805Sbp if (dpunlocked) 62365805Sbp vrele(dp); 62465805Sbp else 62565805Sbp vput(dp); 6261541Srgrimes ndp->ni_vp = NULL; 6271541Srgrimes return (error); 6281541Srgrimes} 6291541Srgrimes 6303148Sphk/* 6313148Sphk * relookup - lookup a path name component 6323148Sphk * Used by lookup to re-aquire things. 6333148Sphk */ 6343148Sphkint 6353148Sphkrelookup(dvp, vpp, cnp) 6363148Sphk struct vnode *dvp, **vpp; 6373148Sphk struct componentname *cnp; 6383148Sphk{ 63983366Sjulian struct thread *td = cnp->cn_thread; 64022521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 6413148Sphk int docache; /* == 0 do not cache last component */ 6423148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 6433148Sphk int rdonly; /* lookup read-only flag bit */ 6443148Sphk int error = 0; 6453148Sphk#ifdef NAMEI_DIAGNOSTIC 6463148Sphk int newhash; /* DEBUG: check name hash */ 6473148Sphk char *cp; /* DEBUG: check name ptr/len */ 6483148Sphk#endif 6491541Srgrimes 6503148Sphk /* 6513148Sphk * Setup: break out flag bits into variables. 6523148Sphk */ 6533148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 6543148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 6553148Sphk if (cnp->cn_nameiop == DELETE || 6563148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 6573148Sphk docache = 0; 6583148Sphk rdonly = cnp->cn_flags & RDONLY; 6593148Sphk cnp->cn_flags &= ~ISSYMLINK; 6603148Sphk dp = dvp; 66183366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 6623148Sphk 6633148Sphk/* dirloop: */ 6643148Sphk /* 6653148Sphk * Search a new directory. 6663148Sphk * 6673148Sphk * The last component of the filename is left accessible via 6683148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 6693148Sphk * the name set the SAVENAME flag. When done, they assume 6703148Sphk * responsibility for freeing the pathname buffer. 6713148Sphk */ 6723148Sphk#ifdef NAMEI_DIAGNOSTIC 6733148Sphk if (cnp->cn_namelen != cp - cnp->cn_nameptr) 6743148Sphk panic ("relookup: bad len"); 6753148Sphk if (*cp != 0) 6763148Sphk panic("relookup: not last component"); 6773148Sphk printf("{%s}: ", cnp->cn_nameptr); 6783148Sphk#endif 6793148Sphk 6803148Sphk /* 6813148Sphk * Check for degenerate name (e.g. / or "") 6823148Sphk * which is a way of talking about a directory, 6833148Sphk * e.g. like "/." or ".". 6843148Sphk */ 6853148Sphk if (cnp->cn_nameptr[0] == '\0') { 6863148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 6873148Sphk error = EISDIR; 6883148Sphk goto bad; 6893148Sphk } 6903148Sphk if (dp->v_type != VDIR) { 6913148Sphk error = ENOTDIR; 6923148Sphk goto bad; 6933148Sphk } 6943148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 69583366Sjulian VOP_UNLOCK(dp, 0, td); 6963148Sphk *vpp = dp; 69754655Seivind /* XXX This should probably move to the top of function. */ 6983148Sphk if (cnp->cn_flags & SAVESTART) 6993148Sphk panic("lookup: SAVESTART"); 7003148Sphk return (0); 7013148Sphk } 7023148Sphk 7033148Sphk if (cnp->cn_flags & ISDOTDOT) 7043148Sphk panic ("relookup: lookup on dot-dot"); 7053148Sphk 7063148Sphk /* 7073148Sphk * We now have a segment name to search for, and a directory to search. 7083148Sphk */ 70943311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 71042408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 7113148Sphk if (error != EJUSTRETURN) 7123148Sphk goto bad; 7133148Sphk /* 7143148Sphk * If creating and at end of pathname, then can consider 7153148Sphk * allowing file to be created. 7163148Sphk */ 71711644Sdg if (rdonly) { 7183148Sphk error = EROFS; 7193148Sphk goto bad; 7203148Sphk } 7213148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7223148Sphk if (cnp->cn_flags & SAVESTART) 7233148Sphk VREF(dvp); 7243148Sphk /* 7253148Sphk * We return with ni_vp NULL to indicate that the entry 7263148Sphk * doesn't currently exist, leaving a pointer to the 7273148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 7283148Sphk */ 7293148Sphk return (0); 7303148Sphk } 7313148Sphk dp = *vpp; 7323148Sphk 7333148Sphk /* 7343148Sphk * Check for symbolic link 7353148Sphk */ 73642408Seivind KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 73742453Seivind ("relookup: symlink found.\n")); 7383148Sphk 7393148Sphk /* 74096755Strhodes * Disallow directory write attempts on read-only filesystems. 7413148Sphk */ 74211644Sdg if (rdonly && 74311644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 74411644Sdg error = EROFS; 74511644Sdg goto bad2; 7463148Sphk } 7473148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 7483148Sphk if (cnp->cn_flags & SAVESTART) 7493148Sphk VREF(dvp); 75022521Sdyson 7513148Sphk if (!wantparent) 7523148Sphk vrele(dvp); 75332071Sdyson 75449101Salc if (vn_canvmio(dp) == TRUE && 75532286Sdyson ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF)) 75683366Sjulian vfs_object_create(dp, td, cnp->cn_cred); 75732071Sdyson 7583148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 75983366Sjulian VOP_UNLOCK(dp, 0, td); 7603148Sphk return (0); 7613148Sphk 7623148Sphkbad2: 7633148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 76483366Sjulian VOP_UNLOCK(dvp, 0, td); 7653148Sphk vrele(dvp); 7663148Sphkbad: 7673148Sphk vput(dp); 7683148Sphk *vpp = NULL; 7693148Sphk return (error); 7703148Sphk} 771