vfs_lookup.c revision 175202
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 175202 2008-01-10 01:10:58Z attilio $"); 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> 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> 54141471Sjhb#include <sys/syscallsubr.h> 55144613Sjeff#include <sys/sysctl.h> 561541Srgrimes#ifdef KTRACE 571541Srgrimes#include <sys/ktrace.h> 581541Srgrimes#endif 591541Srgrimes 60155334Srwatson#include <security/audit/audit.h> 61163606Srwatson#include <security/mac/mac_framework.h> 62155334Srwatson 6392751Sjeff#include <vm/uma.h> 6432011Sbde 65155168Sjeff#define NAMEI_DIAGNOSTIC 1 66138345Sphk#undef NAMEI_DIAGNOSTIC 67138345Sphk 681541Srgrimes/* 6969664Speter * Allocation zone for namei 7069664Speter */ 7192751Sjeffuma_zone_t namei_zone; 72166167Skib/* 73166167Skib * Placeholder vnode for mp traversal 74166167Skib */ 75166167Skibstatic struct vnode *vp_crossmp; 7669664Speter 7769664Speterstatic void 7869664Speternameiinit(void *dummy __unused) 7969664Speter{ 80168138Srwatson int error; 81168138Srwatson 8292654Sjeff namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, 8392654Sjeff UMA_ALIGN_PTR, 0); 84168138Srwatson error = getnewvnode("crossmp", NULL, &dead_vnodeops, &vp_crossmp); 85168138Srwatson if (error != 0) 86168138Srwatson panic("nameiinit: getnewvnode"); 87166167Skib vp_crossmp->v_vnlock->lk_flags &= ~LK_NOSHARE; 8869664Speter} 8969664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL) 9069664Speter 91144613Sjeff#ifdef LOOKUP_SHARED 92144613Sjeffstatic int lookup_shared = 1; 93144613Sjeff#else 94144613Sjeffstatic int lookup_shared = 0; 95144613Sjeff#endif 96144613SjeffSYSCTL_INT(_vfs, OID_AUTO, lookup_shared, CTLFLAG_RW, &lookup_shared, 0, 97144613Sjeff "Enables/Disables shared locks for path name translation"); 98144613Sjeff 9969664Speter/* 100161010Srwatson * Convert a pathname into a pointer to a locked vnode. 1011541Srgrimes * 1021541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 1031541Srgrimes * when they occur at the end of the name translation process. 1041541Srgrimes * Symbolic links are always followed for all other pathname 1051541Srgrimes * components other than the last. 1061541Srgrimes * 1071541Srgrimes * The segflg defines whether the name is to be copied from user 1081541Srgrimes * space or kernel space. 1091541Srgrimes * 1101541Srgrimes * Overall outline of namei: 1111541Srgrimes * 1121541Srgrimes * copy in name 1131541Srgrimes * get starting directory 1141541Srgrimes * while (!done && !error) { 1151541Srgrimes * call lookup to search path. 1161541Srgrimes * if symbolic link, massage name in buffer and continue 1171541Srgrimes * } 1181541Srgrimes */ 1191541Srgrimesint 120161011Srwatsonnamei(struct nameidata *ndp) 1211541Srgrimes{ 122161011Srwatson struct filedesc *fdp; /* pointer to file descriptor state */ 123161011Srwatson char *cp; /* pointer into pathname argument */ 124161011Srwatson struct vnode *dp; /* the directory we are searching */ 1251541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 1261541Srgrimes struct uio auio; 1271541Srgrimes int error, linklen; 1281541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 12983366Sjulian struct thread *td = cnp->cn_thread; 13083366Sjulian struct proc *p = td->td_proc; 131140714Sjeff int vfslocked; 1321541Srgrimes 133150164Scsjp KASSERT((cnp->cn_flags & MPSAFE) != 0 || mtx_owned(&Giant) != 0, 134150164Scsjp ("NOT MPSAFE and Giant not held")); 13591419Sjhb ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; 13683366Sjulian KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); 13742408Seivind KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0, 13842453Seivind ("namei: nameiop contaminated with flags")); 13942408Seivind KASSERT((cnp->cn_flags & OPMASK) == 0, 14042453Seivind ("namei: flags contaminated with nameiops")); 141144613Sjeff if (!lookup_shared) 142144613Sjeff cnp->cn_flags &= ~LOCKSHARED; 14383366Sjulian fdp = p->p_fd; 1441541Srgrimes 1451541Srgrimes /* 1461541Srgrimes * Get a buffer for the name to be translated, and copy the 1471541Srgrimes * name into the buffer. 1481541Srgrimes */ 1491541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 150111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 1511541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1521541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 15336735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 1541541Srgrimes else 1551541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 15636735Sdfr MAXPATHLEN, (size_t *)&ndp->ni_pathlen); 15720069Sbde 158155334Srwatson /* If we are auditing the kernel pathname, save the user pathname. */ 159155334Srwatson if (cnp->cn_flags & AUDITVNODE1) 160155334Srwatson AUDIT_ARG(upath, td, cnp->cn_pnbuf, ARG_UPATH1); 161155334Srwatson if (cnp->cn_flags & AUDITVNODE2) 162155334Srwatson AUDIT_ARG(upath, td, cnp->cn_pnbuf, ARG_UPATH2); 163155334Srwatson 16420069Sbde /* 16520069Sbde * Don't allow empty pathnames. 16620069Sbde */ 16720069Sbde if (!error && *cnp->cn_pnbuf == '\0') 16820069Sbde error = ENOENT; 16920069Sbde 1701541Srgrimes if (error) { 17192751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 172100613Srwatson#ifdef DIAGNOSTIC 173100613Srwatson cnp->cn_pnbuf = NULL; 174100613Srwatson cnp->cn_nameptr = NULL; 175100613Srwatson#endif 1761541Srgrimes ndp->ni_vp = NULL; 1771541Srgrimes return (error); 1781541Srgrimes } 1791541Srgrimes ndp->ni_loopcnt = 0; 1801541Srgrimes#ifdef KTRACE 18197994Sjhb if (KTRPOINT(td, KTR_NAMEI)) { 18297994Sjhb KASSERT(cnp->cn_thread == curthread, 18397994Sjhb ("namei not using curthread")); 18497994Sjhb ktrnamei(cnp->cn_pnbuf); 18597994Sjhb } 1861541Srgrimes#endif 1871541Srgrimes 1881541Srgrimes /* 1891541Srgrimes * Get starting point for the translation. 1901541Srgrimes */ 191168355Srwatson FILEDESC_SLOCK(fdp); 19233360Sdyson ndp->ni_rootdir = fdp->fd_rdir; 19351649Sphk ndp->ni_topdir = fdp->fd_jdir; 19433360Sdyson 1951541Srgrimes dp = fdp->fd_cdir; 196140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 1971541Srgrimes VREF(dp); 198168355Srwatson FILEDESC_SUNLOCK(fdp); 1991541Srgrimes for (;;) { 2001541Srgrimes /* 2011541Srgrimes * Check if root directory should replace current directory. 2021541Srgrimes * Done at start of translation and after symbolic link. 2031541Srgrimes */ 2041541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 2051541Srgrimes if (*(cnp->cn_nameptr) == '/') { 2061541Srgrimes vrele(dp); 207140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 2081541Srgrimes while (*(cnp->cn_nameptr) == '/') { 2091541Srgrimes cnp->cn_nameptr++; 2101541Srgrimes ndp->ni_pathlen--; 2111541Srgrimes } 2121541Srgrimes dp = ndp->ni_rootdir; 213140714Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 2141541Srgrimes VREF(dp); 2151541Srgrimes } 216140714Sjeff if (vfslocked) 217140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 2181541Srgrimes ndp->ni_startdir = dp; 2193148Sphk error = lookup(ndp); 2203148Sphk if (error) { 22192751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 222100613Srwatson#ifdef DIAGNOSTIC 223100613Srwatson cnp->cn_pnbuf = NULL; 224100613Srwatson cnp->cn_nameptr = NULL; 225100613Srwatson#endif 2261541Srgrimes return (error); 2271541Srgrimes } 228140714Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 229140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 2301541Srgrimes /* 2311541Srgrimes * Check for symbolic link 2321541Srgrimes */ 2331541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 234100613Srwatson if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 23592751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 236100613Srwatson#ifdef DIAGNOSTIC 237100613Srwatson cnp->cn_pnbuf = NULL; 238100613Srwatson cnp->cn_nameptr = NULL; 239100613Srwatson#endif 240100613Srwatson } else 2411541Srgrimes cnp->cn_flags |= HASBUF; 24232286Sdyson 243140714Sjeff if ((cnp->cn_flags & MPSAFE) == 0) { 244140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 245140714Sjeff } else if (vfslocked) 246140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 2471541Srgrimes return (0); 2481541Srgrimes } 2491541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 2501541Srgrimes error = ELOOP; 2511541Srgrimes break; 2521541Srgrimes } 253101127Srwatson#ifdef MAC 254105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 255172930Srwatson error = mac_vnode_check_readlink(td->td_ucred, 256105479Srwatson ndp->ni_vp); 257105479Srwatson if (error) 258105479Srwatson break; 259105479Srwatson } 260101127Srwatson#endif 2611541Srgrimes if (ndp->ni_pathlen > 1) 262111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 2631541Srgrimes else 2641541Srgrimes cp = cnp->cn_pnbuf; 2651541Srgrimes aiov.iov_base = cp; 2661541Srgrimes aiov.iov_len = MAXPATHLEN; 2671541Srgrimes auio.uio_iov = &aiov; 2681541Srgrimes auio.uio_iovcnt = 1; 2691541Srgrimes auio.uio_offset = 0; 2701541Srgrimes auio.uio_rw = UIO_READ; 2711541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 27283366Sjulian auio.uio_td = (struct thread *)0; 2731541Srgrimes auio.uio_resid = MAXPATHLEN; 2743148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 2753148Sphk if (error) { 2761541Srgrimes if (ndp->ni_pathlen > 1) 27792751Sjeff uma_zfree(namei_zone, cp); 2781541Srgrimes break; 2791541Srgrimes } 2801541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 28178692Sdillon if (linklen == 0) { 28278692Sdillon if (ndp->ni_pathlen > 1) 28392751Sjeff uma_zfree(namei_zone, cp); 28478692Sdillon error = ENOENT; 28578692Sdillon break; 28678692Sdillon } 2871541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 2881541Srgrimes if (ndp->ni_pathlen > 1) 28992751Sjeff uma_zfree(namei_zone, cp); 2901541Srgrimes error = ENAMETOOLONG; 2911541Srgrimes break; 2921541Srgrimes } 2931541Srgrimes if (ndp->ni_pathlen > 1) { 2941541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 29592751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 2961541Srgrimes cnp->cn_pnbuf = cp; 2971541Srgrimes } else 2981541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2991541Srgrimes ndp->ni_pathlen += linklen; 3001541Srgrimes vput(ndp->ni_vp); 3011541Srgrimes dp = ndp->ni_dvp; 3021541Srgrimes } 30392751Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 304100613Srwatson#ifdef DIAGNOSTIC 305100613Srwatson cnp->cn_pnbuf = NULL; 306100613Srwatson cnp->cn_nameptr = NULL; 307100613Srwatson#endif 308144833Sjeff vput(ndp->ni_vp); 309144833Sjeff ndp->ni_vp = NULL; 3101541Srgrimes vrele(ndp->ni_dvp); 311140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 3121541Srgrimes return (error); 3131541Srgrimes} 3141541Srgrimes 315162288Smohansstatic int 316162288Smohanscompute_cn_lkflags(struct mount *mp, int lkflags) 317162288Smohans{ 318162310Smohans if (mp == NULL || 319162310Smohans ((lkflags & LK_SHARED) && !(mp->mnt_kern_flag & MNTK_LOOKUP_SHARED))) { 320162288Smohans lkflags &= ~LK_SHARED; 321162288Smohans lkflags |= LK_EXCLUSIVE; 322162288Smohans } 323162288Smohans return lkflags; 324162288Smohans} 325162288Smohans 3261541Srgrimes/* 3271541Srgrimes * Search a pathname. 3281541Srgrimes * This is a very central and rather complicated routine. 3291541Srgrimes * 3301541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 3311541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 3321541Srgrimes * descended until done, or a symbolic link is encountered. The variable 3331541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 3341541Srgrimes * symbolic link needing interpretation is encountered. 3351541Srgrimes * 3361541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 3371541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 3381541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 3391541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 3401541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 3411541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 3421541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 3431541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 3441541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 3451541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 3461541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 3478876Srgrimes * 3481541Srgrimes * Overall outline of lookup: 3491541Srgrimes * 3501541Srgrimes * dirloop: 3511541Srgrimes * identify next component of name at ndp->ni_ptr 3521541Srgrimes * handle degenerate case where name is null string 3531541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 3541541Srgrimes * call VOP_LOOKUP routine for next component name 3551541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 3561541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 3571541Srgrimes * if result vnode is mounted on and crossing mount points, 3581541Srgrimes * find mounted on vnode 3591541Srgrimes * if more components of name, do next level at dirloop 3601541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 3611541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 3621541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 3631541Srgrimes */ 3641541Srgrimesint 365161011Srwatsonlookup(struct nameidata *ndp) 3661541Srgrimes{ 367161011Srwatson char *cp; /* pointer into pathname argument */ 368161011Srwatson struct vnode *dp = 0; /* the directory we are searching */ 3691541Srgrimes struct vnode *tdp; /* saved dp */ 3701541Srgrimes struct mount *mp; /* mount table entry */ 3711541Srgrimes int docache; /* == 0 do not cache last component */ 3721541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 3731541Srgrimes int rdonly; /* lookup read-only flag bit */ 3749804Sbde int trailing_slash; 3751541Srgrimes int error = 0; 37665805Sbp int dpunlocked = 0; /* dp has already been unlocked */ 3771541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 37883366Sjulian struct thread *td = cnp->cn_thread; 379158094Sjeff int vfslocked; /* VFS Giant state for child */ 380158094Sjeff int dvfslocked; /* VFS Giant state for parent */ 381140714Sjeff int tvfslocked; 382162288Smohans int lkflags_save; 383162288Smohans 3841541Srgrimes /* 3851541Srgrimes * Setup: break out flag bits into variables. 3861541Srgrimes */ 387158094Sjeff dvfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 388158094Sjeff vfslocked = 0; 389140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 3901541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 391144229Sjeff KASSERT(cnp->cn_nameiop == LOOKUP || wantparent, 392144229Sjeff ("CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT.")); 3931541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 3941541Srgrimes if (cnp->cn_nameiop == DELETE || 39522874Sbde (wantparent && cnp->cn_nameiop != CREATE && 39622874Sbde cnp->cn_nameiop != LOOKUP)) 3971541Srgrimes docache = 0; 3981541Srgrimes rdonly = cnp->cn_flags & RDONLY; 399144286Sjeff cnp->cn_flags &= ~ISSYMLINK; 4001541Srgrimes ndp->ni_dvp = NULL; 401144286Sjeff /* 402144286Sjeff * We use shared locks until we hit the parent of the last cn then 403144286Sjeff * we adjust based on the requesting flags. 404144286Sjeff */ 405144613Sjeff if (lookup_shared) 406144613Sjeff cnp->cn_lkflags = LK_SHARED; 407144613Sjeff else 408144613Sjeff cnp->cn_lkflags = LK_EXCLUSIVE; 4091541Srgrimes dp = ndp->ni_startdir; 4101541Srgrimes ndp->ni_startdir = NULLVP; 411175202Sattilio vn_lock(dp, 412175202Sattilio compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); 4131541Srgrimes 4141541Srgrimesdirloop: 4151541Srgrimes /* 4161541Srgrimes * Search a new directory. 4171541Srgrimes * 4181541Srgrimes * The last component of the filename is left accessible via 4191541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 4201541Srgrimes * the name set the SAVENAME flag. When done, they assume 4211541Srgrimes * responsibility for freeing the pathname buffer. 4221541Srgrimes */ 4231541Srgrimes cnp->cn_consume = 0; 4241541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 42551906Sphk continue; 4261541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 4271541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 4281541Srgrimes error = ENAMETOOLONG; 4291541Srgrimes goto bad; 4301541Srgrimes } 4311541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4321541Srgrimes { char c = *cp; 4331541Srgrimes *cp = '\0'; 4341541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 4351541Srgrimes *cp = c; } 4361541Srgrimes#endif 4371541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 4381541Srgrimes ndp->ni_next = cp; 4399804Sbde 4409804Sbde /* 4419804Sbde * Replace multiple slashes by a single slash and trailing slashes 4429804Sbde * by a null. This must be done before VOP_LOOKUP() because some 4439804Sbde * fs's don't know about trailing slashes. Remember if there were 4449804Sbde * trailing slashes to handle symlinks, existing non-directories 4459804Sbde * and non-existing files that won't be directories specially later. 4469804Sbde */ 4479804Sbde trailing_slash = 0; 4489804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 4499804Sbde cp++; 4509804Sbde ndp->ni_pathlen--; 4519804Sbde if (*cp == '\0') { 4529804Sbde trailing_slash = 1; 4539804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 4549804Sbde } 4559804Sbde } 4569804Sbde ndp->ni_next = cp; 4579804Sbde 4581541Srgrimes cnp->cn_flags |= MAKEENTRY; 4591541Srgrimes if (*cp == '\0' && docache == 0) 4601541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 4611541Srgrimes if (cnp->cn_namelen == 2 && 4621541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 4631541Srgrimes cnp->cn_flags |= ISDOTDOT; 4641541Srgrimes else 4651541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 4661541Srgrimes if (*ndp->ni_next == 0) 4671541Srgrimes cnp->cn_flags |= ISLASTCN; 4681541Srgrimes else 4691541Srgrimes cnp->cn_flags &= ~ISLASTCN; 4701541Srgrimes 4711541Srgrimes 4721541Srgrimes /* 4731541Srgrimes * Check for degenerate name (e.g. / or "") 4741541Srgrimes * which is a way of talking about a directory, 4751541Srgrimes * e.g. like "/." or ".". 4761541Srgrimes */ 4771541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 47822521Sdyson if (dp->v_type != VDIR) { 47922521Sdyson error = ENOTDIR; 48022521Sdyson goto bad; 48122521Sdyson } 4821541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 4831541Srgrimes error = EISDIR; 4841541Srgrimes goto bad; 4851541Srgrimes } 4861541Srgrimes if (wantparent) { 4871541Srgrimes ndp->ni_dvp = dp; 4881541Srgrimes VREF(dp); 4891541Srgrimes } 4901541Srgrimes ndp->ni_vp = dp; 491155334Srwatson 492155334Srwatson if (cnp->cn_flags & AUDITVNODE1) 493155334Srwatson AUDIT_ARG(vnode, dp, ARG_VNODE1); 494155334Srwatson else if (cnp->cn_flags & AUDITVNODE2) 495155334Srwatson AUDIT_ARG(vnode, dp, ARG_VNODE2); 496155334Srwatson 4971541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 49883366Sjulian VOP_UNLOCK(dp, 0, td); 49954655Seivind /* XXX This should probably move to the top of function. */ 5001541Srgrimes if (cnp->cn_flags & SAVESTART) 5011541Srgrimes panic("lookup: SAVESTART"); 502140714Sjeff goto success; 5031541Srgrimes } 5041541Srgrimes 5051541Srgrimes /* 506154649Struckman * Handle "..": four special cases. 507154649Struckman * 1. Return an error if this is the last component of 508154649Struckman * the name and the operation is DELETE or RENAME. 509154649Struckman * 2. If at root directory (e.g. after chroot) 5101541Srgrimes * or at absolute root directory 5111541Srgrimes * then ignore it so can't get out. 512154649Struckman * 3. If this vnode is the root of a mounted 5131541Srgrimes * filesystem, then replace it with the 5141541Srgrimes * vnode which was mounted on so we take the 51596755Strhodes * .. in the other filesystem. 516154649Struckman * 4. If the vnode is the top directory of 51751649Sphk * the jail or chroot, don't let them out. 5181541Srgrimes */ 5191541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 520154649Struckman if ((cnp->cn_flags & ISLASTCN) != 0 && 521154649Struckman (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 522154690Struckman error = EINVAL; 523154649Struckman goto bad; 524154649Struckman } 5251541Srgrimes for (;;) { 52651649Sphk if (dp == ndp->ni_rootdir || 52751649Sphk dp == ndp->ni_topdir || 528166744Skib dp == rootvnode || 529166744Skib ((dp->v_vflag & VV_ROOT) != 0 && 530166744Skib (cnp->cn_flags & NOCROSSMOUNT) != 0)) { 5311541Srgrimes ndp->ni_dvp = dp; 5321541Srgrimes ndp->ni_vp = dp; 533158142Skris vfslocked = VFS_LOCK_GIANT(dp->v_mount); 5341541Srgrimes VREF(dp); 5351541Srgrimes goto nextname; 5361541Srgrimes } 537166744Skib if ((dp->v_vflag & VV_ROOT) == 0) 5381541Srgrimes break; 539155385Sjeff if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ 54069405Salfred error = EBADF; 54169405Salfred goto bad; 54269405Salfred } 5431541Srgrimes tdp = dp; 544144833Sjeff dp = dp->v_mount->mnt_vnodecovered; 545158094Sjeff tvfslocked = dvfslocked; 546158094Sjeff dvfslocked = VFS_LOCK_GIANT(dp->v_mount); 547144833Sjeff VREF(dp); 5481541Srgrimes vput(tdp); 549140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 550175202Sattilio vn_lock(dp, 551175202Sattilio compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | 552175202Sattilio LK_RETRY)); 5531541Srgrimes } 5541541Srgrimes } 5551541Srgrimes 5561541Srgrimes /* 5571541Srgrimes * We now have a segment name to search for, and a directory to search. 5581541Srgrimes */ 5591541Srgrimesunionlookup: 560101127Srwatson#ifdef MAC 561105479Srwatson if ((cnp->cn_flags & NOMACCHECK) == 0) { 562172930Srwatson error = mac_vnode_check_lookup(td->td_ucred, dp, cnp); 563105479Srwatson if (error) 564105479Srwatson goto bad; 565105479Srwatson } 566101127Srwatson#endif 5671541Srgrimes ndp->ni_dvp = dp; 56822521Sdyson ndp->ni_vp = NULL; 56924624Sdfr ASSERT_VOP_LOCKED(dp, "lookup"); 570158094Sjeff VNASSERT(vfslocked == 0, dp, ("lookup: vfslocked %d", vfslocked)); 571144286Sjeff /* 572144286Sjeff * If we have a shared lock we may need to upgrade the lock for the 573144286Sjeff * last operation. 574144286Sjeff */ 575166167Skib if (dp != vp_crossmp && 576166167Skib VOP_ISLOCKED(dp, td) == LK_SHARED && 577144286Sjeff (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT)) 578175202Sattilio vn_lock(dp, LK_UPGRADE|LK_RETRY); 579144286Sjeff /* 580144286Sjeff * If we're looking up the last component and we need an exclusive 581144286Sjeff * lock, adjust our lkflags. 582144286Sjeff */ 583144286Sjeff if ((cnp->cn_flags & (ISLASTCN|LOCKSHARED|LOCKLEAF)) == 584144286Sjeff (ISLASTCN|LOCKLEAF)) 585144286Sjeff cnp->cn_lkflags = LK_EXCLUSIVE; 586138345Sphk#ifdef NAMEI_DIAGNOSTIC 587138345Sphk vprint("lookup in", dp); 588138345Sphk#endif 589162288Smohans lkflags_save = cnp->cn_lkflags; 590162288Smohans cnp->cn_lkflags = compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags); 59143301Sdillon if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 592162288Smohans cnp->cn_lkflags = lkflags_save; 59342408Seivind KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); 5941541Srgrimes#ifdef NAMEI_DIAGNOSTIC 5951541Srgrimes printf("not found\n"); 5961541Srgrimes#endif 5971541Srgrimes if ((error == ENOENT) && 598101308Sjeff (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && 5991541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 6001541Srgrimes tdp = dp; 601144833Sjeff dp = dp->v_mount->mnt_vnodecovered; 602158094Sjeff tvfslocked = dvfslocked; 603158094Sjeff dvfslocked = VFS_LOCK_GIANT(dp->v_mount); 604144833Sjeff VREF(dp); 605144203Sjeff vput(tdp); 606140714Sjeff VFS_UNLOCK_GIANT(tvfslocked); 607175202Sattilio vn_lock(dp, 608175202Sattilio compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | 609175202Sattilio LK_RETRY)); 6101541Srgrimes goto unionlookup; 6111541Srgrimes } 6121541Srgrimes 6131541Srgrimes if (error != EJUSTRETURN) 6141541Srgrimes goto bad; 6151541Srgrimes /* 6161541Srgrimes * If creating and at end of pathname, then can consider 6171541Srgrimes * allowing file to be created. 6181541Srgrimes */ 61911644Sdg if (rdonly) { 6201541Srgrimes error = EROFS; 6211541Srgrimes goto bad; 6221541Srgrimes } 6239804Sbde if (*cp == '\0' && trailing_slash && 6249804Sbde !(cnp->cn_flags & WILLBEDIR)) { 6259804Sbde error = ENOENT; 6269804Sbde goto bad; 6279804Sbde } 628144203Sjeff if ((cnp->cn_flags & LOCKPARENT) == 0) 629144203Sjeff VOP_UNLOCK(dp, 0, td); 6301541Srgrimes /* 631144203Sjeff * This is a temporary assert to make sure I know what the 632144203Sjeff * behavior here was. 633144203Sjeff */ 634144203Sjeff KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0, 635144203Sjeff ("lookup: Unhandled case.")); 636144203Sjeff /* 6371541Srgrimes * We return with ni_vp NULL to indicate that the entry 6381541Srgrimes * doesn't currently exist, leaving a pointer to the 639161010Srwatson * (possibly locked) directory vnode in ndp->ni_dvp. 6401541Srgrimes */ 6411541Srgrimes if (cnp->cn_flags & SAVESTART) { 6421541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 6431541Srgrimes VREF(ndp->ni_startdir); 6441541Srgrimes } 645140714Sjeff goto success; 646162288Smohans } else 647162288Smohans cnp->cn_lkflags = lkflags_save; 6481541Srgrimes#ifdef NAMEI_DIAGNOSTIC 6491541Srgrimes printf("found\n"); 6501541Srgrimes#endif 651144203Sjeff /* 6521541Srgrimes * Take into account any additional components consumed by 6531541Srgrimes * the underlying filesystem. 6541541Srgrimes */ 6551541Srgrimes if (cnp->cn_consume > 0) { 6561541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 6571541Srgrimes ndp->ni_next += cnp->cn_consume; 6581541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 6591541Srgrimes cnp->cn_consume = 0; 6601541Srgrimes } 6611541Srgrimes 6621541Srgrimes dp = ndp->ni_vp; 663158094Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 6641541Srgrimes 6651541Srgrimes /* 6661541Srgrimes * Check to see if the vnode has been mounted on; 66796755Strhodes * if so find the root of the mounted filesystem. 6681541Srgrimes */ 6691541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 6701541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 67183366Sjulian if (vfs_busy(mp, 0, 0, td)) 6721541Srgrimes continue; 673144833Sjeff vput(dp); 674158094Sjeff VFS_UNLOCK_GIANT(vfslocked); 675155168Sjeff vfslocked = VFS_LOCK_GIANT(mp); 676158094Sjeff if (dp != ndp->ni_dvp) 677166167Skib vput(ndp->ni_dvp); 678166167Skib else 679166167Skib vrele(ndp->ni_dvp); 680166167Skib VFS_UNLOCK_GIANT(dvfslocked); 681166167Skib dvfslocked = 0; 682166167Skib vref(vp_crossmp); 683166167Skib ndp->ni_dvp = vp_crossmp; 684162288Smohans error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags), &tdp, td); 68583366Sjulian vfs_unbusy(mp, td); 686175202Sattilio if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT)) 687166167Skib panic("vp_crossmp exclusively locked or reclaimed"); 68865805Sbp if (error) { 68965805Sbp dpunlocked = 1; 6901541Srgrimes goto bad2; 69165805Sbp } 6921541Srgrimes ndp->ni_vp = dp = tdp; 6931541Srgrimes } 6941541Srgrimes 69510219Sdfr /* 69610219Sdfr * Check for symbolic link 69710219Sdfr */ 69810219Sdfr if ((dp->v_type == VLNK) && 69910219Sdfr ((cnp->cn_flags & FOLLOW) || trailing_slash || 70010219Sdfr *ndp->ni_next == '/')) { 70110219Sdfr cnp->cn_flags |= ISSYMLINK; 702155385Sjeff if (dp->v_iflag & VI_DOOMED) { 70369405Salfred /* We can't know whether the directory was mounted with 70469405Salfred * NOSYMFOLLOW, so we can't follow safely. */ 70569405Salfred error = EBADF; 70669405Salfred goto bad2; 70769405Salfred } 70835105Swosch if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { 70935105Swosch error = EACCES; 71035105Swosch goto bad2; 71135105Swosch } 712144833Sjeff /* 713144833Sjeff * Symlink code always expects an unlocked dvp. 714144833Sjeff */ 715144833Sjeff if (ndp->ni_dvp != ndp->ni_vp) 716144833Sjeff VOP_UNLOCK(ndp->ni_dvp, 0, td); 717140714Sjeff goto success; 71810219Sdfr } 71910219Sdfr 72010219Sdfr /* 72110219Sdfr * Check for bogus trailing slashes. 72210219Sdfr */ 72310219Sdfr if (trailing_slash && dp->v_type != VDIR) { 72410219Sdfr error = ENOTDIR; 72510219Sdfr goto bad2; 72610219Sdfr } 72710219Sdfr 7281541Srgrimesnextname: 7291541Srgrimes /* 7301541Srgrimes * Not a symbolic link. If more pathname, 7311541Srgrimes * continue at next component, else return. 7321541Srgrimes */ 733144203Sjeff KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/', 734144203Sjeff ("lookup: invalid path state.")); 7351541Srgrimes if (*ndp->ni_next == '/') { 7361541Srgrimes cnp->cn_nameptr = ndp->ni_next; 7371541Srgrimes while (*cnp->cn_nameptr == '/') { 7381541Srgrimes cnp->cn_nameptr++; 7391541Srgrimes ndp->ni_pathlen--; 7401541Srgrimes } 741144833Sjeff if (ndp->ni_dvp != dp) 742144833Sjeff vput(ndp->ni_dvp); 743144833Sjeff else 744144833Sjeff vrele(ndp->ni_dvp); 745155168Sjeff VFS_UNLOCK_GIANT(dvfslocked); 746158094Sjeff dvfslocked = vfslocked; /* dp becomes dvp in dirloop */ 747158094Sjeff vfslocked = 0; 7481541Srgrimes goto dirloop; 7491541Srgrimes } 7501541Srgrimes /* 75196755Strhodes * Disallow directory write attempts on read-only filesystems. 7521541Srgrimes */ 75311644Sdg if (rdonly && 75411644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 75511644Sdg error = EROFS; 75611644Sdg goto bad2; 7571541Srgrimes } 7581541Srgrimes if (cnp->cn_flags & SAVESTART) { 7591541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 7601541Srgrimes VREF(ndp->ni_startdir); 7611541Srgrimes } 762144833Sjeff if (!wantparent) { 763144833Sjeff if (ndp->ni_dvp != dp) 764144833Sjeff vput(ndp->ni_dvp); 765144833Sjeff else 766144833Sjeff vrele(ndp->ni_dvp); 767155168Sjeff VFS_UNLOCK_GIANT(dvfslocked); 768155168Sjeff dvfslocked = 0; 769144833Sjeff } else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) 770144833Sjeff VOP_UNLOCK(ndp->ni_dvp, 0, td); 77132071Sdyson 772155334Srwatson if (cnp->cn_flags & AUDITVNODE1) 773155334Srwatson AUDIT_ARG(vnode, dp, ARG_VNODE1); 774155334Srwatson else if (cnp->cn_flags & AUDITVNODE2) 775155334Srwatson AUDIT_ARG(vnode, dp, ARG_VNODE2); 776155334Srwatson 7771541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 77883366Sjulian VOP_UNLOCK(dp, 0, td); 779140714Sjeffsuccess: 780172274Spjd /* 781172274Spjd * Because of lookup_shared we may have the vnode shared locked, but 782172274Spjd * the caller may want it to be exclusively locked. 783172274Spjd */ 784172274Spjd if ((cnp->cn_flags & (ISLASTCN | LOCKSHARED | LOCKLEAF)) == 785172274Spjd (ISLASTCN | LOCKLEAF) && VOP_ISLOCKED(dp, td) != LK_EXCLUSIVE) { 786175202Sattilio vn_lock(dp, LK_UPGRADE | LK_RETRY); 787172274Spjd } 788155168Sjeff if (vfslocked && dvfslocked) 789155168Sjeff VFS_UNLOCK_GIANT(dvfslocked); /* Only need one */ 790155168Sjeff if (vfslocked || dvfslocked) 791140714Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 7921541Srgrimes return (0); 7931541Srgrimes 7941541Srgrimesbad2: 795144833Sjeff if (dp != ndp->ni_dvp) 796144203Sjeff vput(ndp->ni_dvp); 797144203Sjeff else 798144203Sjeff vrele(ndp->ni_dvp); 7991541Srgrimesbad: 800144833Sjeff if (!dpunlocked) 80165805Sbp vput(dp); 802140714Sjeff VFS_UNLOCK_GIANT(vfslocked); 803155168Sjeff VFS_UNLOCK_GIANT(dvfslocked); 804140714Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 8051541Srgrimes ndp->ni_vp = NULL; 8061541Srgrimes return (error); 8071541Srgrimes} 8081541Srgrimes 8093148Sphk/* 8103148Sphk * relookup - lookup a path name component 811170035Srwatson * Used by lookup to re-acquire things. 8123148Sphk */ 8133148Sphkint 814161011Srwatsonrelookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) 8153148Sphk{ 81683366Sjulian struct thread *td = cnp->cn_thread; 81722521Sdyson struct vnode *dp = 0; /* the directory we are searching */ 8183148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 8193148Sphk int rdonly; /* lookup read-only flag bit */ 8203148Sphk int error = 0; 8211541Srgrimes 822144203Sjeff KASSERT(cnp->cn_flags & ISLASTCN, 823144203Sjeff ("relookup: Not given last component.")); 8243148Sphk /* 8253148Sphk * Setup: break out flag bits into variables. 8263148Sphk */ 8273148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 828145004Sjeff KASSERT(wantparent, ("relookup: parent not wanted.")); 8293148Sphk rdonly = cnp->cn_flags & RDONLY; 8303148Sphk cnp->cn_flags &= ~ISSYMLINK; 8313148Sphk dp = dvp; 832144286Sjeff cnp->cn_lkflags = LK_EXCLUSIVE; 833175202Sattilio vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 8343148Sphk 8353148Sphk /* 8363148Sphk * Search a new directory. 8373148Sphk * 8383148Sphk * The last component of the filename is left accessible via 8393148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 8403148Sphk * the name set the SAVENAME flag. When done, they assume 8413148Sphk * responsibility for freeing the pathname buffer. 8423148Sphk */ 8433148Sphk#ifdef NAMEI_DIAGNOSTIC 8443148Sphk printf("{%s}: ", cnp->cn_nameptr); 8453148Sphk#endif 8463148Sphk 8473148Sphk /* 8483148Sphk * Check for degenerate name (e.g. / or "") 8493148Sphk * which is a way of talking about a directory, 8503148Sphk * e.g. like "/." or ".". 8513148Sphk */ 8523148Sphk if (cnp->cn_nameptr[0] == '\0') { 8533148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 8543148Sphk error = EISDIR; 8553148Sphk goto bad; 8563148Sphk } 8573148Sphk if (dp->v_type != VDIR) { 8583148Sphk error = ENOTDIR; 8593148Sphk goto bad; 8603148Sphk } 8613148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 86283366Sjulian VOP_UNLOCK(dp, 0, td); 8633148Sphk *vpp = dp; 86454655Seivind /* XXX This should probably move to the top of function. */ 8653148Sphk if (cnp->cn_flags & SAVESTART) 8663148Sphk panic("lookup: SAVESTART"); 8673148Sphk return (0); 8683148Sphk } 8693148Sphk 8703148Sphk if (cnp->cn_flags & ISDOTDOT) 8713148Sphk panic ("relookup: lookup on dot-dot"); 8723148Sphk 8733148Sphk /* 8743148Sphk * We now have a segment name to search for, and a directory to search. 8753148Sphk */ 876138345Sphk#ifdef NAMEI_DIAGNOSTIC 877138345Sphk vprint("search in:", dp); 878138345Sphk#endif 87943311Sdillon if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 88042408Seivind KASSERT(*vpp == NULL, ("leaf should be empty")); 8813148Sphk if (error != EJUSTRETURN) 8823148Sphk goto bad; 8833148Sphk /* 8843148Sphk * If creating and at end of pathname, then can consider 8853148Sphk * allowing file to be created. 8863148Sphk */ 88711644Sdg if (rdonly) { 8883148Sphk error = EROFS; 8893148Sphk goto bad; 8903148Sphk } 8913148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 8923148Sphk if (cnp->cn_flags & SAVESTART) 8933148Sphk VREF(dvp); 894144203Sjeff if ((cnp->cn_flags & LOCKPARENT) == 0) 895144203Sjeff VOP_UNLOCK(dp, 0, td); 8963148Sphk /* 897144203Sjeff * This is a temporary assert to make sure I know what the 898144203Sjeff * behavior here was. 899144203Sjeff */ 900144203Sjeff KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0, 901144203Sjeff ("relookup: Unhandled case.")); 902144203Sjeff /* 9033148Sphk * We return with ni_vp NULL to indicate that the entry 9043148Sphk * doesn't currently exist, leaving a pointer to the 905161010Srwatson * (possibly locked) directory vnode in ndp->ni_dvp. 9063148Sphk */ 9073148Sphk return (0); 9083148Sphk } 909162288Smohans 9103148Sphk dp = *vpp; 9113148Sphk 9123148Sphk /* 91396755Strhodes * Disallow directory write attempts on read-only filesystems. 9143148Sphk */ 91511644Sdg if (rdonly && 91611644Sdg (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 917145004Sjeff if (dvp == dp) 918145004Sjeff vrele(dvp); 919145004Sjeff else 920145004Sjeff vput(dvp); 92111644Sdg error = EROFS; 922145004Sjeff goto bad; 9233148Sphk } 924145004Sjeff /* 925145004Sjeff * Set the parent lock/ref state to the requested state. 926145004Sjeff */ 927145004Sjeff if ((cnp->cn_flags & LOCKPARENT) == 0 && dvp != dp) { 928145004Sjeff if (wantparent) 929145004Sjeff VOP_UNLOCK(dvp, 0, td); 930145004Sjeff else 931145004Sjeff vput(dvp); 932145004Sjeff } else if (!wantparent) 933145004Sjeff vrele(dvp); 934145004Sjeff /* 935145004Sjeff * Check for symbolic link 936145004Sjeff */ 937145004Sjeff KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), 938145004Sjeff ("relookup: symlink found.\n")); 939145004Sjeff 9403148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 9413148Sphk if (cnp->cn_flags & SAVESTART) 9423148Sphk VREF(dvp); 94322521Sdyson 9443148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 94583366Sjulian VOP_UNLOCK(dp, 0, td); 9463148Sphk return (0); 9473148Sphkbad: 9483148Sphk vput(dp); 9493148Sphk *vpp = NULL; 9503148Sphk return (error); 9513148Sphk} 952141471Sjhb 953141471Sjhb/* 954144661Sjeff * Free data allocated by namei(); see namei(9) for details. 955144661Sjeff */ 956144661Sjeffvoid 957161011SrwatsonNDFREE(struct nameidata *ndp, const u_int flags) 958144661Sjeff{ 959144833Sjeff int unlock_dvp; 960144833Sjeff int unlock_vp; 961144661Sjeff 962144833Sjeff unlock_dvp = 0; 963144833Sjeff unlock_vp = 0; 964144833Sjeff 965144661Sjeff if (!(flags & NDF_NO_FREE_PNBUF) && 966144661Sjeff (ndp->ni_cnd.cn_flags & HASBUF)) { 967144661Sjeff uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); 968144661Sjeff ndp->ni_cnd.cn_flags &= ~HASBUF; 969144661Sjeff } 970144833Sjeff if (!(flags & NDF_NO_VP_UNLOCK) && 971144833Sjeff (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp) 972144833Sjeff unlock_vp = 1; 973144833Sjeff if (!(flags & NDF_NO_VP_RELE) && ndp->ni_vp) { 974144833Sjeff if (unlock_vp) { 975144833Sjeff vput(ndp->ni_vp); 976144833Sjeff unlock_vp = 0; 977144833Sjeff } else 978144833Sjeff vrele(ndp->ni_vp); 979144833Sjeff ndp->ni_vp = NULL; 980144833Sjeff } 981144833Sjeff if (unlock_vp) 982144833Sjeff VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_thread); 983144661Sjeff if (!(flags & NDF_NO_DVP_UNLOCK) && 984144661Sjeff (ndp->ni_cnd.cn_flags & LOCKPARENT) && 985144661Sjeff ndp->ni_dvp != ndp->ni_vp) 986144833Sjeff unlock_dvp = 1; 987144661Sjeff if (!(flags & NDF_NO_DVP_RELE) && 988144661Sjeff (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) { 989144833Sjeff if (unlock_dvp) { 990144833Sjeff vput(ndp->ni_dvp); 991144833Sjeff unlock_dvp = 0; 992144833Sjeff } else 993144833Sjeff vrele(ndp->ni_dvp); 994144661Sjeff ndp->ni_dvp = NULL; 995144661Sjeff } 996144833Sjeff if (unlock_dvp) 997144833Sjeff VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_thread); 998144661Sjeff if (!(flags & NDF_NO_STARTDIR_RELE) && 999144661Sjeff (ndp->ni_cnd.cn_flags & SAVESTART)) { 1000144661Sjeff vrele(ndp->ni_startdir); 1001144661Sjeff ndp->ni_startdir = NULL; 1002144661Sjeff } 1003144661Sjeff} 1004144661Sjeff 1005144661Sjeff/* 1006141471Sjhb * Determine if there is a suitable alternate filename under the specified 1007141471Sjhb * prefix for the specified path. If the create flag is set, then the 1008141471Sjhb * alternate prefix will be used so long as the parent directory exists. 1009141471Sjhb * This is used by the various compatiblity ABIs so that Linux binaries prefer 1010141471Sjhb * files under /compat/linux for example. The chosen path (whether under 1011141471Sjhb * the prefix or under /) is returned in a kernel malloc'd buffer pointed 1012141471Sjhb * to by pathbuf. The caller is responsible for free'ing the buffer from 1013141471Sjhb * the M_TEMP bucket if one is returned. 1014141471Sjhb */ 1015141471Sjhbint 1016141471Sjhbkern_alternate_path(struct thread *td, const char *prefix, char *path, 1017141471Sjhb enum uio_seg pathseg, char **pathbuf, int create) 1018141471Sjhb{ 1019141471Sjhb struct nameidata nd, ndroot; 1020141471Sjhb char *ptr, *buf, *cp; 1021141471Sjhb size_t len, sz; 1022141471Sjhb int error; 1023141471Sjhb 1024141471Sjhb buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1025141471Sjhb *pathbuf = buf; 1026141471Sjhb 1027141471Sjhb /* Copy the prefix into the new pathname as a starting point. */ 1028141471Sjhb len = strlcpy(buf, prefix, MAXPATHLEN); 1029141471Sjhb if (len >= MAXPATHLEN) { 1030141471Sjhb *pathbuf = NULL; 1031141471Sjhb free(buf, M_TEMP); 1032141471Sjhb return (EINVAL); 1033141471Sjhb } 1034141471Sjhb sz = MAXPATHLEN - len; 1035141471Sjhb ptr = buf + len; 1036141471Sjhb 1037141471Sjhb /* Append the filename to the prefix. */ 1038141471Sjhb if (pathseg == UIO_SYSSPACE) 1039141471Sjhb error = copystr(path, ptr, sz, &len); 1040141471Sjhb else 1041141471Sjhb error = copyinstr(path, ptr, sz, &len); 1042141471Sjhb 1043141471Sjhb if (error) { 1044141471Sjhb *pathbuf = NULL; 1045141471Sjhb free(buf, M_TEMP); 1046141471Sjhb return (error); 1047141471Sjhb } 1048141471Sjhb 1049141471Sjhb /* Only use a prefix with absolute pathnames. */ 1050141471Sjhb if (*ptr != '/') { 1051141471Sjhb error = EINVAL; 1052141471Sjhb goto keeporig; 1053141471Sjhb } 1054141471Sjhb 1055141471Sjhb /* 1056141471Sjhb * We know that there is a / somewhere in this pathname. 1057141471Sjhb * Search backwards for it, to find the file's parent dir 1058141471Sjhb * to see if it exists in the alternate tree. If it does, 1059141471Sjhb * and we want to create a file (cflag is set). We don't 1060141471Sjhb * need to worry about the root comparison in this case. 1061141471Sjhb */ 1062141471Sjhb 1063141471Sjhb if (create) { 1064141471Sjhb for (cp = &ptr[len] - 1; *cp != '/'; cp--); 1065141471Sjhb *cp = '\0'; 1066141471Sjhb 1067150431Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td); 1068141471Sjhb error = namei(&nd); 1069141471Sjhb *cp = '/'; 1070141471Sjhb if (error != 0) 1071150431Sjhb goto keeporig; 1072141471Sjhb } else { 1073150431Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td); 1074141471Sjhb 1075141471Sjhb error = namei(&nd); 1076141471Sjhb if (error != 0) 1077150431Sjhb goto keeporig; 1078141471Sjhb 1079141471Sjhb /* 1080141471Sjhb * We now compare the vnode of the prefix to the one 1081141471Sjhb * vnode asked. If they resolve to be the same, then we 1082141471Sjhb * ignore the match so that the real root gets used. 1083141471Sjhb * This avoids the problem of traversing "../.." to find the 1084141471Sjhb * root directory and never finding it, because "/" resolves 1085141471Sjhb * to the emulation root directory. This is expensive :-( 1086141471Sjhb */ 1087150431Sjhb NDINIT(&ndroot, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, prefix, 1088150431Sjhb td); 1089141471Sjhb 1090141471Sjhb /* We shouldn't ever get an error from this namei(). */ 1091141471Sjhb error = namei(&ndroot); 1092141471Sjhb if (error == 0) { 1093141471Sjhb if (nd.ni_vp == ndroot.ni_vp) 1094141471Sjhb error = ENOENT; 1095141471Sjhb 1096141471Sjhb NDFREE(&ndroot, NDF_ONLY_PNBUF); 1097141471Sjhb vrele(ndroot.ni_vp); 1098150431Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&ndroot)); 1099141471Sjhb } 1100141471Sjhb } 1101141471Sjhb 1102141471Sjhb NDFREE(&nd, NDF_ONLY_PNBUF); 1103141471Sjhb vrele(nd.ni_vp); 1104150431Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 1105141471Sjhb 1106141471Sjhbkeeporig: 1107141471Sjhb /* If there was an error, use the original path name. */ 1108141471Sjhb if (error) 1109141471Sjhb bcopy(ptr, buf, len); 1110141471Sjhb return (error); 1111141471Sjhb} 1112