vfs_lookup.c revision 9804
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 399804Sbde * $Id: vfs_lookup.c,v 1.7 1995/05/30 08:06:33 rgrimes Exp $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes#include <sys/param.h> 432112Swollman#include <sys/systm.h> 441541Srgrimes#include <sys/syslimits.h> 451541Srgrimes#include <sys/time.h> 461541Srgrimes#include <sys/namei.h> 471541Srgrimes#include <sys/vnode.h> 481541Srgrimes#include <sys/mount.h> 491541Srgrimes#include <sys/errno.h> 501541Srgrimes#include <sys/malloc.h> 511541Srgrimes#include <sys/filedesc.h> 521541Srgrimes#include <sys/proc.h> 531541Srgrimes 541541Srgrimes#ifdef KTRACE 551541Srgrimes#include <sys/ktrace.h> 561541Srgrimes#endif 571541Srgrimes 581541Srgrimes/* 591541Srgrimes * Convert a pathname into a pointer to a locked inode. 601541Srgrimes * 611541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 621541Srgrimes * when they occur at the end of the name translation process. 631541Srgrimes * Symbolic links are always followed for all other pathname 641541Srgrimes * components other than the last. 651541Srgrimes * 661541Srgrimes * The segflg defines whether the name is to be copied from user 671541Srgrimes * space or kernel space. 681541Srgrimes * 691541Srgrimes * Overall outline of namei: 701541Srgrimes * 711541Srgrimes * copy in name 721541Srgrimes * get starting directory 731541Srgrimes * while (!done && !error) { 741541Srgrimes * call lookup to search path. 751541Srgrimes * if symbolic link, massage name in buffer and continue 761541Srgrimes * } 771541Srgrimes */ 781541Srgrimesint 791541Srgrimesnamei(ndp) 801541Srgrimes register struct nameidata *ndp; 811541Srgrimes{ 821541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 831541Srgrimes register char *cp; /* pointer into pathname argument */ 841541Srgrimes register struct vnode *dp; /* the directory we are searching */ 851541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 861541Srgrimes struct uio auio; 871541Srgrimes int error, linklen; 881541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 891541Srgrimes 901541Srgrimes ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 911541Srgrimes#ifdef DIAGNOSTIC 921541Srgrimes if (!cnp->cn_cred || !cnp->cn_proc) 931541Srgrimes panic ("namei: bad cred/proc"); 941541Srgrimes if (cnp->cn_nameiop & (~OPMASK)) 951541Srgrimes panic ("namei: nameiop contaminated with flags"); 961541Srgrimes if (cnp->cn_flags & OPMASK) 971541Srgrimes panic ("namei: flags contaminated with nameiops"); 981541Srgrimes#endif 991541Srgrimes fdp = cnp->cn_proc->p_fd; 1001541Srgrimes 1011541Srgrimes /* 1021541Srgrimes * Get a buffer for the name to be translated, and copy the 1031541Srgrimes * name into the buffer. 1041541Srgrimes */ 1051541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 1061541Srgrimes MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 1071541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1081541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 1092142Sdg MAXPATHLEN, (u_int *)&ndp->ni_pathlen); 1101541Srgrimes else 1111541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 1122142Sdg MAXPATHLEN, (u_int *)&ndp->ni_pathlen); 1131541Srgrimes if (error) { 1141541Srgrimes free(cnp->cn_pnbuf, M_NAMEI); 1151541Srgrimes ndp->ni_vp = NULL; 1161541Srgrimes return (error); 1171541Srgrimes } 1181541Srgrimes ndp->ni_loopcnt = 0; 1191541Srgrimes#ifdef KTRACE 1201541Srgrimes if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 1211541Srgrimes ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 1221541Srgrimes#endif 1231541Srgrimes 1241541Srgrimes /* 1251541Srgrimes * Get starting point for the translation. 1261541Srgrimes */ 1271541Srgrimes if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) 1281541Srgrimes ndp->ni_rootdir = rootvnode; 1291541Srgrimes dp = fdp->fd_cdir; 1301541Srgrimes VREF(dp); 1311541Srgrimes for (;;) { 1321541Srgrimes /* 1331541Srgrimes * Check if root directory should replace current directory. 1341541Srgrimes * Done at start of translation and after symbolic link. 1351541Srgrimes */ 1361541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1371541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1381541Srgrimes vrele(dp); 1391541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1401541Srgrimes cnp->cn_nameptr++; 1411541Srgrimes ndp->ni_pathlen--; 1421541Srgrimes } 1431541Srgrimes dp = ndp->ni_rootdir; 1441541Srgrimes VREF(dp); 1451541Srgrimes } 1461541Srgrimes ndp->ni_startdir = dp; 1473148Sphk error = lookup(ndp); 1483148Sphk if (error) { 1491541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 1501541Srgrimes return (error); 1511541Srgrimes } 1521541Srgrimes /* 1531541Srgrimes * Check for symbolic link 1541541Srgrimes */ 1551541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 1561541Srgrimes if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 1571541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 1581541Srgrimes else 1591541Srgrimes cnp->cn_flags |= HASBUF; 1601541Srgrimes return (0); 1611541Srgrimes } 1621541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1631541Srgrimes VOP_UNLOCK(ndp->ni_dvp); 1641541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1651541Srgrimes error = ELOOP; 1661541Srgrimes break; 1671541Srgrimes } 1681541Srgrimes if (ndp->ni_pathlen > 1) 1691541Srgrimes MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1701541Srgrimes else 1711541Srgrimes cp = cnp->cn_pnbuf; 1721541Srgrimes aiov.iov_base = cp; 1731541Srgrimes aiov.iov_len = MAXPATHLEN; 1741541Srgrimes auio.uio_iov = &aiov; 1751541Srgrimes auio.uio_iovcnt = 1; 1761541Srgrimes auio.uio_offset = 0; 1771541Srgrimes auio.uio_rw = UIO_READ; 1781541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 1791541Srgrimes auio.uio_procp = (struct proc *)0; 1801541Srgrimes auio.uio_resid = MAXPATHLEN; 1813148Sphk error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 1823148Sphk if (error) { 1831541Srgrimes if (ndp->ni_pathlen > 1) 1841541Srgrimes free(cp, M_NAMEI); 1851541Srgrimes break; 1861541Srgrimes } 1871541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 1881541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 1891541Srgrimes if (ndp->ni_pathlen > 1) 1901541Srgrimes free(cp, M_NAMEI); 1911541Srgrimes error = ENAMETOOLONG; 1921541Srgrimes break; 1931541Srgrimes } 1941541Srgrimes if (ndp->ni_pathlen > 1) { 1951541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 1961541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 1971541Srgrimes cnp->cn_pnbuf = cp; 1981541Srgrimes } else 1991541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 2001541Srgrimes ndp->ni_pathlen += linklen; 2011541Srgrimes vput(ndp->ni_vp); 2021541Srgrimes dp = ndp->ni_dvp; 2031541Srgrimes } 2041541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 2051541Srgrimes vrele(ndp->ni_dvp); 2061541Srgrimes vput(ndp->ni_vp); 2071541Srgrimes ndp->ni_vp = NULL; 2081541Srgrimes return (error); 2091541Srgrimes} 2101541Srgrimes 2111541Srgrimes/* 2121541Srgrimes * Search a pathname. 2131541Srgrimes * This is a very central and rather complicated routine. 2141541Srgrimes * 2151541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2161541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2171541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2181541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2191541Srgrimes * symbolic link needing interpretation is encountered. 2201541Srgrimes * 2211541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 2221541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 2231541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 2241541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 2251541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 2261541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 2271541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 2281541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 2291541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 2301541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 2311541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 2328876Srgrimes * 2331541Srgrimes * Overall outline of lookup: 2341541Srgrimes * 2351541Srgrimes * dirloop: 2361541Srgrimes * identify next component of name at ndp->ni_ptr 2371541Srgrimes * handle degenerate case where name is null string 2381541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 2391541Srgrimes * call VOP_LOOKUP routine for next component name 2401541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 2411541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 2421541Srgrimes * if result vnode is mounted on and crossing mount points, 2431541Srgrimes * find mounted on vnode 2441541Srgrimes * if more components of name, do next level at dirloop 2451541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 2461541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 2471541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 2481541Srgrimes */ 2491541Srgrimesint 2501541Srgrimeslookup(ndp) 2511541Srgrimes register struct nameidata *ndp; 2521541Srgrimes{ 2531541Srgrimes register char *cp; /* pointer into pathname argument */ 2541541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 2551541Srgrimes struct vnode *tdp; /* saved dp */ 2561541Srgrimes struct mount *mp; /* mount table entry */ 2571541Srgrimes int docache; /* == 0 do not cache last component */ 2581541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 2591541Srgrimes int rdonly; /* lookup read-only flag bit */ 2609804Sbde int trailing_slash; 2611541Srgrimes int error = 0; 2621541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 2631541Srgrimes 2641541Srgrimes /* 2651541Srgrimes * Setup: break out flag bits into variables. 2661541Srgrimes */ 2671541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 2681541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 2691541Srgrimes if (cnp->cn_nameiop == DELETE || 2701541Srgrimes (wantparent && cnp->cn_nameiop != CREATE)) 2711541Srgrimes docache = 0; 2721541Srgrimes rdonly = cnp->cn_flags & RDONLY; 2731541Srgrimes ndp->ni_dvp = NULL; 2741541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 2751541Srgrimes dp = ndp->ni_startdir; 2761541Srgrimes ndp->ni_startdir = NULLVP; 2771541Srgrimes VOP_LOCK(dp); 2781541Srgrimes 2791541Srgrimesdirloop: 2801541Srgrimes /* 2811541Srgrimes * Search a new directory. 2821541Srgrimes * 2831541Srgrimes * The cn_hash value is for use by vfs_cache. 2841541Srgrimes * The last component of the filename is left accessible via 2851541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 2861541Srgrimes * the name set the SAVENAME flag. When done, they assume 2871541Srgrimes * responsibility for freeing the pathname buffer. 2881541Srgrimes */ 2891541Srgrimes cnp->cn_consume = 0; 2901541Srgrimes cnp->cn_hash = 0; 2911541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 2921541Srgrimes cnp->cn_hash += (unsigned char)*cp; 2931541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 2941541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 2951541Srgrimes error = ENAMETOOLONG; 2961541Srgrimes goto bad; 2971541Srgrimes } 2981541Srgrimes#ifdef NAMEI_DIAGNOSTIC 2991541Srgrimes { char c = *cp; 3001541Srgrimes *cp = '\0'; 3011541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 3021541Srgrimes *cp = c; } 3031541Srgrimes#endif 3041541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3051541Srgrimes ndp->ni_next = cp; 3069804Sbde 3079804Sbde /* 3089804Sbde * Replace multiple slashes by a single slash and trailing slashes 3099804Sbde * by a null. This must be done before VOP_LOOKUP() because some 3109804Sbde * fs's don't know about trailing slashes. Remember if there were 3119804Sbde * trailing slashes to handle symlinks, existing non-directories 3129804Sbde * and non-existing files that won't be directories specially later. 3139804Sbde */ 3149804Sbde trailing_slash = 0; 3159804Sbde while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { 3169804Sbde cp++; 3179804Sbde ndp->ni_pathlen--; 3189804Sbde if (*cp == '\0') { 3199804Sbde trailing_slash = 1; 3209804Sbde *ndp->ni_next = '\0'; /* XXX for direnter() ... */ 3219804Sbde } 3229804Sbde } 3239804Sbde ndp->ni_next = cp; 3249804Sbde 3251541Srgrimes cnp->cn_flags |= MAKEENTRY; 3261541Srgrimes if (*cp == '\0' && docache == 0) 3271541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 3281541Srgrimes if (cnp->cn_namelen == 2 && 3291541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 3301541Srgrimes cnp->cn_flags |= ISDOTDOT; 3311541Srgrimes else 3321541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 3331541Srgrimes if (*ndp->ni_next == 0) 3341541Srgrimes cnp->cn_flags |= ISLASTCN; 3351541Srgrimes else 3361541Srgrimes cnp->cn_flags &= ~ISLASTCN; 3371541Srgrimes 3381541Srgrimes 3391541Srgrimes /* 3401541Srgrimes * Check for degenerate name (e.g. / or "") 3411541Srgrimes * which is a way of talking about a directory, 3421541Srgrimes * e.g. like "/." or ".". 3431541Srgrimes */ 3441541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 3451541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 3461541Srgrimes error = EISDIR; 3471541Srgrimes goto bad; 3481541Srgrimes } 3491541Srgrimes if (dp->v_type != VDIR) { 3501541Srgrimes error = ENOTDIR; 3511541Srgrimes goto bad; 3521541Srgrimes } 3531541Srgrimes if (wantparent) { 3541541Srgrimes ndp->ni_dvp = dp; 3551541Srgrimes VREF(dp); 3561541Srgrimes } 3571541Srgrimes ndp->ni_vp = dp; 3581541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 3591541Srgrimes VOP_UNLOCK(dp); 3601541Srgrimes if (cnp->cn_flags & SAVESTART) 3611541Srgrimes panic("lookup: SAVESTART"); 3621541Srgrimes return (0); 3631541Srgrimes } 3641541Srgrimes 3651541Srgrimes /* 3661541Srgrimes * Handle "..": two special cases. 3671541Srgrimes * 1. If at root directory (e.g. after chroot) 3681541Srgrimes * or at absolute root directory 3691541Srgrimes * then ignore it so can't get out. 3701541Srgrimes * 2. If this vnode is the root of a mounted 3711541Srgrimes * filesystem, then replace it with the 3721541Srgrimes * vnode which was mounted on so we take the 3731541Srgrimes * .. in the other file system. 3741541Srgrimes */ 3751541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 3761541Srgrimes for (;;) { 3771541Srgrimes if (dp == ndp->ni_rootdir || dp == rootvnode) { 3781541Srgrimes ndp->ni_dvp = dp; 3791541Srgrimes ndp->ni_vp = dp; 3801541Srgrimes VREF(dp); 3811541Srgrimes goto nextname; 3821541Srgrimes } 3831541Srgrimes if ((dp->v_flag & VROOT) == 0 || 3841541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 3851541Srgrimes break; 3861541Srgrimes tdp = dp; 3871541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 3881541Srgrimes vput(tdp); 3891541Srgrimes VREF(dp); 3901541Srgrimes VOP_LOCK(dp); 3911541Srgrimes } 3921541Srgrimes } 3931541Srgrimes 3941541Srgrimes /* 3951541Srgrimes * We now have a segment name to search for, and a directory to search. 3961541Srgrimes */ 3971541Srgrimesunionlookup: 3981541Srgrimes ndp->ni_dvp = dp; 3993148Sphk error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp); 4003148Sphk if (error) { 4011541Srgrimes#ifdef DIAGNOSTIC 4021541Srgrimes if (ndp->ni_vp != NULL) 4031541Srgrimes panic("leaf should be empty"); 4041541Srgrimes#endif 4051541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4061541Srgrimes printf("not found\n"); 4071541Srgrimes#endif 4081541Srgrimes if ((error == ENOENT) && 4091541Srgrimes (dp->v_flag & VROOT) && 4101541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 4111541Srgrimes tdp = dp; 4121541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 4131541Srgrimes vput(tdp); 4141541Srgrimes VREF(dp); 4151541Srgrimes VOP_LOCK(dp); 4161541Srgrimes goto unionlookup; 4171541Srgrimes } 4181541Srgrimes 4191541Srgrimes if (error != EJUSTRETURN) 4201541Srgrimes goto bad; 4211541Srgrimes /* 4221541Srgrimes * If creating and at end of pathname, then can consider 4231541Srgrimes * allowing file to be created. 4241541Srgrimes */ 4251541Srgrimes if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 4261541Srgrimes error = EROFS; 4271541Srgrimes goto bad; 4281541Srgrimes } 4299804Sbde if (*cp == '\0' && trailing_slash && 4309804Sbde !(cnp->cn_flags & WILLBEDIR)) { 4319804Sbde error = ENOENT; 4329804Sbde goto bad; 4339804Sbde } 4341541Srgrimes /* 4351541Srgrimes * We return with ni_vp NULL to indicate that the entry 4361541Srgrimes * doesn't currently exist, leaving a pointer to the 4371541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 4381541Srgrimes */ 4391541Srgrimes if (cnp->cn_flags & SAVESTART) { 4401541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 4411541Srgrimes VREF(ndp->ni_startdir); 4421541Srgrimes } 4431541Srgrimes return (0); 4441541Srgrimes } 4451541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4461541Srgrimes printf("found\n"); 4471541Srgrimes#endif 4481541Srgrimes 4491541Srgrimes /* 4501541Srgrimes * Take into account any additional components consumed by 4511541Srgrimes * the underlying filesystem. 4521541Srgrimes */ 4531541Srgrimes if (cnp->cn_consume > 0) { 4541541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 4551541Srgrimes ndp->ni_next += cnp->cn_consume; 4561541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 4571541Srgrimes cnp->cn_consume = 0; 4581541Srgrimes } 4591541Srgrimes 4601541Srgrimes dp = ndp->ni_vp; 4611541Srgrimes /* 4621541Srgrimes * Check for symbolic link 4631541Srgrimes */ 4641541Srgrimes if ((dp->v_type == VLNK) && 4659804Sbde ((cnp->cn_flags & FOLLOW) || trailing_slash || 4669804Sbde *ndp->ni_next == '/')) { 4671541Srgrimes cnp->cn_flags |= ISSYMLINK; 4681541Srgrimes return (0); 4691541Srgrimes } 4701541Srgrimes 4711541Srgrimes /* 4729804Sbde * Check for bogus trailing slashes. 4739804Sbde */ 4749804Sbde if (trailing_slash && dp->v_type != VDIR) { 4759804Sbde error = ENOTDIR; 4769804Sbde goto bad2; 4779804Sbde } 4789804Sbde 4799804Sbde /* 4801541Srgrimes * Check to see if the vnode has been mounted on; 4811541Srgrimes * if so find the root of the mounted file system. 4821541Srgrimes */ 4831541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 4841541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 4851541Srgrimes if (mp->mnt_flag & MNT_MLOCK) { 4861541Srgrimes mp->mnt_flag |= MNT_MWAIT; 4873396Sdg (void) tsleep((caddr_t)mp, PVFS, "lookup", 0); 4881541Srgrimes continue; 4891541Srgrimes } 4903148Sphk error = VFS_ROOT(dp->v_mountedhere, &tdp); 4913148Sphk if (error) 4921541Srgrimes goto bad2; 4931541Srgrimes vput(dp); 4941541Srgrimes ndp->ni_vp = dp = tdp; 4951541Srgrimes } 4961541Srgrimes 4971541Srgrimesnextname: 4981541Srgrimes /* 4991541Srgrimes * Not a symbolic link. If more pathname, 5001541Srgrimes * continue at next component, else return. 5011541Srgrimes */ 5021541Srgrimes if (*ndp->ni_next == '/') { 5031541Srgrimes cnp->cn_nameptr = ndp->ni_next; 5041541Srgrimes while (*cnp->cn_nameptr == '/') { 5051541Srgrimes cnp->cn_nameptr++; 5061541Srgrimes ndp->ni_pathlen--; 5071541Srgrimes } 5081541Srgrimes vrele(ndp->ni_dvp); 5091541Srgrimes goto dirloop; 5101541Srgrimes } 5111541Srgrimes /* 5121541Srgrimes * Check for read-only file systems. 5131541Srgrimes */ 5141541Srgrimes if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 5151541Srgrimes /* 5161541Srgrimes * Disallow directory write attempts on read-only 5171541Srgrimes * file systems. 5181541Srgrimes */ 5191541Srgrimes if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 5201541Srgrimes (wantparent && 5211541Srgrimes (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 5221541Srgrimes error = EROFS; 5231541Srgrimes goto bad2; 5241541Srgrimes } 5251541Srgrimes } 5261541Srgrimes if (cnp->cn_flags & SAVESTART) { 5271541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 5281541Srgrimes VREF(ndp->ni_startdir); 5291541Srgrimes } 5301541Srgrimes if (!wantparent) 5311541Srgrimes vrele(ndp->ni_dvp); 5321541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 5331541Srgrimes VOP_UNLOCK(dp); 5341541Srgrimes return (0); 5351541Srgrimes 5361541Srgrimesbad2: 5371541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 5381541Srgrimes VOP_UNLOCK(ndp->ni_dvp); 5391541Srgrimes vrele(ndp->ni_dvp); 5401541Srgrimesbad: 5411541Srgrimes vput(dp); 5421541Srgrimes ndp->ni_vp = NULL; 5431541Srgrimes return (error); 5441541Srgrimes} 5451541Srgrimes 5463148Sphk/* 5473148Sphk * relookup - lookup a path name component 5483148Sphk * Used by lookup to re-aquire things. 5493148Sphk */ 5503148Sphkint 5513148Sphkrelookup(dvp, vpp, cnp) 5523148Sphk struct vnode *dvp, **vpp; 5533148Sphk struct componentname *cnp; 5543148Sphk{ 5553148Sphk register struct vnode *dp = 0; /* the directory we are searching */ 5563148Sphk int docache; /* == 0 do not cache last component */ 5573148Sphk int wantparent; /* 1 => wantparent or lockparent flag */ 5583148Sphk int rdonly; /* lookup read-only flag bit */ 5593148Sphk int error = 0; 5603148Sphk#ifdef NAMEI_DIAGNOSTIC 5613148Sphk int newhash; /* DEBUG: check name hash */ 5623148Sphk char *cp; /* DEBUG: check name ptr/len */ 5633148Sphk#endif 5641541Srgrimes 5653148Sphk /* 5663148Sphk * Setup: break out flag bits into variables. 5673148Sphk */ 5683148Sphk wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 5693148Sphk docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 5703148Sphk if (cnp->cn_nameiop == DELETE || 5713148Sphk (wantparent && cnp->cn_nameiop != CREATE)) 5723148Sphk docache = 0; 5733148Sphk rdonly = cnp->cn_flags & RDONLY; 5743148Sphk cnp->cn_flags &= ~ISSYMLINK; 5753148Sphk dp = dvp; 5763148Sphk VOP_LOCK(dp); 5773148Sphk 5783148Sphk/* dirloop: */ 5793148Sphk /* 5803148Sphk * Search a new directory. 5813148Sphk * 5823148Sphk * The cn_hash value is for use by vfs_cache. 5833148Sphk * The last component of the filename is left accessible via 5843148Sphk * cnp->cn_nameptr for callers that need the name. Callers needing 5853148Sphk * the name set the SAVENAME flag. When done, they assume 5863148Sphk * responsibility for freeing the pathname buffer. 5873148Sphk */ 5883148Sphk#ifdef NAMEI_DIAGNOSTIC 5893148Sphk for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 5903148Sphk newhash += (unsigned char)*cp; 5913148Sphk if (newhash != cnp->cn_hash) 5923148Sphk panic("relookup: bad hash"); 5933148Sphk if (cnp->cn_namelen != cp - cnp->cn_nameptr) 5943148Sphk panic ("relookup: bad len"); 5953148Sphk if (*cp != 0) 5963148Sphk panic("relookup: not last component"); 5973148Sphk printf("{%s}: ", cnp->cn_nameptr); 5983148Sphk#endif 5993148Sphk 6003148Sphk /* 6013148Sphk * Check for degenerate name (e.g. / or "") 6023148Sphk * which is a way of talking about a directory, 6033148Sphk * e.g. like "/." or ".". 6043148Sphk */ 6053148Sphk if (cnp->cn_nameptr[0] == '\0') { 6063148Sphk if (cnp->cn_nameiop != LOOKUP || wantparent) { 6073148Sphk error = EISDIR; 6083148Sphk goto bad; 6093148Sphk } 6103148Sphk if (dp->v_type != VDIR) { 6113148Sphk error = ENOTDIR; 6123148Sphk goto bad; 6133148Sphk } 6143148Sphk if (!(cnp->cn_flags & LOCKLEAF)) 6153148Sphk VOP_UNLOCK(dp); 6163148Sphk *vpp = dp; 6173148Sphk if (cnp->cn_flags & SAVESTART) 6183148Sphk panic("lookup: SAVESTART"); 6193148Sphk return (0); 6203148Sphk } 6213148Sphk 6223148Sphk if (cnp->cn_flags & ISDOTDOT) 6233148Sphk panic ("relookup: lookup on dot-dot"); 6243148Sphk 6253148Sphk /* 6263148Sphk * We now have a segment name to search for, and a directory to search. 6273148Sphk */ 6283148Sphk error = VOP_LOOKUP(dp, vpp, cnp); 6293148Sphk if (error) { 6303148Sphk#ifdef DIAGNOSTIC 6313148Sphk if (*vpp != NULL) 6323148Sphk panic("leaf should be empty"); 6333148Sphk#endif 6343148Sphk if (error != EJUSTRETURN) 6353148Sphk goto bad; 6363148Sphk /* 6373148Sphk * If creating and at end of pathname, then can consider 6383148Sphk * allowing file to be created. 6393148Sphk */ 6403148Sphk if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) { 6413148Sphk error = EROFS; 6423148Sphk goto bad; 6433148Sphk } 6443148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 6453148Sphk if (cnp->cn_flags & SAVESTART) 6463148Sphk VREF(dvp); 6473148Sphk /* 6483148Sphk * We return with ni_vp NULL to indicate that the entry 6493148Sphk * doesn't currently exist, leaving a pointer to the 6503148Sphk * (possibly locked) directory inode in ndp->ni_dvp. 6513148Sphk */ 6523148Sphk return (0); 6533148Sphk } 6543148Sphk dp = *vpp; 6553148Sphk 6563148Sphk#ifdef DIAGNOSTIC 6573148Sphk /* 6583148Sphk * Check for symbolic link 6593148Sphk */ 6603148Sphk if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW)) 6613148Sphk panic ("relookup: symlink found.\n"); 6623148Sphk#endif 6633148Sphk 6643148Sphk /* 6653148Sphk * Check for read-only file systems. 6663148Sphk */ 6673148Sphk if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 6683148Sphk /* 6693148Sphk * Disallow directory write attempts on read-only 6703148Sphk * file systems. 6713148Sphk */ 6723148Sphk if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 6733148Sphk (wantparent && 6743148Sphk (dvp->v_mount->mnt_flag & MNT_RDONLY))) { 6753148Sphk error = EROFS; 6763148Sphk goto bad2; 6773148Sphk } 6783148Sphk } 6793148Sphk /* ASSERT(dvp == ndp->ni_startdir) */ 6803148Sphk if (cnp->cn_flags & SAVESTART) 6813148Sphk VREF(dvp); 6828876Srgrimes 6833148Sphk if (!wantparent) 6843148Sphk vrele(dvp); 6853148Sphk if ((cnp->cn_flags & LOCKLEAF) == 0) 6863148Sphk VOP_UNLOCK(dp); 6873148Sphk return (0); 6883148Sphk 6893148Sphkbad2: 6903148Sphk if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 6913148Sphk VOP_UNLOCK(dvp); 6923148Sphk vrele(dvp); 6933148Sphkbad: 6943148Sphk vput(dp); 6953148Sphk *vpp = NULL; 6963148Sphk return (error); 6973148Sphk} 698