vfs_lookup.c revision 42408
1139825Simp/*
2139740Sphk * Copyright (c) 1982, 1986, 1989, 1993
350974Swpaul *	The Regents of the University of California.  All rights reserved.
450974Swpaul * (c) UNIX System Laboratories, Inc.
550974Swpaul * All or some portions of this file are derived from material licensed
650974Swpaul * to the University of California by American Telephone and Telegraph
750974Swpaul * Co. or Unix System Laboratories, Inc. and are reproduced herein with
850974Swpaul * the permission of UNIX System Laboratories, Inc.
950974Swpaul *
1050974Swpaul * Redistribution and use in source and binary forms, with or without
1150974Swpaul * modification, are permitted provided that the following conditions
1250974Swpaul * are met:
1350974Swpaul * 1. Redistributions of source code must retain the above copyright
1450974Swpaul *    notice, this list of conditions and the following disclaimer.
1550974Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1650974Swpaul *    notice, this list of conditions and the following disclaimer in the
1750974Swpaul *    documentation and/or other materials provided with the distribution.
1850974Swpaul * 3. All advertising materials mentioning features or use of this software
1950974Swpaul *    must display the following acknowledgement:
2050974Swpaul *	This product includes software developed by the University of
2150974Swpaul *	California, Berkeley and its contributors.
2250974Swpaul * 4. Neither the name of the University nor the names of its contributors
2350974Swpaul *    may be used to endorse or promote products derived from this software
2450974Swpaul *    without specific prior written permission.
2550974Swpaul *
2650974Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2750974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2850974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2950974Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3050974Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3150974Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3250974Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3350974Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34122678Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35122678Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36122678Sobrien * SUCH DAMAGE.
3750974Swpaul *
3850974Swpaul *	@(#)vfs_lookup.c	8.4 (Berkeley) 2/16/94
3950974Swpaul * $Id: vfs_lookup.c,v 1.29 1999/01/05 18:49:52 eivind Exp $
4050974Swpaul */
4164963Swpaul
4264963Swpaul#include "opt_ktrace.h"
4364963Swpaul
4450974Swpaul#include <sys/param.h>
4550974Swpaul#include <sys/systm.h>
4650974Swpaul#include <sys/namei.h>
4750974Swpaul#include <sys/vnode.h>
4850974Swpaul#include <sys/mount.h>
4950974Swpaul#include <sys/filedesc.h>
5050974Swpaul#include <sys/proc.h>
5150974Swpaul
5250974Swpaul#ifdef KTRACE
5350974Swpaul#include <sys/ktrace.h>
5450974Swpaul#endif
5550974Swpaul
5650974Swpaul#include <vm/vm_zone.h>
5750974Swpaul
5850974Swpaul/*
5950974Swpaul * Convert a pathname into a pointer to a locked inode.
6050974Swpaul *
6150974Swpaul * The FOLLOW flag is set when symbolic links are to be followed
6250974Swpaul * when they occur at the end of the name translation process.
6350974Swpaul * Symbolic links are always followed for all other pathname
6450974Swpaul * components other than the last.
6550974Swpaul *
6650974Swpaul * The segflg defines whether the name is to be copied from user
67129876Sphk * space or kernel space.
6850974Swpaul *
6987059Sluigi * Overall outline of namei:
7050974Swpaul *
7150974Swpaul *	copy in name
7250974Swpaul *	get starting directory
7350974Swpaul *	while (!done && !error) {
7450974Swpaul *		call lookup to search path.
7550974Swpaul *		if symbolic link, massage name in buffer and continue
7687390Sjhay *	}
7787390Sjhay */
7850974Swpaulint
7950974Swpaulnamei(ndp)
8050974Swpaul	register struct nameidata *ndp;
8150974Swpaul{
8250974Swpaul	register struct filedesc *fdp;	/* pointer to file descriptor state */
8350974Swpaul	register char *cp;		/* pointer into pathname argument */
8450974Swpaul	register struct vnode *dp;	/* the directory we are searching */
8550974Swpaul	struct iovec aiov;		/* uio for reading symbolic links */
8650974Swpaul	struct uio auio;
8750974Swpaul	int error, linklen;
8850974Swpaul	struct componentname *cnp = &ndp->ni_cnd;
89119288Simp	struct proc *p = cnp->cn_proc;
90119288Simp
9150974Swpaul	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
9250974Swpaul	KASSERT(cnp->cn_cred && cnp->cn_proc, ("namei: bad cred/proc"));
9350974Swpaul	KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0,
9450974Swpaul		("namei: nameiop contaminated with flags"));
9550974Swpaul	KASSERT((cnp->cn_flags & OPMASK) == 0,
96113506Smdodd		("namei: flags contaminated with nameiops"));
97113506Smdodd	fdp = cnp->cn_proc->p_fd;
9859758Speter
9959758Speter	/*
10051089Speter	 * Get a buffer for the name to be translated, and copy the
10150974Swpaul	 * name into the buffer.
10250974Swpaul	 */
10350974Swpaul	if ((cnp->cn_flags & HASBUF) == 0)
10450974Swpaul		cnp->cn_pnbuf = zalloc(namei_zone);
10550974Swpaul	if (ndp->ni_segflg == UIO_SYSSPACE)
10650974Swpaul		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
10750974Swpaul			    MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
10850974Swpaul	else
109119712Sphk		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
11050974Swpaul			    MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
11150974Swpaul
11250974Swpaul	/*
113139801Sphk	 * Don't allow empty pathnames.
114139801Sphk	 */
115139801Sphk	if (!error && *cnp->cn_pnbuf == '\0')
116139801Sphk		error = ENOENT;
117139801Sphk
118139801Sphk	if (error) {
119139801Sphk		zfree(namei_zone, cnp->cn_pnbuf);
120139801Sphk		ndp->ni_vp = NULL;
121139801Sphk		return (error);
122139801Sphk	}
123139801Sphk	ndp->ni_loopcnt = 0;
124139801Sphk#ifdef KTRACE
12550974Swpaul	if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
12650974Swpaul		ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
12750974Swpaul#endif
12850974Swpaul
12950974Swpaul	/*
13051030Swpaul	 * Get starting point for the translation.
13151030Swpaul	 */
13250974Swpaul	ndp->ni_rootdir = fdp->fd_rdir;
13350974Swpaul
13450974Swpaul	dp = fdp->fd_cdir;
13550974Swpaul	VREF(dp);
13650974Swpaul	for (;;) {
13750974Swpaul		/*
13850974Swpaul		 * Check if root directory should replace current directory.
13950974Swpaul		 * Done at start of translation and after symbolic link.
14050974Swpaul		 */
14150974Swpaul		cnp->cn_nameptr = cnp->cn_pnbuf;
14250974Swpaul		if (*(cnp->cn_nameptr) == '/') {
14350974Swpaul			vrele(dp);
14450974Swpaul			while (*(cnp->cn_nameptr) == '/') {
14550974Swpaul				cnp->cn_nameptr++;
14650974Swpaul				ndp->ni_pathlen--;
14750974Swpaul			}
14881713Swpaul			dp = ndp->ni_rootdir;
149139740Sphk			VREF(dp);
15081713Swpaul		}
15181713Swpaul		ndp->ni_startdir = dp;
15281713Swpaul		error = lookup(ndp);
15381713Swpaul		if (error) {
15481713Swpaul			zfree(namei_zone, cnp->cn_pnbuf);
15581713Swpaul			return (error);
15681713Swpaul		}
15781713Swpaul		/*
158139740Sphk		 * Check for symbolic link
15981713Swpaul		 */
16081713Swpaul		if ((cnp->cn_flags & ISSYMLINK) == 0) {
16181713Swpaul			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
16281713Swpaul				zfree(namei_zone, cnp->cn_pnbuf);
16381713Swpaul			else
16481713Swpaul				cnp->cn_flags |= HASBUF;
16581713Swpaul
16681713Swpaul			if (ndp->ni_vp && ndp->ni_vp->v_type == VREG &&
167139740Sphk				(cnp->cn_nameiop != DELETE) &&
16881713Swpaul				((cnp->cn_flags & (NOOBJ|LOCKLEAF)) ==
16981713Swpaul				 LOCKLEAF))
17081713Swpaul				vfs_object_create(ndp->ni_vp,
17181713Swpaul					ndp->ni_cnd.cn_proc,
17281713Swpaul					ndp->ni_cnd.cn_cred);
17381713Swpaul
17481713Swpaul			return (0);
17562672Swpaul		}
17662672Swpaul		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
17762672Swpaul			VOP_UNLOCK(ndp->ni_dvp, 0, p);
17862672Swpaul		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
179139740Sphk			error = ELOOP;
180139740Sphk			break;
18162672Swpaul		}
18262672Swpaul		if (ndp->ni_pathlen > 1)
18362672Swpaul			cp = zalloc(namei_zone);
18462672Swpaul		else
18562672Swpaul			cp = cnp->cn_pnbuf;
18662672Swpaul		aiov.iov_base = cp;
18762672Swpaul		aiov.iov_len = MAXPATHLEN;
18862672Swpaul		auio.uio_iov = &aiov;
18962672Swpaul		auio.uio_iovcnt = 1;
190102334Salfred		auio.uio_offset = 0;
191139740Sphk		auio.uio_rw = UIO_READ;
19250974Swpaul		auio.uio_segflg = UIO_SYSSPACE;
19350974Swpaul		auio.uio_procp = (struct proc *)0;
19450974Swpaul		auio.uio_resid = MAXPATHLEN;
19550974Swpaul		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
19650974Swpaul		if (error) {
19750974Swpaul			if (ndp->ni_pathlen > 1)
19850974Swpaul				zfree(namei_zone, cp);
199102334Salfred			break;
200139740Sphk		}
20150974Swpaul		linklen = MAXPATHLEN - auio.uio_resid;
202139708Sphk		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
20350974Swpaul			if (ndp->ni_pathlen > 1)
20450974Swpaul				zfree(namei_zone, cp);
20550974Swpaul			error = ENAMETOOLONG;
20650974Swpaul			break;
20750974Swpaul		}
20850974Swpaul		if (ndp->ni_pathlen > 1) {
20950974Swpaul			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
21050974Swpaul			zfree(namei_zone, cnp->cn_pnbuf);
21150974Swpaul			cnp->cn_pnbuf = cp;
21250974Swpaul		} else
21350974Swpaul			cnp->cn_pnbuf[linklen] = '\0';
21450974Swpaul		ndp->ni_pathlen += linklen;
21550974Swpaul		vput(ndp->ni_vp);
21650974Swpaul		dp = ndp->ni_dvp;
21750974Swpaul	}
21850974Swpaul	zfree(namei_zone, cnp->cn_pnbuf);
21950974Swpaul	vrele(ndp->ni_dvp);
22050974Swpaul	vput(ndp->ni_vp);
22150974Swpaul	ndp->ni_vp = NULL;
22250974Swpaul	return (error);
22350974Swpaul}
22450974Swpaul
22550974Swpaul/*
226102334Salfred * Search a pathname.
227139740Sphk * This is a very central and rather complicated routine.
22850974Swpaul *
229139708Sphk * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
23050974Swpaul * The starting directory is taken from ni_startdir. The pathname is
23150974Swpaul * descended until done, or a symbolic link is encountered. The variable
23250974Swpaul * ni_more is clear if the path is completed; it is set to one if a
23350974Swpaul * symbolic link needing interpretation is encountered.
23450974Swpaul *
23550974Swpaul * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
23650974Swpaul * whether the name is to be looked up, created, renamed, or deleted.
23750974Swpaul * When CREATE, RENAME, or DELETE is specified, information usable in
23850974Swpaul * creating, renaming, or deleting a directory entry may be calculated.
23950974Swpaul * If flag has LOCKPARENT or'ed into it, the parent directory is returned
24050974Swpaul * locked. If flag has WANTPARENT or'ed into it, the parent directory is
24150974Swpaul * returned unlocked. Otherwise the parent directory is not returned. If
24250974Swpaul * the target of the pathname exists and LOCKLEAF is or'ed into the flag
24350974Swpaul * the target is returned locked, otherwise it is returned unlocked.
24450974Swpaul * When creating or renaming and LOCKPARENT is specified, the target may not
24550974Swpaul * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
24650974Swpaul *
24750974Swpaul * Overall outline of lookup:
24850974Swpaul *
24950974Swpaul * dirloop:
25050974Swpaul *	identify next component of name at ndp->ni_ptr
25150974Swpaul *	handle degenerate case where name is null string
25250974Swpaul *	if .. and crossing mount points and on mounted filesys, find parent
253102334Salfred *	call VOP_LOOKUP routine for next component name
254139740Sphk *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
25550974Swpaul *	    component vnode returned in ni_vp (if it exists), locked.
256139708Sphk *	if result vnode is mounted on and crossing mount points,
25750974Swpaul *	    find mounted on vnode
25850974Swpaul *	if more components of name, do next level at dirloop
25950974Swpaul *	return the answer in ni_vp, locked if LOCKLEAF set
26050974Swpaul *	    if LOCKPARENT set, return locked parent in ni_dvp
26150974Swpaul *	    if WANTPARENT set, return unlocked parent in ni_dvp
26250974Swpaul */
26350974Swpaulint
26462672Swpaullookup(ndp)
26562672Swpaul	register struct nameidata *ndp;
26650974Swpaul{
26750974Swpaul	register char *cp;		/* pointer into pathname argument */
26850974Swpaul	register struct vnode *dp = 0;	/* the directory we are searching */
26950974Swpaul	struct vnode *tdp;		/* saved dp */
27050974Swpaul	struct mount *mp;		/* mount table entry */
27150974Swpaul	int docache;			/* == 0 do not cache last component */
27250974Swpaul	int wantparent;			/* 1 => wantparent or lockparent flag */
27350974Swpaul	int rdonly;			/* lookup read-only flag bit */
27450974Swpaul	int trailing_slash;
27550974Swpaul	int error = 0;
27650974Swpaul	struct componentname *cnp = &ndp->ni_cnd;
27750974Swpaul	struct proc *p = cnp->cn_proc;
27850974Swpaul
27950974Swpaul	/*
28050974Swpaul	 * Setup: break out flag bits into variables.
28150974Swpaul	 */
28250974Swpaul	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
28350974Swpaul	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
28450974Swpaul	if (cnp->cn_nameiop == DELETE ||
28550974Swpaul	    (wantparent && cnp->cn_nameiop != CREATE &&
28650974Swpaul	     cnp->cn_nameiop != LOOKUP))
28750974Swpaul		docache = 0;
28850974Swpaul	rdonly = cnp->cn_flags & RDONLY;
28950974Swpaul	ndp->ni_dvp = NULL;
29050974Swpaul	cnp->cn_flags &= ~ISSYMLINK;
29150974Swpaul	dp = ndp->ni_startdir;
29250974Swpaul	ndp->ni_startdir = NULLVP;
29350974Swpaul	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
29450974Swpaul
29550974Swpauldirloop:
296102334Salfred	/*
297139740Sphk	 * Search a new directory.
29850974Swpaul	 *
29950974Swpaul	 * The cn_hash value is for use by vfs_cache.
30050974Swpaul	 * The last component of the filename is left accessible via
30150974Swpaul	 * cnp->cn_nameptr for callers that need the name. Callers needing
30250974Swpaul	 * the name set the SAVENAME flag. When done, they assume
30350974Swpaul	 * responsibility for freeing the pathname buffer.
30450974Swpaul	 */
30550974Swpaul	cnp->cn_consume = 0;
30650974Swpaul	cnp->cn_hash = 0;
30750974Swpaul	for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
30850974Swpaul		cnp->cn_hash += (unsigned char)*cp;
30950974Swpaul	cnp->cn_namelen = cp - cnp->cn_nameptr;
31050974Swpaul	if (cnp->cn_namelen > NAME_MAX) {
31150974Swpaul		error = ENAMETOOLONG;
312144243Sobrien		goto bad;
313102334Salfred	}
314139740Sphk#ifdef NAMEI_DIAGNOSTIC
31572197Swpaul	{ char c = *cp;
31672197Swpaul	*cp = '\0';
31772197Swpaul	printf("{%s}: ", cnp->cn_nameptr);
31872197Swpaul	*cp = c; }
31972197Swpaul#endif
32072197Swpaul	ndp->ni_pathlen -= cnp->cn_namelen;
32172197Swpaul	ndp->ni_next = cp;
32287994Sarchie
32372197Swpaul	/*
32472197Swpaul	 * Replace multiple slashes by a single slash and trailing slashes
32572197Swpaul	 * by a null.  This must be done before VOP_LOOKUP() because some
32672197Swpaul	 * fs's don't know about trailing slashes.  Remember if there were
32772197Swpaul	 * trailing slashes to handle symlinks, existing non-directories
32872197Swpaul	 * and non-existing files that won't be directories specially later.
32972197Swpaul	 */
33072197Swpaul	trailing_slash = 0;
33172197Swpaul	while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
33272197Swpaul		cp++;
33372197Swpaul		ndp->ni_pathlen--;
33472197Swpaul		if (*cp == '\0') {
33572197Swpaul			trailing_slash = 1;
33672197Swpaul			*ndp->ni_next = '\0';	/* XXX for direnter() ... */
33787994Sarchie		}
33887994Sarchie	}
33972197Swpaul	ndp->ni_next = cp;
34072197Swpaul
34172197Swpaul	cnp->cn_flags |= MAKEENTRY;
34272197Swpaul	if (*cp == '\0' && docache == 0)
34387994Sarchie		cnp->cn_flags &= ~MAKEENTRY;
34472197Swpaul	if (cnp->cn_namelen == 2 &&
34572197Swpaul	    cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
34687994Sarchie		cnp->cn_flags |= ISDOTDOT;
34772197Swpaul	else
34872197Swpaul		cnp->cn_flags &= ~ISDOTDOT;
349102334Salfred	if (*ndp->ni_next == 0)
350139740Sphk		cnp->cn_flags |= ISLASTCN;
35172197Swpaul	else
35272197Swpaul		cnp->cn_flags &= ~ISLASTCN;
35372197Swpaul
35472197Swpaul
35572197Swpaul	/*
35672197Swpaul	 * Check for degenerate name (e.g. / or "")
35772197Swpaul	 * which is a way of talking about a directory,
35872197Swpaul	 * e.g. like "/." or ".".
35972197Swpaul	 */
36072197Swpaul	if (cnp->cn_nameptr[0] == '\0') {
36172197Swpaul		if (dp->v_type != VDIR) {
36272197Swpaul			error = ENOTDIR;
36372197Swpaul			goto bad;
364144243Sobrien		}
36572197Swpaul		if (cnp->cn_nameiop != LOOKUP) {
366144243Sobrien			error = EISDIR;
367144243Sobrien			goto bad;
368144243Sobrien		}
36972197Swpaul		if (wantparent) {
37072197Swpaul			ndp->ni_dvp = dp;
37172197Swpaul			VREF(dp);
37272197Swpaul		}
37372197Swpaul		ndp->ni_vp = dp;
37472197Swpaul		if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
37572197Swpaul			VOP_UNLOCK(dp, 0, p);
37672197Swpaul		if (cnp->cn_flags & SAVESTART)
37772197Swpaul			panic("lookup: SAVESTART");
37889296Swpaul		return (0);
379102334Salfred	}
380139740Sphk
38189296Swpaul	/*
38289296Swpaul	 * Handle "..": two special cases.
38389296Swpaul	 * 1. If at root directory (e.g. after chroot)
38489296Swpaul	 *    or at absolute root directory
38589296Swpaul	 *    then ignore it so can't get out.
38689296Swpaul	 * 2. If this vnode is the root of a mounted
38789296Swpaul	 *    filesystem, then replace it with the
38889296Swpaul	 *    vnode which was mounted on so we take the
38989296Swpaul	 *    .. in the other file system.
39089296Swpaul	 */
39189296Swpaul	if (cnp->cn_flags & ISDOTDOT) {
39289296Swpaul		for (;;) {
39389296Swpaul			if (dp == ndp->ni_rootdir || dp == rootvnode) {
39489296Swpaul				ndp->ni_dvp = dp;
39589296Swpaul				ndp->ni_vp = dp;
39689296Swpaul				VREF(dp);
39789296Swpaul				goto nextname;
39889296Swpaul			}
39989296Swpaul			if ((dp->v_flag & VROOT) == 0 ||
40089296Swpaul			    (cnp->cn_flags & NOCROSSMOUNT))
40189296Swpaul				break;
40289296Swpaul			tdp = dp;
40372197Swpaul			dp = dp->v_mount->mnt_vnodecovered;
40472197Swpaul			vput(tdp);
405109060Smbr			VREF(dp);
406109060Smbr			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
407109060Smbr		}
408139740Sphk	}
409139740Sphk
410109060Smbr	/*
411139708Sphk	 * We now have a segment name to search for, and a directory to search.
412109060Smbr	 */
413109060Smbrunionlookup:
414109060Smbr	ndp->ni_dvp = dp;
415109060Smbr	ndp->ni_vp = NULL;
416109060Smbr	ASSERT_VOP_LOCKED(dp, "lookup");
417109060Smbr	if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
418109060Smbr		KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
419109060Smbr#ifdef NAMEI_DIAGNOSTIC
420109060Smbr		printf("not found\n");
421109060Smbr#endif
422109060Smbr		if ((error == ENOENT) &&
423109060Smbr		    (dp->v_flag & VROOT) &&
424109060Smbr		    (dp->v_mount->mnt_flag & MNT_UNION)) {
425109060Smbr			tdp = dp;
426139740Sphk			dp = dp->v_mount->mnt_vnodecovered;
427139740Sphk			vput(tdp);
428109060Smbr			VREF(dp);
429109060Smbr			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
430109060Smbr			goto unionlookup;
431109060Smbr		}
432109060Smbr
433109060Smbr		if (error != EJUSTRETURN)
434109060Smbr			goto bad;
435109060Smbr		/*
436109060Smbr		 * If creating and at end of pathname, then can consider
437109060Smbr		 * allowing file to be created.
438109060Smbr		 */
439109060Smbr		if (rdonly) {
440109060Smbr			error = EROFS;
441109060Smbr			goto bad;
442109060Smbr		}
443109060Smbr		if (*cp == '\0' && trailing_slash &&
444109060Smbr		     !(cnp->cn_flags & WILLBEDIR)) {
445109060Smbr			error = ENOENT;
446109060Smbr			goto bad;
447109060Smbr		}
448109060Smbr		/*
449139740Sphk		 * We return with ni_vp NULL to indicate that the entry
450139740Sphk		 * doesn't currently exist, leaving a pointer to the
451109060Smbr		 * (possibly locked) directory inode in ndp->ni_dvp.
452109060Smbr		 */
453109060Smbr		if (cnp->cn_flags & SAVESTART) {
454109060Smbr			ndp->ni_startdir = ndp->ni_dvp;
455109060Smbr			VREF(ndp->ni_startdir);
456109060Smbr		}
457109060Smbr		return (0);
458109060Smbr	}
459109060Smbr#ifdef NAMEI_DIAGNOSTIC
460109060Smbr	printf("found\n");
461109060Smbr#endif
462109060Smbr
463109060Smbr	ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup");
464109060Smbr
465109060Smbr	/*
466109060Smbr	 * Take into account any additional components consumed by
467109060Smbr	 * the underlying filesystem.
468109060Smbr	 */
469109060Smbr	if (cnp->cn_consume > 0) {
470109060Smbr		cnp->cn_nameptr += cnp->cn_consume;
471109060Smbr		ndp->ni_next += cnp->cn_consume;
472109060Smbr		ndp->ni_pathlen -= cnp->cn_consume;
473109060Smbr		cnp->cn_consume = 0;
474109060Smbr	}
475109060Smbr
476109060Smbr	dp = ndp->ni_vp;
477109060Smbr
478109060Smbr	/*
479109060Smbr	 * Check to see if the vnode has been mounted on;
480109060Smbr	 * if so find the root of the mounted file system.
481109060Smbr	 */
482109060Smbr	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
483109060Smbr	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
484109060Smbr		if (vfs_busy(mp, 0, 0, p))
485109060Smbr			continue;
486109060Smbr		error = VFS_ROOT(mp, &tdp);
487109060Smbr		vfs_unbusy(mp, p);
488109060Smbr		if (error)
489109060Smbr			goto bad2;
490109060Smbr		vput(dp);
491109060Smbr		ndp->ni_vp = dp = tdp;
492109060Smbr	}
493109060Smbr
494109060Smbr	/*
495109060Smbr	 * Check for symbolic link
496109060Smbr	 */
497109060Smbr	if ((dp->v_type == VLNK) &&
498109060Smbr	    ((cnp->cn_flags & FOLLOW) || trailing_slash ||
499109060Smbr	     *ndp->ni_next == '/')) {
500109060Smbr		cnp->cn_flags |= ISSYMLINK;
501109060Smbr		if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
502109060Smbr			error = EACCES;
503109060Smbr			goto bad2;
504109060Smbr		}
505109060Smbr		return (0);
506109060Smbr	}
507109060Smbr
508109060Smbr	/*
509109060Smbr	 * Check for bogus trailing slashes.
510109060Smbr	 */
511109060Smbr	if (trailing_slash && dp->v_type != VDIR) {
512109060Smbr		error = ENOTDIR;
513109060Smbr		goto bad2;
514109060Smbr	}
515109060Smbr
516109060Smbrnextname:
517109060Smbr	/*
518109060Smbr	 * Not a symbolic link.  If more pathname,
519109060Smbr	 * continue at next component, else return.
520109060Smbr	 */
521109060Smbr	if (*ndp->ni_next == '/') {
522109060Smbr		cnp->cn_nameptr = ndp->ni_next;
523109060Smbr		while (*cnp->cn_nameptr == '/') {
524109060Smbr			cnp->cn_nameptr++;
525109060Smbr			ndp->ni_pathlen--;
526109060Smbr		}
527109060Smbr		if (ndp->ni_dvp != ndp->ni_vp) {
528109060Smbr		    ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup");
529109060Smbr		}
530109060Smbr		vrele(ndp->ni_dvp);
531109060Smbr		goto dirloop;
532109060Smbr	}
533109060Smbr	/*
534109060Smbr	 * Disallow directory write attempts on read-only file systems.
535109060Smbr	 */
536109060Smbr	if (rdonly &&
537109060Smbr	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
538139740Sphk		error = EROFS;
539139740Sphk		goto bad2;
540109060Smbr	}
541109060Smbr	if (cnp->cn_flags & SAVESTART) {
542109060Smbr		ndp->ni_startdir = ndp->ni_dvp;
543109060Smbr		VREF(ndp->ni_startdir);
544109060Smbr	}
545109060Smbr	if (!wantparent)
546109060Smbr		vrele(ndp->ni_dvp);
547109060Smbr
548109060Smbr	if ((cnp->cn_flags & LOCKLEAF) == 0)
549109060Smbr		VOP_UNLOCK(dp, 0, p);
550109060Smbr	return (0);
551109060Smbr
552109060Smbrbad2:
553109060Smbr	if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
554109060Smbr		VOP_UNLOCK(ndp->ni_dvp, 0, p);
555109060Smbr	vrele(ndp->ni_dvp);
556109060Smbrbad:
557109060Smbr	vput(dp);
558109060Smbr	ndp->ni_vp = NULL;
559109060Smbr	return (error);
560109060Smbr}
561109060Smbr
562109060Smbr/*
563109060Smbr * relookup - lookup a path name component
564109060Smbr *    Used by lookup to re-aquire things.
565109060Smbr */
566109060Smbrint
567109060Smbrrelookup(dvp, vpp, cnp)
568109060Smbr	struct vnode *dvp, **vpp;
569109060Smbr	struct componentname *cnp;
570109060Smbr{
571109060Smbr	struct proc *p = cnp->cn_proc;
572109060Smbr	struct vnode *dp = 0;		/* the directory we are searching */
573109060Smbr	int docache;			/* == 0 do not cache last component */
574109060Smbr	int wantparent;			/* 1 => wantparent or lockparent flag */
575109060Smbr	int rdonly;			/* lookup read-only flag bit */
576109060Smbr	int error = 0;
577109060Smbr#ifdef NAMEI_DIAGNOSTIC
578109060Smbr	int newhash;			/* DEBUG: check name hash */
579109060Smbr	char *cp;			/* DEBUG: check name ptr/len */
580109060Smbr#endif
581109060Smbr
582102334Salfred	/*
583139740Sphk	 * Setup: break out flag bits into variables.
58450974Swpaul	 */
58550974Swpaul	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
586109060Smbr	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
58750974Swpaul	if (cnp->cn_nameiop == DELETE ||
58850974Swpaul	    (wantparent && cnp->cn_nameiop != CREATE))
58950974Swpaul		docache = 0;
59062672Swpaul	rdonly = cnp->cn_flags & RDONLY;
59162672Swpaul	cnp->cn_flags &= ~ISSYMLINK;
59262672Swpaul	dp = dvp;
59362672Swpaul	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
59462672Swpaul
59562672Swpaul/* dirloop: */
59662672Swpaul	/*
59762672Swpaul	 * Search a new directory.
59862672Swpaul	 *
59962672Swpaul	 * The cn_hash value is for use by vfs_cache.
60062672Swpaul	 * The last component of the filename is left accessible via
60162672Swpaul	 * cnp->cn_nameptr for callers that need the name. Callers needing
60262672Swpaul	 * the name set the SAVENAME flag. When done, they assume
60362672Swpaul	 * responsibility for freeing the pathname buffer.
60462672Swpaul	 */
605109060Smbr#ifdef NAMEI_DIAGNOSTIC
60662672Swpaul	for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
60762672Swpaul		newhash += (unsigned char)*cp;
608109976Smbr	if (newhash != cnp->cn_hash)
609109976Smbr		panic("relookup: bad hash");
610109976Smbr	if (cnp->cn_namelen != cp - cnp->cn_nameptr)
611109976Smbr		panic ("relookup: bad len");
612109976Smbr	if (*cp != 0)
61389296Swpaul		panic("relookup: not last component");
614109976Smbr	printf("{%s}: ", cnp->cn_nameptr);
615109976Smbr#endif
61650974Swpaul
617109976Smbr	/*
618109976Smbr	 * Check for degenerate name (e.g. / or "")
61950974Swpaul	 * which is a way of talking about a directory,
620109976Smbr	 * e.g. like "/." or ".".
621109976Smbr	 */
622109976Smbr	if (cnp->cn_nameptr[0] == '\0') {
62350974Swpaul		if (cnp->cn_nameiop != LOOKUP || wantparent) {
624109976Smbr			error = EISDIR;
625109976Smbr			goto bad;
626109976Smbr		}
627109976Smbr		if (dp->v_type != VDIR) {
628109976Smbr			error = ENOTDIR;
629109976Smbr			goto bad;
630109976Smbr		}
631109976Smbr		if (!(cnp->cn_flags & LOCKLEAF))
632109976Smbr			VOP_UNLOCK(dp, 0, p);
633109976Smbr		*vpp = dp;
634109976Smbr		if (cnp->cn_flags & SAVESTART)
635109976Smbr			panic("lookup: SAVESTART");
636109976Smbr		return (0);
637109976Smbr	}
638109976Smbr
639109976Smbr	if (cnp->cn_flags & ISDOTDOT)
640109976Smbr		panic ("relookup: lookup on dot-dot");
641109976Smbr
642109976Smbr	/*
643109976Smbr	 * We now have a segment name to search for, and a directory to search.
644109976Smbr	 */
645109976Smbr	if (error = VOP_LOOKUP(dp, vpp, cnp)) {
646109976Smbr		KASSERT(*vpp == NULL, ("leaf should be empty"));
647109976Smbr		if (error != EJUSTRETURN)
648109976Smbr			goto bad;
649109976Smbr		/*
65050974Swpaul		 * If creating and at end of pathname, then can consider
65150974Swpaul		 * allowing file to be created.
652102334Salfred		 */
653139740Sphk		if (rdonly) {
65450974Swpaul			error = EROFS;
65550974Swpaul			goto bad;
656109060Smbr		}
65750974Swpaul		/* ASSERT(dvp == ndp->ni_startdir) */
65850974Swpaul		if (cnp->cn_flags & SAVESTART)
65950974Swpaul			VREF(dvp);
66062672Swpaul		/*
66162672Swpaul		 * We return with ni_vp NULL to indicate that the entry
66262672Swpaul		 * doesn't currently exist, leaving a pointer to the
66362672Swpaul		 * (possibly locked) directory inode in ndp->ni_dvp.
66462672Swpaul		 */
66562672Swpaul		return (0);
66662672Swpaul	}
667109976Smbr	dp = *vpp;
668109976Smbr
669109976Smbr	/*
670109976Smbr	 * Check for symbolic link
671109976Smbr	 */
672109976Smbr	KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW),
673109976Smbr		("relookup: symlink found.\n"));
674109976Smbr
67550974Swpaul	/*
676109976Smbr	 * Disallow directory write attempts on read-only file systems.
677109976Smbr	 */
67850974Swpaul	if (rdonly &&
679109976Smbr	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
680109976Smbr		error = EROFS;
681109976Smbr		goto bad2;
68250974Swpaul	}
683109976Smbr	/* ASSERT(dvp == ndp->ni_startdir) */
684109976Smbr	if (cnp->cn_flags & SAVESTART)
685109976Smbr		VREF(dvp);
686109976Smbr
68750974Swpaul	if (!wantparent)
688109976Smbr		vrele(dvp);
689109976Smbr
690109976Smbr	if (dp->v_type == VREG &&
691109976Smbr		((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF))
692109976Smbr		vfs_object_create(dp, cnp->cn_proc, cnp->cn_cred);
693109976Smbr
694109976Smbr	if ((cnp->cn_flags & LOCKLEAF) == 0)
695109976Smbr		VOP_UNLOCK(dp, 0, p);
696109976Smbr	return (0);
697109976Smbr
698109976Smbrbad2:
69950974Swpaul	if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
70050974Swpaul		VOP_UNLOCK(dvp, 0, p);
70150974Swpaul	vrele(dvp);
702102334Salfredbad:
703139717Sphk	vput(dp);
70450974Swpaul	*vpp = NULL;
70550974Swpaul	return (error);
70650974Swpaul}
70750974Swpaul