vfs_lookup.c revision 1541
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 391541Srgrimes */ 401541Srgrimes 411541Srgrimes#include <sys/param.h> 421541Srgrimes#include <sys/syslimits.h> 431541Srgrimes#include <sys/time.h> 441541Srgrimes#include <sys/namei.h> 451541Srgrimes#include <sys/vnode.h> 461541Srgrimes#include <sys/mount.h> 471541Srgrimes#include <sys/errno.h> 481541Srgrimes#include <sys/malloc.h> 491541Srgrimes#include <sys/filedesc.h> 501541Srgrimes#include <sys/proc.h> 511541Srgrimes 521541Srgrimes#ifdef KTRACE 531541Srgrimes#include <sys/ktrace.h> 541541Srgrimes#endif 551541Srgrimes 561541Srgrimes/* 571541Srgrimes * Convert a pathname into a pointer to a locked inode. 581541Srgrimes * 591541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed 601541Srgrimes * when they occur at the end of the name translation process. 611541Srgrimes * Symbolic links are always followed for all other pathname 621541Srgrimes * components other than the last. 631541Srgrimes * 641541Srgrimes * The segflg defines whether the name is to be copied from user 651541Srgrimes * space or kernel space. 661541Srgrimes * 671541Srgrimes * Overall outline of namei: 681541Srgrimes * 691541Srgrimes * copy in name 701541Srgrimes * get starting directory 711541Srgrimes * while (!done && !error) { 721541Srgrimes * call lookup to search path. 731541Srgrimes * if symbolic link, massage name in buffer and continue 741541Srgrimes * } 751541Srgrimes */ 761541Srgrimesint 771541Srgrimesnamei(ndp) 781541Srgrimes register struct nameidata *ndp; 791541Srgrimes{ 801541Srgrimes register struct filedesc *fdp; /* pointer to file descriptor state */ 811541Srgrimes register char *cp; /* pointer into pathname argument */ 821541Srgrimes register struct vnode *dp; /* the directory we are searching */ 831541Srgrimes struct iovec aiov; /* uio for reading symbolic links */ 841541Srgrimes struct uio auio; 851541Srgrimes int error, linklen; 861541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 871541Srgrimes 881541Srgrimes ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 891541Srgrimes#ifdef DIAGNOSTIC 901541Srgrimes if (!cnp->cn_cred || !cnp->cn_proc) 911541Srgrimes panic ("namei: bad cred/proc"); 921541Srgrimes if (cnp->cn_nameiop & (~OPMASK)) 931541Srgrimes panic ("namei: nameiop contaminated with flags"); 941541Srgrimes if (cnp->cn_flags & OPMASK) 951541Srgrimes panic ("namei: flags contaminated with nameiops"); 961541Srgrimes#endif 971541Srgrimes fdp = cnp->cn_proc->p_fd; 981541Srgrimes 991541Srgrimes /* 1001541Srgrimes * Get a buffer for the name to be translated, and copy the 1011541Srgrimes * name into the buffer. 1021541Srgrimes */ 1031541Srgrimes if ((cnp->cn_flags & HASBUF) == 0) 1041541Srgrimes MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 1051541Srgrimes if (ndp->ni_segflg == UIO_SYSSPACE) 1061541Srgrimes error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 1071541Srgrimes MAXPATHLEN, &ndp->ni_pathlen); 1081541Srgrimes else 1091541Srgrimes error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 1101541Srgrimes MAXPATHLEN, &ndp->ni_pathlen); 1111541Srgrimes if (error) { 1121541Srgrimes free(cnp->cn_pnbuf, M_NAMEI); 1131541Srgrimes ndp->ni_vp = NULL; 1141541Srgrimes return (error); 1151541Srgrimes } 1161541Srgrimes ndp->ni_loopcnt = 0; 1171541Srgrimes#ifdef KTRACE 1181541Srgrimes if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 1191541Srgrimes ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 1201541Srgrimes#endif 1211541Srgrimes 1221541Srgrimes /* 1231541Srgrimes * Get starting point for the translation. 1241541Srgrimes */ 1251541Srgrimes if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) 1261541Srgrimes ndp->ni_rootdir = rootvnode; 1271541Srgrimes dp = fdp->fd_cdir; 1281541Srgrimes VREF(dp); 1291541Srgrimes for (;;) { 1301541Srgrimes /* 1311541Srgrimes * Check if root directory should replace current directory. 1321541Srgrimes * Done at start of translation and after symbolic link. 1331541Srgrimes */ 1341541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 1351541Srgrimes if (*(cnp->cn_nameptr) == '/') { 1361541Srgrimes vrele(dp); 1371541Srgrimes while (*(cnp->cn_nameptr) == '/') { 1381541Srgrimes cnp->cn_nameptr++; 1391541Srgrimes ndp->ni_pathlen--; 1401541Srgrimes } 1411541Srgrimes dp = ndp->ni_rootdir; 1421541Srgrimes VREF(dp); 1431541Srgrimes } 1441541Srgrimes ndp->ni_startdir = dp; 1451541Srgrimes if (error = lookup(ndp)) { 1461541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 1471541Srgrimes return (error); 1481541Srgrimes } 1491541Srgrimes /* 1501541Srgrimes * Check for symbolic link 1511541Srgrimes */ 1521541Srgrimes if ((cnp->cn_flags & ISSYMLINK) == 0) { 1531541Srgrimes if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 1541541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 1551541Srgrimes else 1561541Srgrimes cnp->cn_flags |= HASBUF; 1571541Srgrimes return (0); 1581541Srgrimes } 1591541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1601541Srgrimes VOP_UNLOCK(ndp->ni_dvp); 1611541Srgrimes if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1621541Srgrimes error = ELOOP; 1631541Srgrimes break; 1641541Srgrimes } 1651541Srgrimes if (ndp->ni_pathlen > 1) 1661541Srgrimes MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1671541Srgrimes else 1681541Srgrimes cp = cnp->cn_pnbuf; 1691541Srgrimes aiov.iov_base = cp; 1701541Srgrimes aiov.iov_len = MAXPATHLEN; 1711541Srgrimes auio.uio_iov = &aiov; 1721541Srgrimes auio.uio_iovcnt = 1; 1731541Srgrimes auio.uio_offset = 0; 1741541Srgrimes auio.uio_rw = UIO_READ; 1751541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 1761541Srgrimes auio.uio_procp = (struct proc *)0; 1771541Srgrimes auio.uio_resid = MAXPATHLEN; 1781541Srgrimes if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) { 1791541Srgrimes if (ndp->ni_pathlen > 1) 1801541Srgrimes free(cp, M_NAMEI); 1811541Srgrimes break; 1821541Srgrimes } 1831541Srgrimes linklen = MAXPATHLEN - auio.uio_resid; 1841541Srgrimes if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 1851541Srgrimes if (ndp->ni_pathlen > 1) 1861541Srgrimes free(cp, M_NAMEI); 1871541Srgrimes error = ENAMETOOLONG; 1881541Srgrimes break; 1891541Srgrimes } 1901541Srgrimes if (ndp->ni_pathlen > 1) { 1911541Srgrimes bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 1921541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 1931541Srgrimes cnp->cn_pnbuf = cp; 1941541Srgrimes } else 1951541Srgrimes cnp->cn_pnbuf[linklen] = '\0'; 1961541Srgrimes ndp->ni_pathlen += linklen; 1971541Srgrimes vput(ndp->ni_vp); 1981541Srgrimes dp = ndp->ni_dvp; 1991541Srgrimes } 2001541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 2011541Srgrimes vrele(ndp->ni_dvp); 2021541Srgrimes vput(ndp->ni_vp); 2031541Srgrimes ndp->ni_vp = NULL; 2041541Srgrimes return (error); 2051541Srgrimes} 2061541Srgrimes 2071541Srgrimes/* 2081541Srgrimes * Search a pathname. 2091541Srgrimes * This is a very central and rather complicated routine. 2101541Srgrimes * 2111541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 2121541Srgrimes * The starting directory is taken from ni_startdir. The pathname is 2131541Srgrimes * descended until done, or a symbolic link is encountered. The variable 2141541Srgrimes * ni_more is clear if the path is completed; it is set to one if a 2151541Srgrimes * symbolic link needing interpretation is encountered. 2161541Srgrimes * 2171541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 2181541Srgrimes * whether the name is to be looked up, created, renamed, or deleted. 2191541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in 2201541Srgrimes * creating, renaming, or deleting a directory entry may be calculated. 2211541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned 2221541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is 2231541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If 2241541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag 2251541Srgrimes * the target is returned locked, otherwise it is returned unlocked. 2261541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not 2271541Srgrimes * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 2281541Srgrimes * 2291541Srgrimes * Overall outline of lookup: 2301541Srgrimes * 2311541Srgrimes * dirloop: 2321541Srgrimes * identify next component of name at ndp->ni_ptr 2331541Srgrimes * handle degenerate case where name is null string 2341541Srgrimes * if .. and crossing mount points and on mounted filesys, find parent 2351541Srgrimes * call VOP_LOOKUP routine for next component name 2361541Srgrimes * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 2371541Srgrimes * component vnode returned in ni_vp (if it exists), locked. 2381541Srgrimes * if result vnode is mounted on and crossing mount points, 2391541Srgrimes * find mounted on vnode 2401541Srgrimes * if more components of name, do next level at dirloop 2411541Srgrimes * return the answer in ni_vp, locked if LOCKLEAF set 2421541Srgrimes * if LOCKPARENT set, return locked parent in ni_dvp 2431541Srgrimes * if WANTPARENT set, return unlocked parent in ni_dvp 2441541Srgrimes */ 2451541Srgrimesint 2461541Srgrimeslookup(ndp) 2471541Srgrimes register struct nameidata *ndp; 2481541Srgrimes{ 2491541Srgrimes register char *cp; /* pointer into pathname argument */ 2501541Srgrimes register struct vnode *dp = 0; /* the directory we are searching */ 2511541Srgrimes struct vnode *tdp; /* saved dp */ 2521541Srgrimes struct mount *mp; /* mount table entry */ 2531541Srgrimes int docache; /* == 0 do not cache last component */ 2541541Srgrimes int wantparent; /* 1 => wantparent or lockparent flag */ 2551541Srgrimes int rdonly; /* lookup read-only flag bit */ 2561541Srgrimes int error = 0; 2571541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 2581541Srgrimes 2591541Srgrimes /* 2601541Srgrimes * Setup: break out flag bits into variables. 2611541Srgrimes */ 2621541Srgrimes wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 2631541Srgrimes docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 2641541Srgrimes if (cnp->cn_nameiop == DELETE || 2651541Srgrimes (wantparent && cnp->cn_nameiop != CREATE)) 2661541Srgrimes docache = 0; 2671541Srgrimes rdonly = cnp->cn_flags & RDONLY; 2681541Srgrimes ndp->ni_dvp = NULL; 2691541Srgrimes cnp->cn_flags &= ~ISSYMLINK; 2701541Srgrimes dp = ndp->ni_startdir; 2711541Srgrimes ndp->ni_startdir = NULLVP; 2721541Srgrimes VOP_LOCK(dp); 2731541Srgrimes 2741541Srgrimesdirloop: 2751541Srgrimes /* 2761541Srgrimes * Search a new directory. 2771541Srgrimes * 2781541Srgrimes * The cn_hash value is for use by vfs_cache. 2791541Srgrimes * The last component of the filename is left accessible via 2801541Srgrimes * cnp->cn_nameptr for callers that need the name. Callers needing 2811541Srgrimes * the name set the SAVENAME flag. When done, they assume 2821541Srgrimes * responsibility for freeing the pathname buffer. 2831541Srgrimes */ 2841541Srgrimes cnp->cn_consume = 0; 2851541Srgrimes cnp->cn_hash = 0; 2861541Srgrimes for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 2871541Srgrimes cnp->cn_hash += (unsigned char)*cp; 2881541Srgrimes cnp->cn_namelen = cp - cnp->cn_nameptr; 2891541Srgrimes if (cnp->cn_namelen > NAME_MAX) { 2901541Srgrimes error = ENAMETOOLONG; 2911541Srgrimes goto bad; 2921541Srgrimes } 2931541Srgrimes#ifdef NAMEI_DIAGNOSTIC 2941541Srgrimes { char c = *cp; 2951541Srgrimes *cp = '\0'; 2961541Srgrimes printf("{%s}: ", cnp->cn_nameptr); 2971541Srgrimes *cp = c; } 2981541Srgrimes#endif 2991541Srgrimes ndp->ni_pathlen -= cnp->cn_namelen; 3001541Srgrimes ndp->ni_next = cp; 3011541Srgrimes cnp->cn_flags |= MAKEENTRY; 3021541Srgrimes if (*cp == '\0' && docache == 0) 3031541Srgrimes cnp->cn_flags &= ~MAKEENTRY; 3041541Srgrimes if (cnp->cn_namelen == 2 && 3051541Srgrimes cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 3061541Srgrimes cnp->cn_flags |= ISDOTDOT; 3071541Srgrimes else 3081541Srgrimes cnp->cn_flags &= ~ISDOTDOT; 3091541Srgrimes if (*ndp->ni_next == 0) 3101541Srgrimes cnp->cn_flags |= ISLASTCN; 3111541Srgrimes else 3121541Srgrimes cnp->cn_flags &= ~ISLASTCN; 3131541Srgrimes 3141541Srgrimes 3151541Srgrimes /* 3161541Srgrimes * Check for degenerate name (e.g. / or "") 3171541Srgrimes * which is a way of talking about a directory, 3181541Srgrimes * e.g. like "/." or ".". 3191541Srgrimes */ 3201541Srgrimes if (cnp->cn_nameptr[0] == '\0') { 3211541Srgrimes if (cnp->cn_nameiop != LOOKUP) { 3221541Srgrimes error = EISDIR; 3231541Srgrimes goto bad; 3241541Srgrimes } 3251541Srgrimes if (dp->v_type != VDIR) { 3261541Srgrimes error = ENOTDIR; 3271541Srgrimes goto bad; 3281541Srgrimes } 3291541Srgrimes if (wantparent) { 3301541Srgrimes ndp->ni_dvp = dp; 3311541Srgrimes VREF(dp); 3321541Srgrimes } 3331541Srgrimes ndp->ni_vp = dp; 3341541Srgrimes if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 3351541Srgrimes VOP_UNLOCK(dp); 3361541Srgrimes if (cnp->cn_flags & SAVESTART) 3371541Srgrimes panic("lookup: SAVESTART"); 3381541Srgrimes return (0); 3391541Srgrimes } 3401541Srgrimes 3411541Srgrimes /* 3421541Srgrimes * Handle "..": two special cases. 3431541Srgrimes * 1. If at root directory (e.g. after chroot) 3441541Srgrimes * or at absolute root directory 3451541Srgrimes * then ignore it so can't get out. 3461541Srgrimes * 2. If this vnode is the root of a mounted 3471541Srgrimes * filesystem, then replace it with the 3481541Srgrimes * vnode which was mounted on so we take the 3491541Srgrimes * .. in the other file system. 3501541Srgrimes */ 3511541Srgrimes if (cnp->cn_flags & ISDOTDOT) { 3521541Srgrimes for (;;) { 3531541Srgrimes if (dp == ndp->ni_rootdir || dp == rootvnode) { 3541541Srgrimes ndp->ni_dvp = dp; 3551541Srgrimes ndp->ni_vp = dp; 3561541Srgrimes VREF(dp); 3571541Srgrimes goto nextname; 3581541Srgrimes } 3591541Srgrimes if ((dp->v_flag & VROOT) == 0 || 3601541Srgrimes (cnp->cn_flags & NOCROSSMOUNT)) 3611541Srgrimes break; 3621541Srgrimes tdp = dp; 3631541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 3641541Srgrimes vput(tdp); 3651541Srgrimes VREF(dp); 3661541Srgrimes VOP_LOCK(dp); 3671541Srgrimes } 3681541Srgrimes } 3691541Srgrimes 3701541Srgrimes /* 3711541Srgrimes * We now have a segment name to search for, and a directory to search. 3721541Srgrimes */ 3731541Srgrimesunionlookup: 3741541Srgrimes ndp->ni_dvp = dp; 3751541Srgrimes if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { 3761541Srgrimes#ifdef DIAGNOSTIC 3771541Srgrimes if (ndp->ni_vp != NULL) 3781541Srgrimes panic("leaf should be empty"); 3791541Srgrimes#endif 3801541Srgrimes#ifdef NAMEI_DIAGNOSTIC 3811541Srgrimes printf("not found\n"); 3821541Srgrimes#endif 3831541Srgrimes if ((error == ENOENT) && 3841541Srgrimes (dp->v_flag & VROOT) && 3851541Srgrimes (dp->v_mount->mnt_flag & MNT_UNION)) { 3861541Srgrimes tdp = dp; 3871541Srgrimes dp = dp->v_mount->mnt_vnodecovered; 3881541Srgrimes vput(tdp); 3891541Srgrimes VREF(dp); 3901541Srgrimes VOP_LOCK(dp); 3911541Srgrimes goto unionlookup; 3921541Srgrimes } 3931541Srgrimes 3941541Srgrimes if (error != EJUSTRETURN) 3951541Srgrimes goto bad; 3961541Srgrimes /* 3971541Srgrimes * If creating and at end of pathname, then can consider 3981541Srgrimes * allowing file to be created. 3991541Srgrimes */ 4001541Srgrimes if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 4011541Srgrimes error = EROFS; 4021541Srgrimes goto bad; 4031541Srgrimes } 4041541Srgrimes /* 4051541Srgrimes * We return with ni_vp NULL to indicate that the entry 4061541Srgrimes * doesn't currently exist, leaving a pointer to the 4071541Srgrimes * (possibly locked) directory inode in ndp->ni_dvp. 4081541Srgrimes */ 4091541Srgrimes if (cnp->cn_flags & SAVESTART) { 4101541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 4111541Srgrimes VREF(ndp->ni_startdir); 4121541Srgrimes } 4131541Srgrimes return (0); 4141541Srgrimes } 4151541Srgrimes#ifdef NAMEI_DIAGNOSTIC 4161541Srgrimes printf("found\n"); 4171541Srgrimes#endif 4181541Srgrimes 4191541Srgrimes /* 4201541Srgrimes * Take into account any additional components consumed by 4211541Srgrimes * the underlying filesystem. 4221541Srgrimes */ 4231541Srgrimes if (cnp->cn_consume > 0) { 4241541Srgrimes cnp->cn_nameptr += cnp->cn_consume; 4251541Srgrimes ndp->ni_next += cnp->cn_consume; 4261541Srgrimes ndp->ni_pathlen -= cnp->cn_consume; 4271541Srgrimes cnp->cn_consume = 0; 4281541Srgrimes } 4291541Srgrimes 4301541Srgrimes dp = ndp->ni_vp; 4311541Srgrimes /* 4321541Srgrimes * Check for symbolic link 4331541Srgrimes */ 4341541Srgrimes if ((dp->v_type == VLNK) && 4351541Srgrimes ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { 4361541Srgrimes cnp->cn_flags |= ISSYMLINK; 4371541Srgrimes return (0); 4381541Srgrimes } 4391541Srgrimes 4401541Srgrimes /* 4411541Srgrimes * Check to see if the vnode has been mounted on; 4421541Srgrimes * if so find the root of the mounted file system. 4431541Srgrimes */ 4441541Srgrimes while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 4451541Srgrimes (cnp->cn_flags & NOCROSSMOUNT) == 0) { 4461541Srgrimes if (mp->mnt_flag & MNT_MLOCK) { 4471541Srgrimes mp->mnt_flag |= MNT_MWAIT; 4481541Srgrimes sleep((caddr_t)mp, PVFS); 4491541Srgrimes continue; 4501541Srgrimes } 4511541Srgrimes if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) 4521541Srgrimes goto bad2; 4531541Srgrimes vput(dp); 4541541Srgrimes ndp->ni_vp = dp = tdp; 4551541Srgrimes } 4561541Srgrimes 4571541Srgrimesnextname: 4581541Srgrimes /* 4591541Srgrimes * Not a symbolic link. If more pathname, 4601541Srgrimes * continue at next component, else return. 4611541Srgrimes */ 4621541Srgrimes if (*ndp->ni_next == '/') { 4631541Srgrimes cnp->cn_nameptr = ndp->ni_next; 4641541Srgrimes while (*cnp->cn_nameptr == '/') { 4651541Srgrimes cnp->cn_nameptr++; 4661541Srgrimes ndp->ni_pathlen--; 4671541Srgrimes } 4681541Srgrimes vrele(ndp->ni_dvp); 4691541Srgrimes goto dirloop; 4701541Srgrimes } 4711541Srgrimes /* 4721541Srgrimes * Check for read-only file systems. 4731541Srgrimes */ 4741541Srgrimes if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 4751541Srgrimes /* 4761541Srgrimes * Disallow directory write attempts on read-only 4771541Srgrimes * file systems. 4781541Srgrimes */ 4791541Srgrimes if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 4801541Srgrimes (wantparent && 4811541Srgrimes (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 4821541Srgrimes error = EROFS; 4831541Srgrimes goto bad2; 4841541Srgrimes } 4851541Srgrimes } 4861541Srgrimes if (cnp->cn_flags & SAVESTART) { 4871541Srgrimes ndp->ni_startdir = ndp->ni_dvp; 4881541Srgrimes VREF(ndp->ni_startdir); 4891541Srgrimes } 4901541Srgrimes if (!wantparent) 4911541Srgrimes vrele(ndp->ni_dvp); 4921541Srgrimes if ((cnp->cn_flags & LOCKLEAF) == 0) 4931541Srgrimes VOP_UNLOCK(dp); 4941541Srgrimes return (0); 4951541Srgrimes 4961541Srgrimesbad2: 4971541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 4981541Srgrimes VOP_UNLOCK(ndp->ni_dvp); 4991541Srgrimes vrele(ndp->ni_dvp); 5001541Srgrimesbad: 5011541Srgrimes vput(dp); 5021541Srgrimes ndp->ni_vp = NULL; 5031541Srgrimes return (error); 5041541Srgrimes} 5051541Srgrimes 5061541Srgrimes 507