Home | History | Annotate | Line # | Download | only in kern
vfs_lookup.c revision 1.24
      1 /*	$NetBSD: vfs_lookup.c,v 1.24 1997/10/11 00:08:08 enami Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1989, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * (c) UNIX System Laboratories, Inc.
      7  * All or some portions of this file are derived from material licensed
      8  * to the University of California by American Telephone and Telegraph
      9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10  * the permission of UNIX System Laboratories, Inc.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  *	This product includes software developed by the University of
     23  *	California, Berkeley and its contributors.
     24  * 4. Neither the name of the University nor the names of its contributors
     25  *    may be used to endorse or promote products derived from this software
     26  *    without specific prior written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  * SUCH DAMAGE.
     39  *
     40  *	@(#)vfs_lookup.c	8.6 (Berkeley) 11/21/94
     41  */
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/syslimits.h>
     46 #include <sys/time.h>
     47 #include <sys/namei.h>
     48 #include <sys/vnode.h>
     49 #include <sys/mount.h>
     50 #include <sys/errno.h>
     51 #include <sys/malloc.h>
     52 #include <sys/filedesc.h>
     53 #include <sys/proc.h>
     54 
     55 #ifdef KTRACE
     56 #include <sys/ktrace.h>
     57 #endif
     58 
     59 /*
     60  * Convert a pathname into a pointer to a locked inode.
     61  *
     62  * The FOLLOW flag is set when symbolic links are to be followed
     63  * when they occur at the end of the name translation process.
     64  * Symbolic links are always followed for all other pathname
     65  * components other than the last.
     66  *
     67  * The segflg defines whether the name is to be copied from user
     68  * space or kernel space.
     69  *
     70  * Overall outline of namei:
     71  *
     72  *	copy in name
     73  *	get starting directory
     74  *	while (!done && !error) {
     75  *		call lookup to search path.
     76  *		if symbolic link, massage name in buffer and continue
     77  *	}
     78  */
     79 int
     80 namei(ndp)
     81 	register struct nameidata *ndp;
     82 {
     83 	register struct filedesc *fdp;	/* pointer to file descriptor state */
     84 	register char *cp;		/* pointer into pathname argument */
     85 	register struct vnode *dp;	/* the directory we are searching */
     86 	struct iovec aiov;		/* uio for reading symbolic links */
     87 	struct uio auio;
     88 	int error, linklen;
     89 	struct componentname *cnp = &ndp->ni_cnd;
     90 
     91 	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
     92 #ifdef DIAGNOSTIC
     93 	if (!cnp->cn_cred || !cnp->cn_proc)
     94 		panic ("namei: bad cred/proc");
     95 	if (cnp->cn_nameiop & (~OPMASK))
     96 		panic ("namei: nameiop contaminated with flags");
     97 	if (cnp->cn_flags & OPMASK)
     98 		panic ("namei: flags contaminated with nameiops");
     99 #endif
    100 	fdp = cnp->cn_proc->p_fd;
    101 
    102 	/*
    103 	 * Get a buffer for the name to be translated, and copy the
    104 	 * name into the buffer.
    105 	 */
    106 	if ((cnp->cn_flags & HASBUF) == 0)
    107 		MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
    108 	if (ndp->ni_segflg == UIO_SYSSPACE)
    109 		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
    110 			    MAXPATHLEN, &ndp->ni_pathlen);
    111 	else
    112 		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
    113 			    MAXPATHLEN, &ndp->ni_pathlen);
    114 
    115 	/*
    116 	 * POSIX.1 requirement: "" is not a valid file name.
    117 	 */
    118 	if (!error && ndp->ni_pathlen == 1)
    119 		error = ENOENT;
    120 
    121 	if (error) {
    122 		free(cnp->cn_pnbuf, M_NAMEI);
    123 		ndp->ni_vp = NULL;
    124 		return (error);
    125 	}
    126 	ndp->ni_loopcnt = 0;
    127 
    128 #ifdef KTRACE
    129 	if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
    130 		ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
    131 #endif
    132 
    133 	/*
    134 	 * Get starting point for the translation.
    135 	 */
    136 	if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
    137 		ndp->ni_rootdir = rootvnode;
    138 	/*
    139 	 * Check if starting from root directory or current directory.
    140 	 */
    141 	if (cnp->cn_pnbuf[0] == '/') {
    142 		dp = ndp->ni_rootdir;
    143 		VREF(dp);
    144 	} else {
    145 		dp = fdp->fd_cdir;
    146 		VREF(dp);
    147 	}
    148 	for (;;) {
    149 		cnp->cn_nameptr = cnp->cn_pnbuf;
    150 		ndp->ni_startdir = dp;
    151 		if ((error = lookup(ndp)) != 0) {
    152 			FREE(cnp->cn_pnbuf, M_NAMEI);
    153 			return (error);
    154 		}
    155 		/*
    156 		 * Check for symbolic link
    157 		 */
    158 		if ((cnp->cn_flags & ISSYMLINK) == 0) {
    159 			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
    160 				FREE(cnp->cn_pnbuf, M_NAMEI);
    161 			else
    162 				cnp->cn_flags |= HASBUF;
    163 			return (0);
    164 		}
    165 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
    166 			VOP_UNLOCK(ndp->ni_dvp);
    167 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
    168 			error = ELOOP;
    169 			break;
    170 		}
    171 		error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
    172 		    cnp->cn_proc);
    173 		if (error != 0)
    174 			break;
    175 		if (ndp->ni_pathlen > 1)
    176 			MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
    177 		else
    178 			cp = cnp->cn_pnbuf;
    179 		aiov.iov_base = cp;
    180 		aiov.iov_len = MAXPATHLEN;
    181 		auio.uio_iov = &aiov;
    182 		auio.uio_iovcnt = 1;
    183 		auio.uio_offset = 0;
    184 		auio.uio_rw = UIO_READ;
    185 		auio.uio_segflg = UIO_SYSSPACE;
    186 		auio.uio_procp = (struct proc *)0;
    187 		auio.uio_resid = MAXPATHLEN;
    188 		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
    189 		if (error) {
    190 		badlink:
    191 			if (ndp->ni_pathlen > 1)
    192 				FREE(cp, M_NAMEI);
    193 			break;
    194 		}
    195 		linklen = MAXPATHLEN - auio.uio_resid;
    196 		if (linklen == 0) {
    197 			error = ENOENT;
    198 			goto badlink;
    199 		}
    200 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
    201 			error = ENAMETOOLONG;
    202 			goto badlink;
    203 		}
    204 		if (ndp->ni_pathlen > 1) {
    205 			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
    206 			FREE(cnp->cn_pnbuf, M_NAMEI);
    207 			cnp->cn_pnbuf = cp;
    208 		} else
    209 			cnp->cn_pnbuf[linklen] = '\0';
    210 		ndp->ni_pathlen += linklen;
    211 		vput(ndp->ni_vp);
    212 		dp = ndp->ni_dvp;
    213 		/*
    214 		 * Check if root directory should replace current directory.
    215 		 */
    216 		if (cnp->cn_pnbuf[0] == '/') {
    217 			vrele(dp);
    218 			dp = ndp->ni_rootdir;
    219 			VREF(dp);
    220 		}
    221 	}
    222 	FREE(cnp->cn_pnbuf, M_NAMEI);
    223 	vrele(ndp->ni_dvp);
    224 	vput(ndp->ni_vp);
    225 	ndp->ni_vp = NULL;
    226 	return (error);
    227 }
    228 
    229 /*
    230  * Search a pathname.
    231  * This is a very central and rather complicated routine.
    232  *
    233  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
    234  * The starting directory is taken from ni_startdir. The pathname is
    235  * descended until done, or a symbolic link is encountered. The variable
    236  * ni_more is clear if the path is completed; it is set to one if a
    237  * symbolic link needing interpretation is encountered.
    238  *
    239  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
    240  * whether the name is to be looked up, created, renamed, or deleted.
    241  * When CREATE, RENAME, or DELETE is specified, information usable in
    242  * creating, renaming, or deleting a directory entry may be calculated.
    243  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
    244  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
    245  * returned unlocked. Otherwise the parent directory is not returned. If
    246  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
    247  * the target is returned locked, otherwise it is returned unlocked.
    248  * When creating or renaming and LOCKPARENT is specified, the target may not
    249  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
    250  *
    251  * Overall outline of lookup:
    252  *
    253  * dirloop:
    254  *	identify next component of name at ndp->ni_ptr
    255  *	handle degenerate case where name is null string
    256  *	if .. and crossing mount points and on mounted filesys, find parent
    257  *	call VOP_LOOKUP routine for next component name
    258  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
    259  *	    component vnode returned in ni_vp (if it exists), locked.
    260  *	if result vnode is mounted on and crossing mount points,
    261  *	    find mounted on vnode
    262  *	if more components of name, do next level at dirloop
    263  *	return the answer in ni_vp, locked if LOCKLEAF set
    264  *	    if LOCKPARENT set, return locked parent in ni_dvp
    265  *	    if WANTPARENT set, return unlocked parent in ni_dvp
    266  */
    267 int
    268 lookup(ndp)
    269 	register struct nameidata *ndp;
    270 {
    271 	register const char *cp;	/* pointer into pathname argument */
    272 	register struct vnode *dp = 0;	/* the directory we are searching */
    273 	struct vnode *tdp;		/* saved dp */
    274 	struct mount *mp;		/* mount table entry */
    275 	int docache;			/* == 0 do not cache last component */
    276 	int wantparent;			/* 1 => wantparent or lockparent flag */
    277 	int rdonly;			/* lookup read-only flag bit */
    278 	int error = 0;
    279 	int slashes;
    280 	struct componentname *cnp = &ndp->ni_cnd;
    281 
    282 	/*
    283 	 * Setup: break out flag bits into variables.
    284 	 */
    285 	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
    286 	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
    287 	if (cnp->cn_nameiop == DELETE ||
    288 	    (wantparent && cnp->cn_nameiop != CREATE))
    289 		docache = 0;
    290 	rdonly = cnp->cn_flags & RDONLY;
    291 	ndp->ni_dvp = NULL;
    292 	cnp->cn_flags &= ~ISSYMLINK;
    293 	dp = ndp->ni_startdir;
    294 	ndp->ni_startdir = NULLVP;
    295 	VOP_LOCK(dp);
    296 
    297 	/*
    298 	 * If we have a leading string of slashes, remove them, and just make
    299 	 * sure the current node is a directory.
    300 	 */
    301 	cp = cnp->cn_nameptr;
    302 	if (*cp == '/') {
    303 		do {
    304 			cp++;
    305 		} while (*cp == '/');
    306 		ndp->ni_pathlen -= cp - cnp->cn_nameptr;
    307 		cnp->cn_nameptr = cp;
    308 
    309 		if (dp->v_type != VDIR) {
    310 			error = ENOTDIR;
    311 			goto bad;
    312 		}
    313 
    314 		/*
    315 		 * If we've exhausted the path name, then just return the
    316 		 * current node.  If the caller requested the parent node (i.e.
    317 		 * it's a CREATE, DELETE, or RENAME), and we don't have one
    318 		 * (because this is the root directory), then we must fail.
    319 		 */
    320 		if (cnp->cn_nameptr[0] == '\0') {
    321 			if (ndp->ni_dvp == NULL && wantparent) {
    322 				error = EISDIR;
    323 				goto bad;
    324 			}
    325 			ndp->ni_vp = dp;
    326 			cnp->cn_flags |= ISLASTCN;
    327 			goto terminal;
    328 		}
    329 	}
    330 
    331 dirloop:
    332 	/*
    333 	 * Search a new directory.
    334 	 *
    335 	 * The cn_hash value is for use by vfs_cache.
    336 	 * The last component of the filename is left accessible via
    337 	 * cnp->cn_nameptr for callers that need the name. Callers needing
    338 	 * the name set the SAVENAME flag. When done, they assume
    339 	 * responsibility for freeing the pathname buffer.
    340 	 */
    341 	cnp->cn_consume = 0;
    342 	cnp->cn_hash = 0;
    343 	for (cp = cnp->cn_nameptr; *cp != '\0' && *cp != '/'; cp++)
    344 		cnp->cn_hash += (unsigned char)*cp;
    345 	cnp->cn_namelen = cp - cnp->cn_nameptr;
    346 	if (cnp->cn_namelen > NAME_MAX) {
    347 		error = ENAMETOOLONG;
    348 		goto bad;
    349 	}
    350 #ifdef NAMEI_DIAGNOSTIC
    351 	{ char c = *cp;
    352 	*cp = '\0';
    353 	printf("{%s}: ", cnp->cn_nameptr);
    354 	*cp = c; }
    355 #endif
    356 	ndp->ni_pathlen -= cnp->cn_namelen;
    357 	ndp->ni_next = cp;
    358 	/*
    359 	 * If this component is followed by a slash, then move the pointer to
    360 	 * the next component forward, and remember that this component must be
    361 	 * a directory.
    362 	 */
    363 	if (*cp == '/') {
    364 		do {
    365 			cp++;
    366 		} while (*cp == '/');
    367 		slashes = cp - ndp->ni_next;
    368 		ndp->ni_pathlen -= slashes;
    369 		ndp->ni_next = cp;
    370 		cnp->cn_flags |= REQUIREDIR;
    371 	} else {
    372 		slashes = 0;
    373 		cnp->cn_flags &= ~REQUIREDIR;
    374 	}
    375 	/*
    376 	 * We do special processing on the last component, whether or not it's
    377 	 * a directory.  Cache all intervening lookups, but not the final one.
    378 	 */
    379 	if (*cp == '\0') {
    380 		if (docache)
    381 			cnp->cn_flags |= MAKEENTRY;
    382 		else
    383 			cnp->cn_flags &= ~MAKEENTRY;
    384 		cnp->cn_flags |= ISLASTCN;
    385 	} else {
    386 		cnp->cn_flags |= MAKEENTRY;
    387 		cnp->cn_flags &= ~ISLASTCN;
    388 	}
    389 	if (cnp->cn_namelen == 2 &&
    390 	    cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
    391 		cnp->cn_flags |= ISDOTDOT;
    392 	else
    393 		cnp->cn_flags &= ~ISDOTDOT;
    394 
    395 	/*
    396 	 * Handle "..": two special cases.
    397 	 * 1. If at root directory (e.g. after chroot)
    398 	 *    or at absolute root directory
    399 	 *    then ignore it so can't get out.
    400 	 * 2. If this vnode is the root of a mounted
    401 	 *    filesystem, then replace it with the
    402 	 *    vnode which was mounted on so we take the
    403 	 *    .. in the other file system.
    404 	 */
    405 	if (cnp->cn_flags & ISDOTDOT) {
    406 		for (;;) {
    407 			if (dp == ndp->ni_rootdir || dp == rootvnode) {
    408 				ndp->ni_dvp = dp;
    409 				ndp->ni_vp = dp;
    410 				VREF(dp);
    411 				goto nextname;
    412 			}
    413 			if ((dp->v_flag & VROOT) == 0 ||
    414 			    (cnp->cn_flags & NOCROSSMOUNT))
    415 				break;
    416 			tdp = dp;
    417 			dp = dp->v_mount->mnt_vnodecovered;
    418 			vput(tdp);
    419 			VREF(dp);
    420 			VOP_LOCK(dp);
    421 		}
    422 	}
    423 
    424 	/*
    425 	 * We now have a segment name to search for, and a directory to search.
    426 	 */
    427 unionlookup:
    428 	ndp->ni_dvp = dp;
    429 	if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
    430 #ifdef DIAGNOSTIC
    431 		if (ndp->ni_vp != NULL)
    432 			panic("leaf should be empty");
    433 #endif
    434 #ifdef NAMEI_DIAGNOSTIC
    435 		printf("not found\n");
    436 #endif
    437 		if ((error == ENOENT) &&
    438 		    (dp->v_flag & VROOT) &&
    439 		    (dp->v_mount->mnt_flag & MNT_UNION)) {
    440 			tdp = dp;
    441 			dp = dp->v_mount->mnt_vnodecovered;
    442 			vput(tdp);
    443 			VREF(dp);
    444 			VOP_LOCK(dp);
    445 			goto unionlookup;
    446 		}
    447 
    448 		if (error != EJUSTRETURN)
    449 			goto bad;
    450 		/*
    451 		 * If this was not the last component, or there were trailing
    452 		 * slashes, then the name must exist.
    453 		 */
    454 		if (cnp->cn_flags & REQUIREDIR) {
    455 			error = ENOENT;
    456 			goto bad;
    457 		}
    458 		/*
    459 		 * If creating and at end of pathname, then can consider
    460 		 * allowing file to be created.
    461 		 */
    462 		if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
    463 			error = EROFS;
    464 			goto bad;
    465 		}
    466 		/*
    467 		 * We return with ni_vp NULL to indicate that the entry
    468 		 * doesn't currently exist, leaving a pointer to the
    469 		 * (possibly locked) directory inode in ndp->ni_dvp.
    470 		 */
    471 		if (cnp->cn_flags & SAVESTART) {
    472 			ndp->ni_startdir = ndp->ni_dvp;
    473 			VREF(ndp->ni_startdir);
    474 		}
    475 		return (0);
    476 	}
    477 #ifdef NAMEI_DIAGNOSTIC
    478 	printf("found\n");
    479 #endif
    480 
    481 	/*
    482 	 * Take into account any additional components consumed by the
    483 	 * underlying filesystem.  This will include any trailing slashes after
    484 	 * the last component consumed.
    485 	 */
    486 	if (cnp->cn_consume > 0) {
    487 		ndp->ni_pathlen -= cnp->cn_consume - slashes;
    488 		ndp->ni_next += cnp->cn_consume - slashes;
    489 		cnp->cn_consume = 0;
    490 		if (ndp->ni_next[0] == '\0')
    491 			cnp->cn_flags |= ISLASTCN;
    492 	}
    493 
    494 	dp = ndp->ni_vp;
    495 	/*
    496 	 * Check to see if the vnode has been mounted on;
    497 	 * if so find the root of the mounted file system.
    498 	 */
    499 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
    500 	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
    501 		if (mp->mnt_flag & MNT_MLOCK) {
    502 			mp->mnt_flag |= MNT_MWAIT;
    503 			sleep((caddr_t)mp, PVFS);
    504 			continue;
    505 		}
    506 		if ((error = VFS_ROOT(dp->v_mountedhere, &tdp)) != 0)
    507 			goto bad2;
    508 		vput(dp);
    509 		ndp->ni_vp = dp = tdp;
    510 	}
    511 
    512 	/*
    513 	 * Check for symbolic link.  Back up over any slashes that we skipped,
    514 	 * as we will need them again.
    515 	 */
    516 	if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
    517 		ndp->ni_pathlen += slashes;
    518 		ndp->ni_next -= slashes;
    519 		cnp->cn_flags |= ISSYMLINK;
    520 		return (0);
    521 	}
    522 
    523 	/*
    524 	 * Check for directory, if the component was followed by a series of
    525 	 * slashes.
    526 	 */
    527 	if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
    528 		error = ENOTDIR;
    529 		goto bad2;
    530 	}
    531 
    532 nextname:
    533 	/*
    534 	 * Not a symbolic link.  If this was not the last component, then
    535 	 * continue at the next component, else return.
    536 	 */
    537 	if (!(cnp->cn_flags & ISLASTCN)) {
    538 		cnp->cn_nameptr = ndp->ni_next;
    539 		vrele(ndp->ni_dvp);
    540 		goto dirloop;
    541 	}
    542 
    543 terminal:
    544 	/*
    545 	 * Check for read-only file systems.
    546 	 */
    547 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
    548 		/*
    549 		 * Disallow directory write attempts on read-only
    550 		 * file systems.
    551 		 */
    552 		if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
    553 		    (wantparent &&
    554 		     (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
    555 			error = EROFS;
    556 			goto bad2;
    557 		}
    558 	}
    559 	if (ndp->ni_dvp != NULL) {
    560 		if (cnp->cn_flags & SAVESTART) {
    561 			ndp->ni_startdir = ndp->ni_dvp;
    562 			VREF(ndp->ni_startdir);
    563 		}
    564 		if (!wantparent)
    565 			vrele(ndp->ni_dvp);
    566 	}
    567 	if ((cnp->cn_flags & LOCKLEAF) == 0)
    568 		VOP_UNLOCK(dp);
    569 	return (0);
    570 
    571 bad2:
    572 	if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
    573 		VOP_UNLOCK(ndp->ni_dvp);
    574 	vrele(ndp->ni_dvp);
    575 bad:
    576 	vput(dp);
    577 	ndp->ni_vp = NULL;
    578 	return (error);
    579 }
    580 
    581 /*
    582  * Reacquire a path name component.
    583  */
    584 int
    585 relookup(dvp, vpp, cnp)
    586 	struct vnode *dvp, **vpp;
    587 	struct componentname *cnp;
    588 {
    589 	register struct vnode *dp = 0;	/* the directory we are searching */
    590 	int docache;			/* == 0 do not cache last component */
    591 	int wantparent;			/* 1 => wantparent or lockparent flag */
    592 	int rdonly;			/* lookup read-only flag bit */
    593 	int error = 0;
    594 #ifdef NAMEI_DIAGNOSTIC
    595 	int newhash;			/* DEBUG: check name hash */
    596 	char *cp;			/* DEBUG: check name ptr/len */
    597 #endif
    598 
    599 	/*
    600 	 * Setup: break out flag bits into variables.
    601 	 */
    602 	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
    603 	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
    604 	if (cnp->cn_nameiop == DELETE ||
    605 	    (wantparent && cnp->cn_nameiop != CREATE))
    606 		docache = 0;
    607 	rdonly = cnp->cn_flags & RDONLY;
    608 	cnp->cn_flags &= ~ISSYMLINK;
    609 	dp = dvp;
    610 	VOP_LOCK(dp);
    611 
    612 /* dirloop: */
    613 	/*
    614 	 * Search a new directory.
    615 	 *
    616 	 * The cn_hash value is for use by vfs_cache.
    617 	 * The last component of the filename is left accessible via
    618 	 * cnp->cn_nameptr for callers that need the name. Callers needing
    619 	 * the name set the SAVENAME flag. When done, they assume
    620 	 * responsibility for freeing the pathname buffer.
    621 	 */
    622 #ifdef NAMEI_DIAGNOSTIC
    623 	for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
    624 		newhash += (unsigned char)*cp;
    625 	if (newhash != cnp->cn_hash)
    626 		panic("relookup: bad hash");
    627 	if (cnp->cn_namelen != cp - cnp->cn_nameptr)
    628 		panic ("relookup: bad len");
    629 	if (*cp != 0)
    630 		panic("relookup: not last component");
    631 	printf("{%s}: ", cnp->cn_nameptr);
    632 #endif
    633 
    634 	/*
    635 	 * Check for degenerate name (e.g. / or "")
    636 	 * which is a way of talking about a directory,
    637 	 * e.g. like "/." or ".".
    638 	 */
    639 	if (cnp->cn_nameptr[0] == '\0')
    640 		panic("relookup: null name");
    641 
    642 	if (cnp->cn_flags & ISDOTDOT)
    643 		panic ("relookup: lookup on dot-dot");
    644 
    645 	/*
    646 	 * We now have a segment name to search for, and a directory to search.
    647 	 */
    648 	if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
    649 #ifdef DIAGNOSTIC
    650 		if (*vpp != NULL)
    651 			panic("leaf should be empty");
    652 #endif
    653 		if (error != EJUSTRETURN)
    654 			goto bad;
    655 		/*
    656 		 * If creating and at end of pathname, then can consider
    657 		 * allowing file to be created.
    658 		 */
    659 		if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
    660 			error = EROFS;
    661 			goto bad;
    662 		}
    663 		/* ASSERT(dvp == ndp->ni_startdir) */
    664 		if (cnp->cn_flags & SAVESTART)
    665 			VREF(dvp);
    666 		/*
    667 		 * We return with ni_vp NULL to indicate that the entry
    668 		 * doesn't currently exist, leaving a pointer to the
    669 		 * (possibly locked) directory inode in ndp->ni_dvp.
    670 		 */
    671 		return (0);
    672 	}
    673 	dp = *vpp;
    674 
    675 #ifdef DIAGNOSTIC
    676 	/*
    677 	 * Check for symbolic link
    678 	 */
    679 	if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
    680 		panic ("relookup: symlink found.\n");
    681 #endif
    682 
    683 	/*
    684 	 * Check for read-only file systems.
    685 	 */
    686 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
    687 		/*
    688 		 * Disallow directory write attempts on read-only
    689 		 * file systems.
    690 		 */
    691 		if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
    692 		    (wantparent &&
    693 		     (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
    694 			error = EROFS;
    695 			goto bad2;
    696 		}
    697 	}
    698 	/* ASSERT(dvp == ndp->ni_startdir) */
    699 	if (cnp->cn_flags & SAVESTART)
    700 		VREF(dvp);
    701 	if (!wantparent)
    702 		vrele(dvp);
    703 	if ((cnp->cn_flags & LOCKLEAF) == 0)
    704 		VOP_UNLOCK(dp);
    705 	return (0);
    706 
    707 bad2:
    708 	if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
    709 		VOP_UNLOCK(dvp);
    710 	vrele(dvp);
    711 bad:
    712 	vput(dp);
    713 	*vpp = NULL;
    714 	return (error);
    715 }
    716