vfs_lookup.c revision 3148
1163953Srrs/* 2185694Srrs * Copyright (c) 1982, 1986, 1989, 1993 3235828Stuexen * The Regents of the University of California. All rights reserved. 4235828Stuexen * (c) UNIX System Laboratories, Inc. 5163953Srrs * All or some portions of this file are derived from material licensed 6163953Srrs * to the University of California by American Telephone and Telegraph 7163953Srrs * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8163953Srrs * the permission of UNIX System Laboratories, Inc. 9163953Srrs * 10228653Stuexen * Redistribution and use in source and binary forms, with or without 11163953Srrs * modification, are permitted provided that the following conditions 12163953Srrs * are met: 13163953Srrs * 1. Redistributions of source code must retain the above copyright 14228653Stuexen * notice, this list of conditions and the following disclaimer. 15163953Srrs * 2. Redistributions in binary form must reproduce the above copyright 16163953Srrs * notice, this list of conditions and the following disclaimer in the 17163953Srrs * documentation and/or other materials provided with the distribution. 18163953Srrs * 3. All advertising materials mentioning features or use of this software 19163953Srrs * must display the following acknowledgement: 20163953Srrs * This product includes software developed by the University of 21163953Srrs * California, Berkeley and its contributors. 22163953Srrs * 4. Neither the name of the University nor the names of its contributors 23163953Srrs * may be used to endorse or promote products derived from this software 24163953Srrs * without specific prior written permission. 25163953Srrs * 26163953Srrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36163953Srrs * SUCH DAMAGE. 37163953Srrs * 38167598Srrs * @(#)vfs_lookup.c 8.4 (Berkeley) 2/16/94 39163953Srrs * $Id: vfs_lookup.c,v 1.4 1994/08/20 03:48:49 davidg Exp $ 40163953Srrs */ 41163953Srrs 42163953Srrs#include <sys/param.h> 43163953Srrs#include <sys/systm.h> 44163953Srrs#include <sys/syslimits.h> 45163953Srrs#include <sys/time.h> 46163953Srrs#include <sys/namei.h> 47170091Srrs#include <sys/vnode.h> 48172091Srrs#include <sys/mount.h> 49188067Srrs#include <sys/errno.h> 50179157Srrs#include <sys/malloc.h> 51218211Srrs#include <sys/filedesc.h> 52163953Srrs#include <sys/proc.h> 53163953Srrs 54163953Srrs#ifdef KTRACE 55163953Srrs#include <sys/ktrace.h> 56163953Srrs#endif 57163953Srrs 58163953Srrs/* 59163953Srrs * Convert a pathname into a pointer to a locked inode. 60165220Srrs * 61165220Srrs * The FOLLOW flag is set when symbolic links are to be followed 62165220Srrs * when they occur at the end of the name translation process. 63165220Srrs * Symbolic links are always followed for all other pathname 64165220Srrs * components other than the last. 65163953Srrs * 66163953Srrs * The segflg defines whether the name is to be copied from user 67165220Srrs * space or kernel space. 68163953Srrs * 69163953Srrs * Overall outline of namei: 70163953Srrs * 71165220Srrs * copy in name 72165220Srrs * get starting directory 73165220Srrs * while (!done && !error) { 74165220Srrs * call lookup to search path. 75165220Srrs * if symbolic link, massage name in buffer and continue 76165220Srrs * } 77163953Srrs */ 78163953Srrsint 79163953Srrsnamei(ndp) 80163953Srrs register struct nameidata *ndp; 81163953Srrs{ 82163953Srrs register struct filedesc *fdp; /* pointer to file descriptor state */ 83237715Stuexen register char *cp; /* pointer into pathname argument */ 84237715Stuexen register struct vnode *dp; /* the directory we are searching */ 85237049Stuexen struct iovec aiov; /* uio for reading symbolic links */ 86237049Stuexen struct uio auio; 87237049Stuexen int error, linklen; 88237049Stuexen struct componentname *cnp = &ndp->ni_cnd; 89163953Srrs 90163953Srrs ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 91163953Srrs#ifdef DIAGNOSTIC 92163953Srrs if (!cnp->cn_cred || !cnp->cn_proc) 93169420Srrs panic ("namei: bad cred/proc"); 94240148Stuexen if (cnp->cn_nameiop & (~OPMASK)) 95172396Srrs panic ("namei: nameiop contaminated with flags"); 96172396Srrs if (cnp->cn_flags & OPMASK) 97172396Srrs panic ("namei: flags contaminated with nameiops"); 98229774Stuexen#endif 99163953Srrs fdp = cnp->cn_proc->p_fd; 100163953Srrs 101237715Stuexen /* 102237049Stuexen * Get a buffer for the name to be translated, and copy the 103179157Srrs * name into the buffer. 104168299Srrs */ 105168299Srrs if ((cnp->cn_flags & HASBUF) == 0) 106172396Srrs MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 107163953Srrs if (ndp->ni_segflg == UIO_SYSSPACE) 108163953Srrs error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 109229774Stuexen MAXPATHLEN, (u_int *)&ndp->ni_pathlen); 110163953Srrs else 111163953Srrs error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 112163953Srrs MAXPATHLEN, (u_int *)&ndp->ni_pathlen); 113237715Stuexen if (error) { 114237049Stuexen free(cnp->cn_pnbuf, M_NAMEI); 115179157Srrs ndp->ni_vp = NULL; 116168299Srrs return (error); 117168299Srrs } 118172396Srrs ndp->ni_loopcnt = 0; 119163953Srrs#ifdef KTRACE 120163953Srrs if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 121163953Srrs ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 122163953Srrs#endif 123237715Stuexen 124237049Stuexen /* 125179157Srrs * Get starting point for the translation. 126171440Srrs */ 127171440Srrs if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) 128172396Srrs ndp->ni_rootdir = rootvnode; 129163953Srrs dp = fdp->fd_cdir; 130163953Srrs VREF(dp); 131163953Srrs for (;;) { 132163953Srrs /* 133237715Stuexen * Check if root directory should replace current directory. 134237049Stuexen * Done at start of translation and after symbolic link. 135179157Srrs */ 136168299Srrs cnp->cn_nameptr = cnp->cn_pnbuf; 137168299Srrs if (*(cnp->cn_nameptr) == '/') { 138172396Srrs vrele(dp); 139163953Srrs while (*(cnp->cn_nameptr) == '/') { 140163953Srrs cnp->cn_nameptr++; 141163953Srrs ndp->ni_pathlen--; 142163953Srrs } 143237715Stuexen dp = ndp->ni_rootdir; 144237049Stuexen VREF(dp); 145179157Srrs } 146168299Srrs ndp->ni_startdir = dp; 147168299Srrs error = lookup(ndp); 148172396Srrs if (error) { 149163953Srrs FREE(cnp->cn_pnbuf, M_NAMEI); 150163953Srrs return (error); 151229774Stuexen } 152163953Srrs /* 153237715Stuexen * Check for symbolic link 154237049Stuexen */ 155237049Stuexen if ((cnp->cn_flags & ISSYMLINK) == 0) { 156168299Srrs if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 157168299Srrs FREE(cnp->cn_pnbuf, M_NAMEI); 158172396Srrs else 159163953Srrs cnp->cn_flags |= HASBUF; 160229774Stuexen return (0); 161229774Stuexen } 162229774Stuexen if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 163229774Stuexen VOP_UNLOCK(ndp->ni_dvp); 164229774Stuexen if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 165229774Stuexen error = ELOOP; 166229774Stuexen break; 167229774Stuexen } 168229774Stuexen if (ndp->ni_pathlen > 1) 169229774Stuexen MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 170229774Stuexen else 171229774Stuexen cp = cnp->cn_pnbuf; 172229774Stuexen aiov.iov_base = cp; 173229774Stuexen aiov.iov_len = MAXPATHLEN; 174229774Stuexen auio.uio_iov = &aiov; 175229774Stuexen auio.uio_iovcnt = 1; 176229774Stuexen auio.uio_offset = 0; 177229774Stuexen auio.uio_rw = UIO_READ; 178229774Stuexen auio.uio_segflg = UIO_SYSSPACE; 179229774Stuexen auio.uio_procp = (struct proc *)0; 180229774Stuexen auio.uio_resid = MAXPATHLEN; 181229805Stuexen error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 182237715Stuexen if (error) { 183237049Stuexen if (ndp->ni_pathlen > 1) 184237049Stuexen free(cp, M_NAMEI); 185229805Stuexen break; 186229774Stuexen } 187229774Stuexen linklen = MAXPATHLEN - auio.uio_resid; 188229774Stuexen if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 189229774Stuexen if (ndp->ni_pathlen > 1) 190229774Stuexen free(cp, M_NAMEI); 191229774Stuexen error = ENAMETOOLONG; 192229774Stuexen break; 193229774Stuexen } 194229774Stuexen if (ndp->ni_pathlen > 1) { 195237715Stuexen bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 196237715Stuexen FREE(cnp->cn_pnbuf, M_NAMEI); 197237049Stuexen cnp->cn_pnbuf = cp; 198237049Stuexen } else 199229774Stuexen cnp->cn_pnbuf[linklen] = '\0'; 200229774Stuexen ndp->ni_pathlen += linklen; 201172396Srrs vput(ndp->ni_vp); 202172396Srrs dp = ndp->ni_dvp; 203172396Srrs } 204172396Srrs FREE(cnp->cn_pnbuf, M_NAMEI); 205163953Srrs vrele(ndp->ni_dvp); 206163953Srrs vput(ndp->ni_vp); 207163953Srrs ndp->ni_vp = NULL; 208163953Srrs return (error); 209163953Srrs} 210171158Srrs 211171158Srrs/* 212221627Stuexen * Search a pathname. 213221627Stuexen * This is a very central and rather complicated routine. 214221627Stuexen * 215221627Stuexen * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 216221627Stuexen * The starting directory is taken from ni_startdir. The pathname is 217171158Srrs * descended until done, or a symbolic link is encountered. The variable 218171158Srrs * ni_more is clear if the path is completed; it is set to one if a 219217760Stuexen * symbolic link needing interpretation is encountered. 220217760Stuexen * 221171158Srrs * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 222171158Srrs * whether the name is to be looked up, created, renamed, or deleted. 223171158Srrs * When CREATE, RENAME, or DELETE is specified, information usable in 224171158Srrs * creating, renaming, or deleting a directory entry may be calculated. 225171158Srrs * If flag has LOCKPARENT or'ed into it, the parent directory is returned 226171158Srrs * locked. If flag has WANTPARENT or'ed into it, the parent directory is 227171158Srrs * returned unlocked. Otherwise the parent directory is not returned. If 228171158Srrs * the target of the pathname exists and LOCKLEAF is or'ed into the flag 229171158Srrs * the target is returned locked, otherwise it is returned unlocked. 230171158Srrs * When creating or renaming and LOCKPARENT is specified, the target may not 231217760Stuexen * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 232217760Stuexen * 233217760Stuexen * Overall outline of lookup: 234217760Stuexen * 235217760Stuexen * dirloop: 236217760Stuexen * identify next component of name at ndp->ni_ptr 237217760Stuexen * handle degenerate case where name is null string 238217760Stuexen * if .. and crossing mount points and on mounted filesys, find parent 239171158Srrs * call VOP_LOOKUP routine for next component name 240171158Srrs * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 241171158Srrs * component vnode returned in ni_vp (if it exists), locked. 242171158Srrs * if result vnode is mounted on and crossing mount points, 243171158Srrs * find mounted on vnode 244171158Srrs * if more components of name, do next level at dirloop 245171158Srrs * return the answer in ni_vp, locked if LOCKLEAF set 246171158Srrs * if LOCKPARENT set, return locked parent in ni_dvp 247171158Srrs * if WANTPARENT set, return unlocked parent in ni_dvp 248171158Srrs */ 249171158Srrsint 250171158Srrslookup(ndp) 251171158Srrs register struct nameidata *ndp; 252171158Srrs{ 253171158Srrs register char *cp; /* pointer into pathname argument */ 254171158Srrs register struct vnode *dp = 0; /* the directory we are searching */ 255217760Stuexen struct vnode *tdp; /* saved dp */ 256217760Stuexen struct mount *mp; /* mount table entry */ 257212712Stuexen int docache; /* == 0 do not cache last component */ 258212712Stuexen int wantparent; /* 1 => wantparent or lockparent flag */ 259212712Stuexen int rdonly; /* lookup read-only flag bit */ 260212712Stuexen int error = 0; 261171158Srrs struct componentname *cnp = &ndp->ni_cnd; 262171158Srrs 263171158Srrs /* 264171158Srrs * Setup: break out flag bits into variables. 265221627Stuexen */ 266171158Srrs wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 267171158Srrs docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 268216822Stuexen if (cnp->cn_nameiop == DELETE || 269171158Srrs (wantparent && cnp->cn_nameiop != CREATE)) 270171158Srrs docache = 0; 271171158Srrs rdonly = cnp->cn_flags & RDONLY; 272171158Srrs ndp->ni_dvp = NULL; 273171158Srrs cnp->cn_flags &= ~ISSYMLINK; 274171158Srrs dp = ndp->ni_startdir; 275171158Srrs ndp->ni_startdir = NULLVP; 276163953Srrs VOP_LOCK(dp); 277228653Stuexen 278163953Srrsdirloop: 279163953Srrs /* 280163953Srrs * Search a new directory. 281163953Srrs * 282163953Srrs * The cn_hash value is for use by vfs_cache. 283163953Srrs * The last component of the filename is left accessible via 284163953Srrs * cnp->cn_nameptr for callers that need the name. Callers needing 285163953Srrs * the name set the SAVENAME flag. When done, they assume 286163953Srrs * responsibility for freeing the pathname buffer. 287163953Srrs */ 288163953Srrs cnp->cn_consume = 0; 289218129Srrs cnp->cn_hash = 0; 290218129Srrs for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 291218129Srrs cnp->cn_hash += (unsigned char)*cp; 292212712Stuexen cnp->cn_namelen = cp - cnp->cn_nameptr; 293163953Srrs if (cnp->cn_namelen > NAME_MAX) { 294163953Srrs error = ENAMETOOLONG; 295163953Srrs goto bad; 296179783Srrs } 297170744Srrs#ifdef NAMEI_DIAGNOSTIC 298170744Srrs { char c = *cp; 299163953Srrs *cp = '\0'; 300163953Srrs printf("{%s}: ", cnp->cn_nameptr); 301164181Srrs *cp = c; } 302163953Srrs#endif 303163953Srrs ndp->ni_pathlen -= cnp->cn_namelen; 304163953Srrs ndp->ni_next = cp; 305216822Stuexen cnp->cn_flags |= MAKEENTRY; 306216822Stuexen if (*cp == '\0' && docache == 0) 307163953Srrs cnp->cn_flags &= ~MAKEENTRY; 308196260Stuexen if (cnp->cn_namelen == 2 && 309163953Srrs cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 310216822Stuexen cnp->cn_flags |= ISDOTDOT; 311216822Stuexen else 312216822Stuexen cnp->cn_flags &= ~ISDOTDOT; 313216822Stuexen if (*ndp->ni_next == 0) 314242714Stuexen cnp->cn_flags |= ISLASTCN; 315242714Stuexen else 316242714Stuexen cnp->cn_flags &= ~ISLASTCN; 317242714Stuexen 318242714Stuexen 319242714Stuexen /* 320242714Stuexen * Check for degenerate name (e.g. / or "") 321216822Stuexen * which is a way of talking about a directory, 322216822Stuexen * e.g. like "/." or ".". 323235416Stuexen */ 324235416Stuexen if (cnp->cn_nameptr[0] == '\0') { 325216822Stuexen if (cnp->cn_nameiop != LOOKUP) { 326216822Stuexen error = EISDIR; 327216822Stuexen goto bad; 328196260Stuexen } 329196260Stuexen if (dp->v_type != VDIR) { 330221627Stuexen error = ENOTDIR; 331216822Stuexen goto bad; 332196260Stuexen } 333196260Stuexen if (wantparent) { 334163953Srrs ndp->ni_dvp = dp; 335163953Srrs VREF(dp); 336163953Srrs } 337216822Stuexen ndp->ni_vp = dp; 338196260Stuexen if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 339163953Srrs VOP_UNLOCK(dp); 340163953Srrs if (cnp->cn_flags & SAVESTART) 341235416Stuexen panic("lookup: SAVESTART"); 342163953Srrs return (0); 343163953Srrs } 344163953Srrs 345163953Srrs /* 346212712Stuexen * Handle "..": two special cases. 347212712Stuexen * 1. If at root directory (e.g. after chroot) 348212712Stuexen * or at absolute root directory 349212712Stuexen * then ignore it so can't get out. 350163953Srrs * 2. If this vnode is the root of a mounted 351221627Stuexen * filesystem, then replace it with the 352169655Srrs * vnode which was mounted on so we take the 353163953Srrs * .. in the other file system. 354163953Srrs */ 355163953Srrs if (cnp->cn_flags & ISDOTDOT) { 356196260Stuexen for (;;) { 357163953Srrs if (dp == ndp->ni_rootdir || dp == rootvnode) { 358163953Srrs ndp->ni_dvp = dp; 359164181Srrs ndp->ni_vp = dp; 360188854Srrs VREF(dp); 361218129Srrs goto nextname; 362185694Srrs } 363185694Srrs if ((dp->v_flag & VROOT) == 0 || 364179783Srrs (cnp->cn_flags & NOCROSSMOUNT)) 365170744Srrs break; 366170744Srrs tdp = dp; 367163953Srrs dp = dp->v_mount->mnt_vnodecovered; 368163953Srrs vput(tdp); 369163953Srrs VREF(dp); 370163953Srrs VOP_LOCK(dp); 371180955Srrs } 372218129Srrs } 373163953Srrs 374163953Srrs /* 375170091Srrs * We now have a segment name to search for, and a directory to search. 376163953Srrs */ 377163953Srrsunionlookup: 378216822Stuexen ndp->ni_dvp = dp; 379164181Srrs error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp); 380164181Srrs if (error) { 381216822Stuexen#ifdef DIAGNOSTIC 382164181Srrs if (ndp->ni_vp != NULL) 383164181Srrs panic("leaf should be empty"); 384171158Srrs#endif 385164181Srrs#ifdef NAMEI_DIAGNOSTIC 386164181Srrs printf("not found\n"); 387164181Srrs#endif 388164181Srrs if ((error == ENOENT) && 389164181Srrs (dp->v_flag & VROOT) && 390170091Srrs (dp->v_mount->mnt_flag & MNT_UNION)) { 391163953Srrs tdp = dp; 392164181Srrs dp = dp->v_mount->mnt_vnodecovered; 393164181Srrs vput(tdp); 394164181Srrs VREF(dp); 395164181Srrs VOP_LOCK(dp); 396163953Srrs goto unionlookup; 397170091Srrs } 398163953Srrs 399163953Srrs if (error != EJUSTRETURN) 400169420Srrs goto bad; 401163953Srrs /* 402163953Srrs * If creating and at end of pathname, then can consider 403163953Srrs * allowing file to be created. 404163953Srrs */ 405163953Srrs if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 406163953Srrs error = EROFS; 407163953Srrs goto bad; 408163953Srrs } 409163953Srrs /* 410163953Srrs * We return with ni_vp NULL to indicate that the entry 411163953Srrs * doesn't currently exist, leaving a pointer to the 412168943Srrs * (possibly locked) directory inode in ndp->ni_dvp. 413163953Srrs */ 414163953Srrs if (cnp->cn_flags & SAVESTART) { 415163953Srrs ndp->ni_startdir = ndp->ni_dvp; 416163953Srrs VREF(ndp->ni_startdir); 417163953Srrs } 418163953Srrs return (0); 419163953Srrs } 420163953Srrs#ifdef NAMEI_DIAGNOSTIC 421163953Srrs printf("found\n"); 422163953Srrs#endif 423169655Srrs 424163953Srrs /* 425163953Srrs * Take into account any additional components consumed by 426163953Srrs * the underlying filesystem. 427163953Srrs */ 428163953Srrs if (cnp->cn_consume > 0) { 429163953Srrs cnp->cn_nameptr += cnp->cn_consume; 430163953Srrs ndp->ni_next += cnp->cn_consume; 431237715Stuexen ndp->ni_pathlen -= cnp->cn_consume; 432237715Stuexen cnp->cn_consume = 0; 433237049Stuexen } 434237049Stuexen 435237049Stuexen dp = ndp->ni_vp; 436237049Stuexen /* 437163953Srrs * Check for symbolic link 438163953Srrs */ 439163953Srrs if ((dp->v_type == VLNK) && 440163953Srrs ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { 441163953Srrs cnp->cn_flags |= ISSYMLINK; 442185694Srrs return (0); 443163953Srrs } 444163953Srrs 445163953Srrs /* 446163953Srrs * Check to see if the vnode has been mounted on; 447163953Srrs * if so find the root of the mounted file system. 448163953Srrs */ 449163953Srrs while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 450185694Srrs (cnp->cn_flags & NOCROSSMOUNT) == 0) { 451163953Srrs if (mp->mnt_flag & MNT_MLOCK) { 452163953Srrs mp->mnt_flag |= MNT_MWAIT; 453235360Stuexen sleep((caddr_t)mp, PVFS); 454170056Srrs continue; 455163953Srrs } 456163953Srrs error = VFS_ROOT(dp->v_mountedhere, &tdp); 457163953Srrs if (error) 458185694Srrs goto bad2; 459163953Srrs vput(dp); 460228653Stuexen ndp->ni_vp = dp = tdp; 461163953Srrs } 462163953Srrs 463163953Srrsnextname: 464163953Srrs /* 465163953Srrs * Not a symbolic link. If more pathname, 466228653Stuexen * continue at next component, else return. 467237715Stuexen */ 468237715Stuexen if (*ndp->ni_next == '/') { 469163953Srrs cnp->cn_nameptr = ndp->ni_next; 470169420Srrs while (*cnp->cn_nameptr == '/') { 471169420Srrs cnp->cn_nameptr++; 472169420Srrs ndp->ni_pathlen--; 473237715Stuexen } 474237715Stuexen vrele(ndp->ni_dvp); 475237049Stuexen goto dirloop; 476237049Stuexen } 477168299Srrs /* 478163953Srrs * Check for read-only file systems. 479163953Srrs */ 480171477Srrs if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 481171477Srrs /* 482216822Stuexen * Disallow directory write attempts on read-only 483171477Srrs * file systems. 484216822Stuexen */ 485216822Stuexen if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 486216822Stuexen (wantparent && 487171477Srrs (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 488171477Srrs error = EROFS; 489163953Srrs goto bad2; 490163953Srrs } 491163953Srrs } 492163953Srrs if (cnp->cn_flags & SAVESTART) { 493163953Srrs ndp->ni_startdir = ndp->ni_dvp; 494163953Srrs VREF(ndp->ni_startdir); 495163953Srrs } 496163953Srrs if (!wantparent) 497179783Srrs vrele(ndp->ni_dvp); 498171943Srrs if ((cnp->cn_flags & LOCKLEAF) == 0) 499171943Srrs VOP_UNLOCK(dp); 500171943Srrs return (0); 501171943Srrs 502171943Srrsbad2: 503171943Srrs if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 504163953Srrs VOP_UNLOCK(ndp->ni_dvp); 505163953Srrs vrele(ndp->ni_dvp); 506163953Srrsbad: 507163953Srrs vput(dp); 508163953Srrs ndp->ni_vp = NULL; 509163953Srrs return (error); 510163953Srrs} 511163953Srrs 512163953Srrs/* 513163953Srrs * relookup - lookup a path name component 514165220Srrs * Used by lookup to re-aquire things. 515163953Srrs */ 516165220Srrsint 517218186Srrsrelookup(dvp, vpp, cnp) 518219397Srrs struct vnode *dvp, **vpp; 519165220Srrs struct componentname *cnp; 520163953Srrs{ 521163953Srrs register struct vnode *dp = 0; /* the directory we are searching */ 522163953Srrs int docache; /* == 0 do not cache last component */ 523163953Srrs int wantparent; /* 1 => wantparent or lockparent flag */ 524163953Srrs int rdonly; /* lookup read-only flag bit */ 525163953Srrs int error = 0; 526163953Srrs#ifdef NAMEI_DIAGNOSTIC 527163953Srrs int newhash; /* DEBUG: check name hash */ 528163953Srrs char *cp; /* DEBUG: check name ptr/len */ 529163953Srrs#endif 530163953Srrs 531163953Srrs /* 532163953Srrs * Setup: break out flag bits into variables. 533163953Srrs */ 534163953Srrs wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 535163953Srrs docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 536163953Srrs if (cnp->cn_nameiop == DELETE || 537163953Srrs (wantparent && cnp->cn_nameiop != CREATE)) 538165647Srrs docache = 0; 539163953Srrs rdonly = cnp->cn_flags & RDONLY; 540163953Srrs cnp->cn_flags &= ~ISSYMLINK; 541163953Srrs dp = dvp; 542163953Srrs VOP_LOCK(dp); 543163953Srrs 544163953Srrs/* dirloop: */ 545163953Srrs /* 546163953Srrs * Search a new directory. 547163953Srrs * 548163953Srrs * The cn_hash value is for use by vfs_cache. 549163953Srrs * The last component of the filename is left accessible via 550237715Stuexen * cnp->cn_nameptr for callers that need the name. Callers needing 551237049Stuexen * the name set the SAVENAME flag. When done, they assume 552237049Stuexen * responsibility for freeing the pathname buffer. 553168299Srrs */ 554163953Srrs#ifdef NAMEI_DIAGNOSTIC 555163953Srrs for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 556163953Srrs newhash += (unsigned char)*cp; 557163953Srrs if (newhash != cnp->cn_hash) 558163953Srrs panic("relookup: bad hash"); 559163953Srrs if (cnp->cn_namelen != cp - cnp->cn_nameptr) 560163953Srrs panic ("relookup: bad len"); 561163953Srrs if (*cp != 0) 562163953Srrs panic("relookup: not last component"); 563163953Srrs printf("{%s}: ", cnp->cn_nameptr); 564163953Srrs#endif 565212225Srrs 566163953Srrs /* 567172396Srrs * Check for degenerate name (e.g. / or "") 568224641Stuexen * which is a way of talking about a directory, 569163953Srrs * e.g. like "/." or ".". 570221249Stuexen */ 571221249Stuexen if (cnp->cn_nameptr[0] == '\0') { 572221249Stuexen if (cnp->cn_nameiop != LOOKUP || wantparent) { 573221249Stuexen error = EISDIR; 574221249Stuexen goto bad; 575221249Stuexen } 576221249Stuexen if (dp->v_type != VDIR) { 577221249Stuexen error = ENOTDIR; 578221249Stuexen goto bad; 579163953Srrs } 580163953Srrs if (!(cnp->cn_flags & LOCKLEAF)) 581163953Srrs VOP_UNLOCK(dp); 582163953Srrs *vpp = dp; 583163953Srrs if (cnp->cn_flags & SAVESTART) 584221249Stuexen panic("lookup: SAVESTART"); 585221249Stuexen return (0); 586221249Stuexen } 587221249Stuexen 588221249Stuexen if (cnp->cn_flags & ISDOTDOT) 589221249Stuexen panic ("relookup: lookup on dot-dot"); 590221249Stuexen 591221249Stuexen /* 592221249Stuexen * We now have a segment name to search for, and a directory to search. 593221249Stuexen */ 594221249Stuexen error = VOP_LOOKUP(dp, vpp, cnp); 595221249Stuexen if (error) { 596221249Stuexen#ifdef DIAGNOSTIC 597221249Stuexen if (*vpp != NULL) 598221249Stuexen panic("leaf should be empty"); 599221249Stuexen#endif 600221249Stuexen if (error != EJUSTRETURN) 601221249Stuexen goto bad; 602221249Stuexen /* 603221249Stuexen * If creating and at end of pathname, then can consider 604221249Stuexen * allowing file to be created. 605221249Stuexen */ 606221249Stuexen if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) { 607221249Stuexen error = EROFS; 608221249Stuexen goto bad; 609221249Stuexen } 610221249Stuexen /* ASSERT(dvp == ndp->ni_startdir) */ 611221249Stuexen if (cnp->cn_flags & SAVESTART) 612221249Stuexen VREF(dvp); 613221249Stuexen /* 614163953Srrs * We return with ni_vp NULL to indicate that the entry 615163953Srrs * doesn't currently exist, leaving a pointer to the 616221249Stuexen * (possibly locked) directory inode in ndp->ni_dvp. 617163953Srrs */ 618169420Srrs return (0); 619163953Srrs } 620163953Srrs dp = *vpp; 621163953Srrs 622163953Srrs#ifdef DIAGNOSTIC 623163953Srrs /* 624163953Srrs * Check for symbolic link 625163953Srrs */ 626163953Srrs if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW)) 627163953Srrs panic ("relookup: symlink found.\n"); 628163953Srrs#endif 629167598Srrs 630167598Srrs /* 631167598Srrs * Check for read-only file systems. 632212225Srrs */ 633212225Srrs if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 634167598Srrs /* 635167598Srrs * Disallow directory write attempts on read-only 636167598Srrs * file systems. 637167598Srrs */ 638167598Srrs if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 639167598Srrs (wantparent && 640212225Srrs (dvp->v_mount->mnt_flag & MNT_RDONLY))) { 641212225Srrs error = EROFS; 642167598Srrs goto bad2; 643172396Srrs } 644167598Srrs } 645163953Srrs /* ASSERT(dvp == ndp->ni_startdir) */ 646172090Srrs if (cnp->cn_flags & SAVESTART) 647224641Stuexen VREF(dvp); 648224641Stuexen 649163953Srrs if (!wantparent) 650224641Stuexen vrele(dvp); 651163953Srrs if ((cnp->cn_flags & LOCKLEAF) == 0) 652163953Srrs VOP_UNLOCK(dp); 653163953Srrs return (0); 654163953Srrs 655224641Stuexenbad2: 656224641Stuexen if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 657224641Stuexen VOP_UNLOCK(dvp); 658224641Stuexen vrele(dvp); 659163953Srrsbad: 660163953Srrs vput(dp); 661235414Stuexen *vpp = NULL; 662163953Srrs return (error); 663224641Stuexen} 664224641Stuexen