vfs_lookup.c revision 154690
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 154690 2006-01-22 19:37:02Z truckman $"); 39116182Sobrien 4013203Swollman#include "opt_ktrace.h" 41101127Srwatson#include "opt_mac.h" 42144613Sjeff#include "opt_vfs.h" 4313203Swollman 441541Srgrimes#include <sys/param.h> 452112Swollman#include <sys/systm.h> 4669664Speter#include <sys/kernel.h> 4776166Smarkm#include <sys/lock.h> 48101127Srwatson#include <sys/mac.h> 4989316Salfred#include <sys/mutex.h> 501541Srgrimes#include <sys/namei.h> 511541Srgrimes#include <sys/vnode.h> 521541Srgrimes#include <sys/mount.h> 531541Srgrimes#include <sys/filedesc.h> 541541Srgrimes#include <sys/proc.h> 55141471Sjhb#include <sys/syscallsubr.h> 56144613Sjeff#include <sys/sysctl.h> 571541Srgrimes#ifdef KTRACE 581541Srgrimes#include <sys/ktrace.h> 591541Srgrimes#endif 601541Srgrimes 6192751Sjeff#include <vm/uma.h> 6232011Sbde 63138345Sphk#define NAMEI_DIAGNOSTIC 1 64138345Sphk#undef NAMEI_DIAGNOSTIC 65138345Sphk 661541Srgrimes/* 6769664Speter * Allocation zone for namei 6869664Speter */ 6992751Sjeffuma_zone_t namei_zone; 7069664Speter 7169664Speterstatic void 7269664Speternameiinit(void *dummy __unused) 7369664Speter{ 7492654Sjeff namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, 7592654Sjeff UMA_ALIGN_PTR, 0); 7669664Speter 7769664Speter} 7869664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 7969664Speter 80144613Sjeff#ifdef LOOKUP_SHARED 81144613Sjeffstatic int lookup_shared = 1; 82144613Sjeff#else 83144613Sjeffstatic int lookup_shared = 0; 84144613Sjeff#endif 85144613SjeffSYSCTL_INT(_vfs, OID_AUTO, lookup_shared, CTLFLAG_RW, &lookup_shared, 0, 86144613Sjeff "Enables/Disables shared locks for path name translation"); 87144613Sjeff 8869664Speter/* 891541Srgrimes * Convert a pathname into a pointer to a locked inode. 901541Srgrimes * 911541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 921541Srgrimes * when they occur at the end of the name translation process. 931541Srgrimes * Symbolic links are always followed for all other pathname 941541Srgrimes * components other than the last. 951541Srgrimes * 961541Srgrimes * The segflg defines whether the name is to be copied from user 971541Srgrimes * space or kernel space. 981541Srgrimes * 991541Srgrimes * Overall outline of namei: 1001541Srgrimes * 1011541Srgrimes * copy in name 1021541Srgrimes * get starting directory 1031541Srgrimes * while (!done && !error) { 1041541Srgrimes * call lookup to search path. 1051541Srgrimes * if symbolic link, massage name in buffer and continue 1061541Srgrimes * } 1071541Srgrimes */ 1081541Srgrimesint 1091541Srgrimesnamei(ndp) 1101541Srgrimes register struct nameidata *ndp; 1111541Srgrimes{ 1121541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 1131541Srgrimes register char *cp; /* pointer into pathname argument */ 1141541Srgrimes register struct vnode *dp; /* the directory we are searching */ 1151541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1161541Srgrimes struct uio auio; 1171541Srgrimes int error, linklen; 1181541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 11983366Sjulian struct thread *td = cnp->cn_thread; 12083366Sjulian struct proc *p = td->td_proc; 121140714Sjeff int vfslocked; 1221541Srgrimes 123150164Scsjp KASSERT((cnp->cn_flags & MPSAFE) != 0 || mtx_owned(&Giant) != 0, 124150164Scsjp ("NOT MPSAFE and Giant not held")); 12591419Sjhb ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; 12683366Sjulian KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); 12742408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 12842453Seivind ("namei: nameiop contaminated with flags")); 12942408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 13042453Seivind ("namei: flags contaminated with nameiops")); 131144613Sjeff if (!lookup_shared) 132144613Sjeff cnp->cn_flags &= ~LOCKSHARED; 13383366Sjulian fdp = p->p_fd; 1341541Srgrimes 1351541Srgrimes /* 1361541Srgrimes * Get a buffer for the name to be translated, and copy the 1371541Srgrimes * name into the buffer. 1381541Srgrimes */ 1391541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 140111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 1411541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1421541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 14336735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1441541Srgrimes else 1451541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 14636735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 14720069Sbde 14820069Sbde /* 14920069Sbde * Don't allow empty pathnames. 15020069Sbde */ 15120069Sbde if (!error && *cnp->cn_pnbuf == '\0') 15220069Sbde error = ENOENT; 15320069Sbde 1541541Srgrimes if (error) { 15592751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 156100613Srwatson#ifdef DIAGNOSTIC 157100613Srwatson cnp->cn_pnbuf = NULL; 158100613Srwatson cnp->cn_nameptr = NULL; 159100613Srwatson#endif 1601541Srgrimes ndp->ni_vp = NULL; 1611541Srgrimes return (error); 1621541Srgrimes } 1631541Srgrimes ndp->ni_loopcnt = 0; 1641541Srgrimes#ifdef KTRACE 16597994Sjhb if (KTRPOINT(td, KTR_NAMEI)) { 16697994Sjhb KASSERT(cnp->cn_thread == curthread, 16797994Sjhb ("namei not using curthread")); 16897994Sjhb ktrnamei(cnp->cn_pnbuf); 16997994Sjhb } 1701541Srgrimes#endif 1711541Srgrimes 1721541Srgrimes /* 1731541Srgrimes * Get starting point for the translation. 1741541Srgrimes */ 17589306Salfred FILEDESC_LOCK(fdp); 17633360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 17751649Sphk ndp->ni_topdir = fdp->fd_jdir; 17833360Sdyson 1791541Srgrimes dp = fdp->fd_cdir; 180140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1811541Srgrimes VREF(dp); 18289306Salfred FILEDESC_UNLOCK(fdp); 1831541Srgrimes for (;;) { 1841541Srgrimes /* 1851541Srgrimes * Check if root directory should replace current directory. 1861541Srgrimes * Done at start of translation and after symbolic link. 1871541Srgrimes */ 1881541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1891541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1901541Srgrimes vrele(dp); 191140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 1921541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1931541Srgrimes cnp->cn_nameptr++; 1941541Srgrimes ndp->ni_pathlen--; 1951541Srgrimes } 1961541Srgrimes dp = ndp->ni_rootdir; 197140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1981541Srgrimes VREF(dp); 1991541Srgrimes } 200140714Sjeff if (vfslocked) 201140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 2021541Srgrimes ndp->ni_startdir = dp; 2033148Sphk error = lookup(ndp); 2043148Sphk if (error) { 20592751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 206100613Srwatson#ifdef DIAGNOSTIC 207100613Srwatson cnp->cn_pnbuf = NULL; 208100613Srwatson cnp->cn_nameptr = NULL; 209100613Srwatson#endif 2101541Srgrimes return (error); 2111541Srgrimes } 212140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 213140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 2141541Srgrimes /* 2151541Srgrimes * Check for symbolic link 2161541Srgrimes */ 2171541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 218100613Srwatson if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 21992751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 220100613Srwatson#ifdef DIAGNOSTIC 221100613Srwatson cnp->cn_pnbuf = NULL; 222100613Srwatson cnp->cn_nameptr = NULL; 223100613Srwatson#endif 224100613Srwatson } else 2251541Srgrimes cnp->cn_flags |= HASBUF; 22632286Sdyson 227140714Sjeff if ((cnp->cn_flags & MPSAFE) == 0) { 228140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 229140714Sjeff } else if (vfslocked) 230140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 2311541Srgrimes return (0); 2321541Srgrimes } 2331541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2341541Srgrimes error = ELOOP; 2351541Srgrimes break; 2361541Srgrimes } 237101127Srwatson#ifdef MAC 238105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 239105479Srwatson error = mac_check_vnode_readlink(td->td_ucred, 240105479Srwatson ndp->ni_vp); 241105479Srwatson if (error) 242105479Srwatson break; 243105479Srwatson } 244101127Srwatson#endif 2451541Srgrimes if (ndp->ni_pathlen > 1) 246111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 2471541Srgrimes else 2481541Srgrimes cp = cnp->cn_pnbuf; 2491541Srgrimes aiov.iov_base = cp; 2501541Srgrimes aiov.iov_len = MAXPATHLEN; 2511541Srgrimes auio.uio_iov = &aiov; 2521541Srgrimes auio.uio_iovcnt = 1; 2531541Srgrimes auio.uio_offset = 0; 2541541Srgrimes auio.uio_rw = UIO_READ; 2551541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 25683366Sjulian auio.uio_td = (struct thread *)0; 2571541Srgrimes auio.uio_resid = MAXPATHLEN; 2583148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2593148Sphk if (error) { 2601541Srgrimes if (ndp->ni_pathlen > 1) 26192751Sjeff uma_zfree(namei_zone, cp); 2621541Srgrimes break; 2631541Srgrimes } 2641541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 26578692Sdillon if (linklen == 0) { 26678692Sdillon if (ndp->ni_pathlen > 1) 26792751Sjeff uma_zfree(namei_zone, cp); 26878692Sdillon error = ENOENT; 26978692Sdillon break; 27078692Sdillon } 2711541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2721541Srgrimes if (ndp->ni_pathlen > 1) 27392751Sjeff uma_zfree(namei_zone, cp); 2741541Srgrimes error = ENAMETOOLONG; 2751541Srgrimes break; 2761541Srgrimes } 2771541Srgrimes if (ndp->ni_pathlen > 1) { 2781541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 27992751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 2801541Srgrimes cnp->cn_pnbuf = cp; 2811541Srgrimes } else 2821541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2831541Srgrimes ndp->ni_pathlen += linklen; 2841541Srgrimes vput(ndp->ni_vp); 2851541Srgrimes dp = ndp->ni_dvp; 2861541Srgrimes } 28792751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 288100613Srwatson#ifdef DIAGNOSTIC 289100613Srwatson cnp->cn_pnbuf = NULL; 290100613Srwatson cnp->cn_nameptr = NULL; 291100613Srwatson#endif 292144833Sjeff vput(ndp->ni_vp); 293144833Sjeff ndp->ni_vp = NULL; 2941541Srgrimes vrele(ndp->ni_dvp); 295140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 2961541Srgrimes return (error); 2971541Srgrimes} 2981541Srgrimes 2991541Srgrimes/* 3001541Srgrimes * Search a pathname. 3011541Srgrimes * This is a very central and rather complicated routine. 3021541Srgrimes * 3031541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 3041541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 3051541Srgrimes * descended until done, or a symbolic link is encountered. The variable 3061541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 3071541Srgrimes * symbolic link needing interpretation is encountered. 3081541Srgrimes * 3091541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 3101541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 3111541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 3121541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 3131541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 3141541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 3151541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 3161541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 3171541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 3181541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 3191541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 3208876Srgrimes * 3211541Srgrimes * Overall outline of lookup: 3221541Srgrimes * 3231541Srgrimes * dirloop: 3241541Srgrimes * identify next component of name at ndp->ni_ptr 3251541Srgrimes * handle degenerate case where name is null string 3261541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 3271541Srgrimes * call VOP_LOOKUP routine for next component name 3281541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 3291541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 3301541Srgrimes * if result vnode is mounted on and crossing mount points, 3311541Srgrimes * find mounted on vnode 3321541Srgrimes * if more components of name, do next level at dirloop 3331541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 3341541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 3351541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 3361541Srgrimes */ 3371541Srgrimesint 3381541Srgrimeslookup(ndp) 3391541Srgrimes register struct nameidata *ndp; 3401541Srgrimes{ 3411541Srgrimes register char *cp; /* pointer into pathname argument */ 3421541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 3431541Srgrimes struct vnode *tdp; /* saved dp */ 3441541Srgrimes struct mount *mp; /* mount table entry */ 3451541Srgrimes int docache; /* == 0 do not cache last component */ 3461541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 3471541Srgrimes int rdonly; /* lookup read-only flag bit */ 3489804Sbde int trailing_slash; 3491541Srgrimes int error = 0; 35065805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 3511541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 35283366Sjulian struct thread *td = cnp->cn_thread; 353140714Sjeff int vfslocked; 354140714Sjeff int tvfslocked; 3551541Srgrimes 3561541Srgrimes /* 3571541Srgrimes * Setup: break out flag bits into variables. 3581541Srgrimes */ 359140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 360140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 3611541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 362144229Sjeff KASSERT(cnp->cn_nameiop == LOOKUP || wantparent, 363144229Sjeff ("CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT.")); 3641541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3651541Srgrimes if (cnp->cn_nameiop == DELETE || 36622874Sbde (wantparent && cnp->cn_nameiop != CREATE && 36722874Sbde cnp->cn_nameiop != LOOKUP)) 3681541Srgrimes docache = 0; 3691541Srgrimes rdonly = cnp->cn_flags & RDONLY; 370144286Sjeff cnp->cn_flags &= ~ISSYMLINK; 3711541Srgrimes ndp->ni_dvp = NULL; 372144286Sjeff /* 373144286Sjeff * We use shared locks until we hit the parent of the last cn then 374144286Sjeff * we adjust based on the requesting flags. 375144286Sjeff */ 376144613Sjeff if (lookup_shared) 377144613Sjeff cnp->cn_lkflags = LK_SHARED; 378144613Sjeff else 379144613Sjeff cnp->cn_lkflags = LK_EXCLUSIVE; 3801541Srgrimes dp = ndp->ni_startdir; 3811541Srgrimes ndp->ni_startdir = NULLVP; 382144286Sjeff vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td); 3831541Srgrimes 3841541Srgrimesdirloop: 3851541Srgrimes /* 3861541Srgrimes * Search a new directory. 3871541Srgrimes * 3881541Srgrimes * The last component of the filename is left accessible via 3891541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 3901541Srgrimes * the name set the SAVENAME flag. When done, they assume 3911541Srgrimes * responsibility for freeing the pathname buffer. 3921541Srgrimes */ 3931541Srgrimes cnp->cn_consume = 0; 3941541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 39551906Sphk continue; 3961541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 3971541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 3981541Srgrimes error = ENAMETOOLONG; 3991541Srgrimes goto bad; 4001541Srgrimes } 4011541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4021541Srgrimes { char c = *cp; 4031541Srgrimes *cp = '\0'; 4041541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 4051541Srgrimes *cp = c; } 4061541Srgrimes#endif 4071541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 4081541Srgrimes ndp->ni_next = cp; 4099804Sbde 4109804Sbde /* 4119804Sbde * Replace multiple slashes by a single slash and trailing slashes 4129804Sbde * by a null. This must be done before VOP_LOOKUP() because some 4139804Sbde * fs's don't know about trailing slashes. Remember if there were 4149804Sbde * trailing slashes to handle symlinks, existing non-directories 4159804Sbde * and non-existing files that won't be directories specially later. 4169804Sbde */ 4179804Sbde trailing_slash = 0; 4189804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 4199804Sbde cp++; 4209804Sbde ndp->ni_pathlen--; 4219804Sbde if (*cp == '\0') { 4229804Sbde trailing_slash = 1; 4239804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 4249804Sbde } 4259804Sbde } 4269804Sbde ndp->ni_next = cp; 4279804Sbde 4281541Srgrimes cnp->cn_flags |= MAKEENTRY; 4291541Srgrimes if (*cp == '\0' && docache == 0) 4301541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 4311541Srgrimes if (cnp->cn_namelen == 2 && 4321541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 4331541Srgrimes cnp->cn_flags |= ISDOTDOT; 4341541Srgrimes else 4351541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 4361541Srgrimes if (*ndp->ni_next == 0) 4371541Srgrimes cnp->cn_flags |= ISLASTCN; 4381541Srgrimes else 4391541Srgrimes cnp->cn_flags &= ~ISLASTCN; 4401541Srgrimes 4411541Srgrimes 4421541Srgrimes /* 4431541Srgrimes * Check for degenerate name (e.g. / or "") 4441541Srgrimes * which is a way of talking about a directory, 4451541Srgrimes * e.g. like "/." or ".". 4461541Srgrimes */ 4471541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 44822521Sdyson if (dp->v_type != VDIR) { 44922521Sdyson error = ENOTDIR; 45022521Sdyson goto bad; 45122521Sdyson } 4521541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 4531541Srgrimes error = EISDIR; 4541541Srgrimes goto bad; 4551541Srgrimes } 4561541Srgrimes if (wantparent) { 4571541Srgrimes ndp->ni_dvp = dp; 4581541Srgrimes VREF(dp); 4591541Srgrimes } 4601541Srgrimes ndp->ni_vp = dp; 4611541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 46283366Sjulian VOP_UNLOCK(dp, 0, td); 46354655Seivind /* XXX This should probably move to the top of function. */ 4641541Srgrimes if (cnp->cn_flags & SAVESTART) 4651541Srgrimes panic("lookup: SAVESTART"); 466140714Sjeff goto success; 4671541Srgrimes } 4681541Srgrimes 4691541Srgrimes /* 470154649Struckman * Handle "..": four special cases. 471154649Struckman * 1. Return an error if this is the last component of 472154649Struckman * the name and the operation is DELETE or RENAME. 473154649Struckman * 2. If at root directory (e.g. after chroot) 4741541Srgrimes * or at absolute root directory 4751541Srgrimes * then ignore it so can't get out. 476154649Struckman * 3. If this vnode is the root of a mounted 4771541Srgrimes * filesystem, then replace it with the 4781541Srgrimes * vnode which was mounted on so we take the 47996755Strhodes * .. in the other filesystem. 480154649Struckman * 4. If the vnode is the top directory of 48151649Sphk * the jail or chroot, don't let them out. 4821541Srgrimes */ 4831541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 484154649Struckman if ((cnp->cn_flags & ISLASTCN) != 0 && 485154649Struckman (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 486154690Struckman error = EINVAL; 487154649Struckman goto bad; 488154649Struckman } 4891541Srgrimes for (;;) { 49051649Sphk if (dp == ndp->ni_rootdir || 49151649Sphk dp == ndp->ni_topdir || 49251649Sphk dp == rootvnode) { 4931541Srgrimes ndp->ni_dvp = dp; 4941541Srgrimes ndp->ni_vp = dp; 4951541Srgrimes VREF(dp); 4961541Srgrimes goto nextname; 4971541Srgrimes } 498101308Sjeff if ((dp->v_vflag & VV_ROOT) == 0 || 4991541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 5001541Srgrimes break; 50169405Salfred if (dp->v_mount == NULL) { /* forced unmount */ 50269405Salfred error = EBADF; 50369405Salfred goto bad; 50469405Salfred } 5051541Srgrimes tdp = dp; 506144833Sjeff dp = dp->v_mount->mnt_vnodecovered; 507140714Sjeff tvfslocked = vfslocked; 508144833Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 509144833Sjeff VREF(dp); 5101541Srgrimes vput(tdp); 511140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 512144286Sjeff vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td); 5131541Srgrimes } 5141541Srgrimes } 5151541Srgrimes 5161541Srgrimes /* 5171541Srgrimes * We now have a segment name to search for, and a directory to search. 5181541Srgrimes */ 5191541Srgrimesunionlookup: 520101127Srwatson#ifdef MAC 521105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 522105479Srwatson error = mac_check_vnode_lookup(td->td_ucred, dp, cnp); 523105479Srwatson if (error) 524105479Srwatson goto bad; 525105479Srwatson } 526101127Srwatson#endif 5271541Srgrimes ndp->ni_dvp = dp; 52822521Sdyson ndp->ni_vp = NULL; 52924624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 530144286Sjeff /* 531144286Sjeff * If we have a shared lock we may need to upgrade the lock for the 532144286Sjeff * last operation. 533144286Sjeff */ 534144286Sjeff if (VOP_ISLOCKED(dp, td) == LK_SHARED && 535144286Sjeff (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT)) 536144286Sjeff vn_lock(dp, LK_UPGRADE|LK_RETRY, td); 537144286Sjeff /* 538144286Sjeff * If we're looking up the last component and we need an exclusive 539144286Sjeff * lock, adjust our lkflags. 540144286Sjeff */ 541144286Sjeff if ((cnp->cn_flags & (ISLASTCN|LOCKSHARED|LOCKLEAF)) == 542144286Sjeff (ISLASTCN|LOCKLEAF)) 543144286Sjeff cnp->cn_lkflags = LK_EXCLUSIVE; 544138345Sphk#ifdef NAMEI_DIAGNOSTIC 545138345Sphk vprint("lookup in", dp); 546138345Sphk#endif 54743301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 54842408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 5491541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5501541Srgrimes printf("not found\n"); 5511541Srgrimes#endif 5521541Srgrimes if ((error == ENOENT) && 553101308Sjeff (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && 5541541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 5551541Srgrimes tdp = dp; 556144833Sjeff dp = dp->v_mount->mnt_vnodecovered; 557140714Sjeff tvfslocked = vfslocked; 558144833Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 559144833Sjeff VREF(dp); 560144203Sjeff vput(tdp); 561140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 562144286Sjeff vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td); 5631541Srgrimes goto unionlookup; 5641541Srgrimes } 5651541Srgrimes 5661541Srgrimes if (error != EJUSTRETURN) 5671541Srgrimes goto bad; 5681541Srgrimes /* 5691541Srgrimes * If creating and at end of pathname, then can consider 5701541Srgrimes * allowing file to be created. 5711541Srgrimes */ 57211644Sdg if (rdonly) { 5731541Srgrimes error = EROFS; 5741541Srgrimes goto bad; 5751541Srgrimes } 5769804Sbde if (*cp == '\0' && trailing_slash && 5779804Sbde !(cnp->cn_flags & WILLBEDIR)) { 5789804Sbde error = ENOENT; 5799804Sbde goto bad; 5809804Sbde } 581144203Sjeff if ((cnp->cn_flags & LOCKPARENT) == 0) 582144203Sjeff VOP_UNLOCK(dp, 0, td); 5831541Srgrimes /* 584144203Sjeff * This is a temporary assert to make sure I know what the 585144203Sjeff * behavior here was. 586144203Sjeff */ 587144203Sjeff KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0, 588144203Sjeff ("lookup: Unhandled case.")); 589144203Sjeff /* 5901541Srgrimes * We return with ni_vp NULL to indicate that the entry 5911541Srgrimes * doesn't currently exist, leaving a pointer to the 5921541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 5931541Srgrimes */ 5941541Srgrimes if (cnp->cn_flags & SAVESTART) { 5951541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5961541Srgrimes VREF(ndp->ni_startdir); 5971541Srgrimes } 598140714Sjeff goto success; 5991541Srgrimes } 6001541Srgrimes#ifdef NAMEI_DIAGNOSTIC 6011541Srgrimes printf("found\n"); 6021541Srgrimes#endif 603144203Sjeff /* 6041541Srgrimes * Take into account any additional components consumed by 6051541Srgrimes * the underlying filesystem. 6061541Srgrimes */ 6071541Srgrimes if (cnp->cn_consume > 0) { 6081541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 6091541Srgrimes ndp->ni_next += cnp->cn_consume; 6101541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 6111541Srgrimes cnp->cn_consume = 0; 6121541Srgrimes } 6131541Srgrimes 6141541Srgrimes dp = ndp->ni_vp; 6151541Srgrimes 6161541Srgrimes /* 6171541Srgrimes * Check to see if the vnode has been mounted on; 61896755Strhodes * if so find the root of the mounted filesystem. 6191541Srgrimes */ 6201541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 6211541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 622144833Sjeff KASSERT(dp != ndp->ni_dvp, ("XXX")); 62383366Sjulian if (vfs_busy(mp, 0, 0, td)) 6241541Srgrimes continue; 625144833Sjeff vput(dp); 626140714Sjeff tvfslocked = VFS_LOCK_GIANT(mp); 627144833Sjeff VFS_UNLOCK_GIANT(vfslocked); 628144833Sjeff vfslocked = tvfslocked; 629149051Skan VOP_UNLOCK(ndp->ni_dvp, 0, td); 630144286Sjeff error = VFS_ROOT(mp, cnp->cn_lkflags, &tdp, td); 631149051Skan VOP_LOCK(ndp->ni_dvp, cnp->cn_lkflags | LK_RETRY, td); 63283366Sjulian vfs_unbusy(mp, td); 63365805Sbp if (error) { 63465805Sbp dpunlocked = 1; 6351541Srgrimes goto bad2; 63665805Sbp } 6371541Srgrimes ndp->ni_vp = dp = tdp; 6381541Srgrimes } 6391541Srgrimes 64010219Sdfr /* 64110219Sdfr * Check for symbolic link 64210219Sdfr */ 64310219Sdfr if ((dp->v_type == VLNK) && 64410219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 64510219Sdfr *ndp->ni_next == '/')) { 64610219Sdfr cnp->cn_flags |= ISSYMLINK; 64769405Salfred if (dp->v_mount == NULL) { 64869405Salfred /* We can't know whether the directory was mounted with 64969405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 65069405Salfred error = EBADF; 65169405Salfred goto bad2; 65269405Salfred } 65335105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 65435105Swosch error = EACCES; 65535105Swosch goto bad2; 65635105Swosch } 657144833Sjeff /* 658144833Sjeff * Symlink code always expects an unlocked dvp. 659144833Sjeff */ 660144833Sjeff if (ndp->ni_dvp != ndp->ni_vp) 661144833Sjeff VOP_UNLOCK(ndp->ni_dvp, 0, td); 662140714Sjeff goto success; 66310219Sdfr } 66410219Sdfr 66510219Sdfr /* 66610219Sdfr * Check for bogus trailing slashes. 66710219Sdfr */ 66810219Sdfr if (trailing_slash && dp->v_type != VDIR) { 66910219Sdfr error = ENOTDIR; 67010219Sdfr goto bad2; 67110219Sdfr } 67210219Sdfr 6731541Srgrimesnextname: 6741541Srgrimes /* 6751541Srgrimes * Not a symbolic link. If more pathname, 6761541Srgrimes * continue at next component, else return. 6771541Srgrimes */ 678144203Sjeff KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/', 679144203Sjeff ("lookup: invalid path state.")); 6801541Srgrimes if (*ndp->ni_next == '/') { 6811541Srgrimes cnp->cn_nameptr = ndp->ni_next; 6821541Srgrimes while (*cnp->cn_nameptr == '/') { 6831541Srgrimes cnp->cn_nameptr++; 6841541Srgrimes ndp->ni_pathlen--; 6851541Srgrimes } 686144833Sjeff if (ndp->ni_dvp != dp) 687144833Sjeff vput(ndp->ni_dvp); 688144833Sjeff else 689144833Sjeff vrele(ndp->ni_dvp); 6901541Srgrimes goto dirloop; 6911541Srgrimes } 6921541Srgrimes /* 69396755Strhodes * Disallow directory write attempts on read-only filesystems. 6941541Srgrimes */ 69511644Sdg if (rdonly && 69611644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 69711644Sdg error = EROFS; 69811644Sdg goto bad2; 6991541Srgrimes } 7001541Srgrimes if (cnp->cn_flags & SAVESTART) { 7011541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 7021541Srgrimes VREF(ndp->ni_startdir); 7031541Srgrimes } 704144833Sjeff if (!wantparent) { 705144833Sjeff if (ndp->ni_dvp != dp) 706144833Sjeff vput(ndp->ni_dvp); 707144833Sjeff else 708144833Sjeff vrele(ndp->ni_dvp); 709144833Sjeff } else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) 710144833Sjeff VOP_UNLOCK(ndp->ni_dvp, 0, td); 71132071Sdyson 7121541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 71383366Sjulian VOP_UNLOCK(dp, 0, td); 714140714Sjeffsuccess: 715140714Sjeff if (vfslocked) 716140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 7171541Srgrimes return (0); 7181541Srgrimes 7191541Srgrimesbad2: 720144833Sjeff if (dp != ndp->ni_dvp) 721144203Sjeff vput(ndp->ni_dvp); 722144203Sjeff else 723144203Sjeff vrele(ndp->ni_dvp); 7241541Srgrimesbad: 725144833Sjeff if (!dpunlocked) 72665805Sbp vput(dp); 727140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 728140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 7291541Srgrimes ndp->ni_vp = NULL; 7301541Srgrimes return (error); 7311541Srgrimes} 7321541Srgrimes 7333148Sphk/* 7343148Sphk * relookup - lookup a path name component 7353148Sphk * Used by lookup to re-aquire things. 7363148Sphk */ 7373148Sphkint 7383148Sphkrelookup(dvp, vpp, cnp) 7393148Sphk struct vnode *dvp, **vpp; 7403148Sphk struct componentname *cnp; 7413148Sphk{ 74283366Sjulian struct thread *td = cnp->cn_thread; 74322521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 7443148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 7453148Sphk int rdonly; /* lookup read-only flag bit */ 7463148Sphk int error = 0; 7471541Srgrimes 748144203Sjeff KASSERT(cnp->cn_flags & ISLASTCN, 749144203Sjeff ("relookup: Not given last component.")); 7503148Sphk /* 7513148Sphk * Setup: break out flag bits into variables. 7523148Sphk */ 7533148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 754145004Sjeff KASSERT(wantparent, ("relookup: parent not wanted.")); 7553148Sphk rdonly = cnp->cn_flags & RDONLY; 7563148Sphk cnp->cn_flags &= ~ISSYMLINK; 7573148Sphk dp = dvp; 758144286Sjeff cnp->cn_lkflags = LK_EXCLUSIVE; 75983366Sjulian vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 7603148Sphk 7613148Sphk /* 7623148Sphk * Search a new directory. 7633148Sphk * 7643148Sphk * The last component of the filename is left accessible via 7653148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 7663148Sphk * the name set the SAVENAME flag. When done, they assume 7673148Sphk * responsibility for freeing the pathname buffer. 7683148Sphk */ 7693148Sphk#ifdef NAMEI_DIAGNOSTIC 7703148Sphk printf("{%s}: ", cnp->cn_nameptr); 7713148Sphk#endif 7723148Sphk 7733148Sphk /* 7743148Sphk * Check for degenerate name (e.g. / or "") 7753148Sphk * which is a way of talking about a directory, 7763148Sphk * e.g. like "/." or ".". 7773148Sphk */ 7783148Sphk if (cnp->cn_nameptr[0] == '\0') { 7793148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 7803148Sphk error = EISDIR; 7813148Sphk goto bad; 7823148Sphk } 7833148Sphk if (dp->v_type != VDIR) { 7843148Sphk error = ENOTDIR; 7853148Sphk goto bad; 7863148Sphk } 7873148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 78883366Sjulian VOP_UNLOCK(dp, 0, td); 7893148Sphk *vpp = dp; 79054655Seivind /* XXX This should probably move to the top of function. */ 7913148Sphk if (cnp->cn_flags & SAVESTART) 7923148Sphk panic("lookup: SAVESTART"); 7933148Sphk return (0); 7943148Sphk } 7953148Sphk 7963148Sphk if (cnp->cn_flags & ISDOTDOT) 7973148Sphk panic ("relookup: lookup on dot-dot"); 7983148Sphk 7993148Sphk /* 8003148Sphk * We now have a segment name to search for, and a directory to search. 8013148Sphk */ 802138345Sphk#ifdef NAMEI_DIAGNOSTIC 803138345Sphk vprint("search in:", dp); 804138345Sphk#endif 80543311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 80642408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 8073148Sphk if (error != EJUSTRETURN) 8083148Sphk goto bad; 8093148Sphk /* 8103148Sphk * If creating and at end of pathname, then can consider 8113148Sphk * allowing file to be created. 8123148Sphk */ 81311644Sdg if (rdonly) { 8143148Sphk error = EROFS; 8153148Sphk goto bad; 8163148Sphk } 8173148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 8183148Sphk if (cnp->cn_flags & SAVESTART) 8193148Sphk VREF(dvp); 820144203Sjeff if ((cnp->cn_flags & LOCKPARENT) == 0) 821144203Sjeff VOP_UNLOCK(dp, 0, td); 8223148Sphk /* 823144203Sjeff * This is a temporary assert to make sure I know what the 824144203Sjeff * behavior here was. 825144203Sjeff */ 826144203Sjeff KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0, 827144203Sjeff ("relookup: Unhandled case.")); 828144203Sjeff /* 8293148Sphk * We return with ni_vp NULL to indicate that the entry 8303148Sphk * doesn't currently exist, leaving a pointer to the 8313148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 8323148Sphk */ 8333148Sphk return (0); 8343148Sphk } 8353148Sphk dp = *vpp; 8363148Sphk 8373148Sphk /* 83896755Strhodes * Disallow directory write attempts on read-only filesystems. 8393148Sphk */ 84011644Sdg if (rdonly && 84111644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 842145004Sjeff if (dvp == dp) 843145004Sjeff vrele(dvp); 844145004Sjeff else 845145004Sjeff vput(dvp); 84611644Sdg error = EROFS; 847145004Sjeff goto bad; 8483148Sphk } 849145004Sjeff /* 850145004Sjeff * Set the parent lock/ref state to the requested state. 851145004Sjeff */ 852145004Sjeff if ((cnp->cn_flags & LOCKPARENT) == 0 && dvp != dp) { 853145004Sjeff if (wantparent) 854145004Sjeff VOP_UNLOCK(dvp, 0, td); 855145004Sjeff else 856145004Sjeff vput(dvp); 857145004Sjeff } else if (!wantparent) 858145004Sjeff vrele(dvp); 859145004Sjeff /* 860145004Sjeff * Check for symbolic link 861145004Sjeff */ 862145004Sjeff KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 863145004Sjeff ("relookup: symlink found.\n")); 864145004Sjeff 8653148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 8663148Sphk if (cnp->cn_flags & SAVESTART) 8673148Sphk VREF(dvp); 86822521Sdyson 8693148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 87083366Sjulian VOP_UNLOCK(dp, 0, td); 8713148Sphk return (0); 8723148Sphkbad: 8733148Sphk vput(dp); 8743148Sphk *vpp = NULL; 8753148Sphk return (error); 8763148Sphk} 877141471Sjhb 878141471Sjhb/* 879144661Sjeff * Free data allocated by namei(); see namei(9) for details. 880144661Sjeff */ 881144661Sjeffvoid 882144661SjeffNDFREE(ndp, flags) 883144661Sjeff struct nameidata *ndp; 884144661Sjeff const u_int flags; 885144661Sjeff{ 886144833Sjeff int unlock_dvp; 887144833Sjeff int unlock_vp; 888144661Sjeff 889144833Sjeff unlock_dvp = 0; 890144833Sjeff unlock_vp = 0; 891144833Sjeff 892144661Sjeff if (!(flags & NDF_NO_FREE_PNBUF) && 893144661Sjeff (ndp->ni_cnd.cn_flags & HASBUF)) { 894144661Sjeff uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); 895144661Sjeff ndp->ni_cnd.cn_flags &= ~HASBUF; 896144661Sjeff } 897144833Sjeff if (!(flags & NDF_NO_VP_UNLOCK) && 898144833Sjeff (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp) 899144833Sjeff unlock_vp = 1; 900144833Sjeff if (!(flags & NDF_NO_VP_RELE) && ndp->ni_vp) { 901144833Sjeff if (unlock_vp) { 902144833Sjeff vput(ndp->ni_vp); 903144833Sjeff unlock_vp = 0; 904144833Sjeff } else 905144833Sjeff vrele(ndp->ni_vp); 906144833Sjeff ndp->ni_vp = NULL; 907144833Sjeff } 908144833Sjeff if (unlock_vp) 909144833Sjeff VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_thread); 910144661Sjeff if (!(flags & NDF_NO_DVP_UNLOCK) && 911144661Sjeff (ndp->ni_cnd.cn_flags & LOCKPARENT) && 912144661Sjeff ndp->ni_dvp != ndp->ni_vp) 913144833Sjeff unlock_dvp = 1; 914144661Sjeff if (!(flags & NDF_NO_DVP_RELE) && 915144661Sjeff (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) { 916144833Sjeff if (unlock_dvp) { 917144833Sjeff vput(ndp->ni_dvp); 918144833Sjeff unlock_dvp = 0; 919144833Sjeff } else 920144833Sjeff vrele(ndp->ni_dvp); 921144661Sjeff ndp->ni_dvp = NULL; 922144661Sjeff } 923144833Sjeff if (unlock_dvp) 924144833Sjeff VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_thread); 925144661Sjeff if (!(flags & NDF_NO_STARTDIR_RELE) && 926144661Sjeff (ndp->ni_cnd.cn_flags & SAVESTART)) { 927144661Sjeff vrele(ndp->ni_startdir); 928144661Sjeff ndp->ni_startdir = NULL; 929144661Sjeff } 930144661Sjeff} 931144661Sjeff 932144661Sjeff/* 933141471Sjhb * Determine if there is a suitable alternate filename under the specified 934141471Sjhb * prefix for the specified path. If the create flag is set, then the 935141471Sjhb * alternate prefix will be used so long as the parent directory exists. 936141471Sjhb * This is used by the various compatiblity ABIs so that Linux binaries prefer 937141471Sjhb * files under /compat/linux for example. The chosen path (whether under 938141471Sjhb * the prefix or under /) is returned in a kernel malloc'd buffer pointed 939141471Sjhb * to by pathbuf. The caller is responsible for free'ing the buffer from 940141471Sjhb * the M_TEMP bucket if one is returned. 941141471Sjhb */ 942141471Sjhbint 943141471Sjhbkern_alternate_path(struct thread *td, const char *prefix, char *path, 944141471Sjhb enum uio_seg pathseg, char **pathbuf, int create) 945141471Sjhb{ 946141471Sjhb struct nameidata nd, ndroot; 947141471Sjhb char *ptr, *buf, *cp; 948141471Sjhb size_t len, sz; 949141471Sjhb int error; 950141471Sjhb 951141471Sjhb buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 952141471Sjhb *pathbuf = buf; 953141471Sjhb 954141471Sjhb /* Copy the prefix into the new pathname as a starting point. */ 955141471Sjhb len = strlcpy(buf, prefix, MAXPATHLEN); 956141471Sjhb if (len >= MAXPATHLEN) { 957141471Sjhb *pathbuf = NULL; 958141471Sjhb free(buf, M_TEMP); 959141471Sjhb return (EINVAL); 960141471Sjhb } 961141471Sjhb sz = MAXPATHLEN - len; 962141471Sjhb ptr = buf + len; 963141471Sjhb 964141471Sjhb /* Append the filename to the prefix. */ 965141471Sjhb if (pathseg == UIO_SYSSPACE) 966141471Sjhb error = copystr(path, ptr, sz, &len); 967141471Sjhb else 968141471Sjhb error = copyinstr(path, ptr, sz, &len); 969141471Sjhb 970141471Sjhb if (error) { 971141471Sjhb *pathbuf = NULL; 972141471Sjhb free(buf, M_TEMP); 973141471Sjhb return (error); 974141471Sjhb } 975141471Sjhb 976141471Sjhb /* Only use a prefix with absolute pathnames. */ 977141471Sjhb if (*ptr != '/') { 978141471Sjhb error = EINVAL; 979141471Sjhb goto keeporig; 980141471Sjhb } 981141471Sjhb 982141471Sjhb /* 983141471Sjhb * We know that there is a / somewhere in this pathname. 984141471Sjhb * Search backwards for it, to find the file's parent dir 985141471Sjhb * to see if it exists in the alternate tree. If it does, 986141471Sjhb * and we want to create a file (cflag is set). We don't 987141471Sjhb * need to worry about the root comparison in this case. 988141471Sjhb */ 989141471Sjhb 990141471Sjhb if (create) { 991141471Sjhb for (cp = &ptr[len] - 1; *cp != '/'; cp--); 992141471Sjhb *cp = '\0'; 993141471Sjhb 994150431Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td); 995141471Sjhb error = namei(&nd); 996141471Sjhb *cp = '/'; 997141471Sjhb if (error != 0) 998150431Sjhb goto keeporig; 999141471Sjhb } else { 1000150431Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td); 1001141471Sjhb 1002141471Sjhb error = namei(&nd); 1003141471Sjhb if (error != 0) 1004150431Sjhb goto keeporig; 1005141471Sjhb 1006141471Sjhb /* 1007141471Sjhb * We now compare the vnode of the prefix to the one 1008141471Sjhb * vnode asked. If they resolve to be the same, then we 1009141471Sjhb * ignore the match so that the real root gets used. 1010141471Sjhb * This avoids the problem of traversing "../.." to find the 1011141471Sjhb * root directory and never finding it, because "/" resolves 1012141471Sjhb * to the emulation root directory. This is expensive :-( 1013141471Sjhb */ 1014150431Sjhb NDINIT(&ndroot, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, prefix, 1015150431Sjhb td); 1016141471Sjhb 1017141471Sjhb /* We shouldn't ever get an error from this namei(). */ 1018141471Sjhb error = namei(&ndroot); 1019141471Sjhb if (error == 0) { 1020141471Sjhb if (nd.ni_vp == ndroot.ni_vp) 1021141471Sjhb error = ENOENT; 1022141471Sjhb 1023141471Sjhb NDFREE(&ndroot, NDF_ONLY_PNBUF); 1024141471Sjhb vrele(ndroot.ni_vp); 1025150431Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&ndroot)); 1026141471Sjhb } 1027141471Sjhb } 1028141471Sjhb 1029141471Sjhb NDFREE(&nd, NDF_ONLY_PNBUF); 1030141471Sjhb vrele(nd.ni_vp); 1031150431Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 1032141471Sjhb 1033141471Sjhbkeeporig: 1034141471Sjhb /* If there was an error, use the original path name. */ 1035141471Sjhb if (error) 1036141471Sjhb bcopy(ptr, buf, len); 1037141471Sjhb return (error); 1038141471Sjhb} 1039