vfs_lookup.c revision 145004
1139804Simp/*-
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 * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes *
341541Srgrimes *	@(#)vfs_lookup.c	8.4 (Berkeley) 2/16/94
351541Srgrimes */
361541Srgrimes
37116182Sobrien#include <sys/cdefs.h>
38116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_lookup.c 145004 2005-04-13 10:57:13Z jeff $");
39116182Sobrien
4013203Swollman#include "opt_ktrace.h"
41101127Srwatson#include "opt_mac.h"
42144613Sjeff#include "opt_vfs.h"
4313203Swollman
441541Srgrimes#include <sys/param.h>
452112Swollman#include <sys/systm.h>
4669664Speter#include <sys/kernel.h>
4776166Smarkm#include <sys/lock.h>
48101127Srwatson#include <sys/mac.h>
4989316Salfred#include <sys/mutex.h>
501541Srgrimes#include <sys/namei.h>
511541Srgrimes#include <sys/vnode.h>
521541Srgrimes#include <sys/mount.h>
531541Srgrimes#include <sys/filedesc.h>
541541Srgrimes#include <sys/proc.h>
55141471Sjhb#include <sys/syscallsubr.h>
56144613Sjeff#include <sys/sysctl.h>
571541Srgrimes#ifdef KTRACE
581541Srgrimes#include <sys/ktrace.h>
591541Srgrimes#endif
601541Srgrimes
6192751Sjeff#include <vm/uma.h>
6232011Sbde
63138345Sphk#define NAMEI_DIAGNOSTIC 1
64138345Sphk#undef NAMEI_DIAGNOSTIC
65138345Sphk
661541Srgrimes/*
6769664Speter * Allocation zone for namei
6869664Speter */
6992751Sjeffuma_zone_t namei_zone;
7069664Speter
7169664Speterstatic void
7269664Speternameiinit(void *dummy __unused)
7369664Speter{
7492654Sjeff	namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL,
7592654Sjeff	    UMA_ALIGN_PTR, 0);
7669664Speter
7769664Speter}
7869664SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL)
7969664Speter
80144613Sjeff#ifdef LOOKUP_SHARED
81144613Sjeffstatic int lookup_shared = 1;
82144613Sjeff#else
83144613Sjeffstatic int lookup_shared = 0;
84144613Sjeff#endif
85144613SjeffSYSCTL_INT(_vfs, OID_AUTO, lookup_shared, CTLFLAG_RW, &lookup_shared, 0,
86144613Sjeff    "Enables/Disables shared locks for path name translation");
87144613Sjeff
8869664Speter/*
891541Srgrimes * Convert a pathname into a pointer to a locked inode.
901541Srgrimes *
911541Srgrimes * The FOLLOW flag is set when symbolic links are to be followed
921541Srgrimes * when they occur at the end of the name translation process.
931541Srgrimes * Symbolic links are always followed for all other pathname
941541Srgrimes * components other than the last.
951541Srgrimes *
961541Srgrimes * The segflg defines whether the name is to be copied from user
971541Srgrimes * space or kernel space.
981541Srgrimes *
991541Srgrimes * Overall outline of namei:
1001541Srgrimes *
1011541Srgrimes *	copy in name
1021541Srgrimes *	get starting directory
1031541Srgrimes *	while (!done && !error) {
1041541Srgrimes *		call lookup to search path.
1051541Srgrimes *		if symbolic link, massage name in buffer and continue
1061541Srgrimes *	}
1071541Srgrimes */
1081541Srgrimesint
1091541Srgrimesnamei(ndp)
1101541Srgrimes	register struct nameidata *ndp;
1111541Srgrimes{
1121541Srgrimes	register struct filedesc *fdp;	/* pointer to file descriptor state */
1131541Srgrimes	register char *cp;		/* pointer into pathname argument */
1141541Srgrimes	register struct vnode *dp;	/* the directory we are searching */
1151541Srgrimes	struct iovec aiov;		/* uio for reading symbolic links */
1161541Srgrimes	struct uio auio;
1171541Srgrimes	int error, linklen;
1181541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
11983366Sjulian	struct thread *td = cnp->cn_thread;
12083366Sjulian	struct proc *p = td->td_proc;
121140714Sjeff	int vfslocked;
1221541Srgrimes
12391419Sjhb	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred;
12483366Sjulian	KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc"));
12542408Seivind	KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0,
12642453Seivind	    ("namei: nameiop contaminated with flags"));
12742408Seivind	KASSERT((cnp->cn_flags & OPMASK) == 0,
12842453Seivind	    ("namei: flags contaminated with nameiops"));
129144613Sjeff	if (!lookup_shared)
130144613Sjeff		cnp->cn_flags &= ~LOCKSHARED;
13183366Sjulian	fdp = p->p_fd;
1321541Srgrimes
1331541Srgrimes	/*
1341541Srgrimes	 * Get a buffer for the name to be translated, and copy the
1351541Srgrimes	 * name into the buffer.
1361541Srgrimes	 */
1371541Srgrimes	if ((cnp->cn_flags & HASBUF) == 0)
138111119Simp		cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
1391541Srgrimes	if (ndp->ni_segflg == UIO_SYSSPACE)
1401541Srgrimes		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
14136735Sdfr			    MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
1421541Srgrimes	else
1431541Srgrimes		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
14436735Sdfr			    MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
14520069Sbde
14620069Sbde	/*
14720069Sbde	 * Don't allow empty pathnames.
14820069Sbde	 */
14920069Sbde	if (!error && *cnp->cn_pnbuf == '\0')
15020069Sbde		error = ENOENT;
15120069Sbde
1521541Srgrimes	if (error) {
15392751Sjeff		uma_zfree(namei_zone, cnp->cn_pnbuf);
154100613Srwatson#ifdef DIAGNOSTIC
155100613Srwatson		cnp->cn_pnbuf = NULL;
156100613Srwatson		cnp->cn_nameptr = NULL;
157100613Srwatson#endif
1581541Srgrimes		ndp->ni_vp = NULL;
1591541Srgrimes		return (error);
1601541Srgrimes	}
1611541Srgrimes	ndp->ni_loopcnt = 0;
1621541Srgrimes#ifdef KTRACE
16397994Sjhb	if (KTRPOINT(td, KTR_NAMEI)) {
16497994Sjhb		KASSERT(cnp->cn_thread == curthread,
16597994Sjhb		    ("namei not using curthread"));
16697994Sjhb		ktrnamei(cnp->cn_pnbuf);
16797994Sjhb	}
1681541Srgrimes#endif
1691541Srgrimes
1701541Srgrimes	/*
1711541Srgrimes	 * Get starting point for the translation.
1721541Srgrimes	 */
17389306Salfred	FILEDESC_LOCK(fdp);
17433360Sdyson	ndp->ni_rootdir = fdp->fd_rdir;
17551649Sphk	ndp->ni_topdir = fdp->fd_jdir;
17633360Sdyson
1771541Srgrimes	dp = fdp->fd_cdir;
178140714Sjeff	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
1791541Srgrimes	VREF(dp);
18089306Salfred	FILEDESC_UNLOCK(fdp);
1811541Srgrimes	for (;;) {
1821541Srgrimes		/*
1831541Srgrimes		 * Check if root directory should replace current directory.
1841541Srgrimes		 * Done at start of translation and after symbolic link.
1851541Srgrimes		 */
1861541Srgrimes		cnp->cn_nameptr = cnp->cn_pnbuf;
1871541Srgrimes		if (*(cnp->cn_nameptr) == '/') {
1881541Srgrimes			vrele(dp);
189140714Sjeff			VFS_UNLOCK_GIANT(vfslocked);
1901541Srgrimes			while (*(cnp->cn_nameptr) == '/') {
1911541Srgrimes				cnp->cn_nameptr++;
1921541Srgrimes				ndp->ni_pathlen--;
1931541Srgrimes			}
1941541Srgrimes			dp = ndp->ni_rootdir;
195140714Sjeff			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
1961541Srgrimes			VREF(dp);
1971541Srgrimes		}
198140714Sjeff		if (vfslocked)
199140714Sjeff			ndp->ni_cnd.cn_flags |= GIANTHELD;
2001541Srgrimes		ndp->ni_startdir = dp;
2013148Sphk		error = lookup(ndp);
2023148Sphk		if (error) {
20392751Sjeff			uma_zfree(namei_zone, cnp->cn_pnbuf);
204100613Srwatson#ifdef DIAGNOSTIC
205100613Srwatson			cnp->cn_pnbuf = NULL;
206100613Srwatson			cnp->cn_nameptr = NULL;
207100613Srwatson#endif
2081541Srgrimes			return (error);
2091541Srgrimes		}
210140714Sjeff		vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
211140714Sjeff		ndp->ni_cnd.cn_flags &= ~GIANTHELD;
2121541Srgrimes		/*
2131541Srgrimes		 * Check for symbolic link
2141541Srgrimes		 */
2151541Srgrimes		if ((cnp->cn_flags & ISSYMLINK) == 0) {
216100613Srwatson			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
21792751Sjeff				uma_zfree(namei_zone, cnp->cn_pnbuf);
218100613Srwatson#ifdef DIAGNOSTIC
219100613Srwatson				cnp->cn_pnbuf = NULL;
220100613Srwatson				cnp->cn_nameptr = NULL;
221100613Srwatson#endif
222100613Srwatson			} else
2231541Srgrimes				cnp->cn_flags |= HASBUF;
22432286Sdyson
225140714Sjeff			if ((cnp->cn_flags & MPSAFE) == 0) {
226140714Sjeff				VFS_UNLOCK_GIANT(vfslocked);
227140714Sjeff			} else if (vfslocked)
228140714Sjeff				ndp->ni_cnd.cn_flags |= GIANTHELD;
2291541Srgrimes			return (0);
2301541Srgrimes		}
2311541Srgrimes		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
2321541Srgrimes			error = ELOOP;
2331541Srgrimes			break;
2341541Srgrimes		}
235101127Srwatson#ifdef MAC
236105479Srwatson		if ((cnp->cn_flags & NOMACCHECK) == 0) {
237105479Srwatson			error = mac_check_vnode_readlink(td->td_ucred,
238105479Srwatson			    ndp->ni_vp);
239105479Srwatson			if (error)
240105479Srwatson				break;
241105479Srwatson		}
242101127Srwatson#endif
2431541Srgrimes		if (ndp->ni_pathlen > 1)
244111119Simp			cp = uma_zalloc(namei_zone, M_WAITOK);
2451541Srgrimes		else
2461541Srgrimes			cp = cnp->cn_pnbuf;
2471541Srgrimes		aiov.iov_base = cp;
2481541Srgrimes		aiov.iov_len = MAXPATHLEN;
2491541Srgrimes		auio.uio_iov = &aiov;
2501541Srgrimes		auio.uio_iovcnt = 1;
2511541Srgrimes		auio.uio_offset = 0;
2521541Srgrimes		auio.uio_rw = UIO_READ;
2531541Srgrimes		auio.uio_segflg = UIO_SYSSPACE;
25483366Sjulian		auio.uio_td = (struct thread *)0;
2551541Srgrimes		auio.uio_resid = MAXPATHLEN;
2563148Sphk		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
2573148Sphk		if (error) {
2581541Srgrimes			if (ndp->ni_pathlen > 1)
25992751Sjeff				uma_zfree(namei_zone, cp);
2601541Srgrimes			break;
2611541Srgrimes		}
2621541Srgrimes		linklen = MAXPATHLEN - auio.uio_resid;
26378692Sdillon		if (linklen == 0) {
26478692Sdillon			if (ndp->ni_pathlen > 1)
26592751Sjeff				uma_zfree(namei_zone, cp);
26678692Sdillon			error = ENOENT;
26778692Sdillon			break;
26878692Sdillon		}
2691541Srgrimes		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
2701541Srgrimes			if (ndp->ni_pathlen > 1)
27192751Sjeff				uma_zfree(namei_zone, cp);
2721541Srgrimes			error = ENAMETOOLONG;
2731541Srgrimes			break;
2741541Srgrimes		}
2751541Srgrimes		if (ndp->ni_pathlen > 1) {
2761541Srgrimes			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
27792751Sjeff			uma_zfree(namei_zone, cnp->cn_pnbuf);
2781541Srgrimes			cnp->cn_pnbuf = cp;
2791541Srgrimes		} else
2801541Srgrimes			cnp->cn_pnbuf[linklen] = '\0';
2811541Srgrimes		ndp->ni_pathlen += linklen;
2821541Srgrimes		vput(ndp->ni_vp);
2831541Srgrimes		dp = ndp->ni_dvp;
2841541Srgrimes	}
28592751Sjeff	uma_zfree(namei_zone, cnp->cn_pnbuf);
286100613Srwatson#ifdef DIAGNOSTIC
287100613Srwatson	cnp->cn_pnbuf = NULL;
288100613Srwatson	cnp->cn_nameptr = NULL;
289100613Srwatson#endif
290144833Sjeff	vput(ndp->ni_vp);
291144833Sjeff	ndp->ni_vp = NULL;
2921541Srgrimes	vrele(ndp->ni_dvp);
293140714Sjeff	VFS_UNLOCK_GIANT(vfslocked);
2941541Srgrimes	return (error);
2951541Srgrimes}
2961541Srgrimes
2971541Srgrimes/*
2981541Srgrimes * Search a pathname.
2991541Srgrimes * This is a very central and rather complicated routine.
3001541Srgrimes *
3011541Srgrimes * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
3021541Srgrimes * The starting directory is taken from ni_startdir. The pathname is
3031541Srgrimes * descended until done, or a symbolic link is encountered. The variable
3041541Srgrimes * ni_more is clear if the path is completed; it is set to one if a
3051541Srgrimes * symbolic link needing interpretation is encountered.
3061541Srgrimes *
3071541Srgrimes * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
3081541Srgrimes * whether the name is to be looked up, created, renamed, or deleted.
3091541Srgrimes * When CREATE, RENAME, or DELETE is specified, information usable in
3101541Srgrimes * creating, renaming, or deleting a directory entry may be calculated.
3111541Srgrimes * If flag has LOCKPARENT or'ed into it, the parent directory is returned
3121541Srgrimes * locked. If flag has WANTPARENT or'ed into it, the parent directory is
3131541Srgrimes * returned unlocked. Otherwise the parent directory is not returned. If
3141541Srgrimes * the target of the pathname exists and LOCKLEAF is or'ed into the flag
3151541Srgrimes * the target is returned locked, otherwise it is returned unlocked.
3161541Srgrimes * When creating or renaming and LOCKPARENT is specified, the target may not
3171541Srgrimes * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
3188876Srgrimes *
3191541Srgrimes * Overall outline of lookup:
3201541Srgrimes *
3211541Srgrimes * dirloop:
3221541Srgrimes *	identify next component of name at ndp->ni_ptr
3231541Srgrimes *	handle degenerate case where name is null string
3241541Srgrimes *	if .. and crossing mount points and on mounted filesys, find parent
3251541Srgrimes *	call VOP_LOOKUP routine for next component name
3261541Srgrimes *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
3271541Srgrimes *	    component vnode returned in ni_vp (if it exists), locked.
3281541Srgrimes *	if result vnode is mounted on and crossing mount points,
3291541Srgrimes *	    find mounted on vnode
3301541Srgrimes *	if more components of name, do next level at dirloop
3311541Srgrimes *	return the answer in ni_vp, locked if LOCKLEAF set
3321541Srgrimes *	    if LOCKPARENT set, return locked parent in ni_dvp
3331541Srgrimes *	    if WANTPARENT set, return unlocked parent in ni_dvp
3341541Srgrimes */
3351541Srgrimesint
3361541Srgrimeslookup(ndp)
3371541Srgrimes	register struct nameidata *ndp;
3381541Srgrimes{
3391541Srgrimes	register char *cp;		/* pointer into pathname argument */
3401541Srgrimes	register struct vnode *dp = 0;	/* the directory we are searching */
3411541Srgrimes	struct vnode *tdp;		/* saved dp */
3421541Srgrimes	struct mount *mp;		/* mount table entry */
3431541Srgrimes	int docache;			/* == 0 do not cache last component */
3441541Srgrimes	int wantparent;			/* 1 => wantparent or lockparent flag */
3451541Srgrimes	int rdonly;			/* lookup read-only flag bit */
3469804Sbde	int trailing_slash;
3471541Srgrimes	int error = 0;
34865805Sbp	int dpunlocked = 0;		/* dp has already been unlocked */
3491541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
35083366Sjulian	struct thread *td = cnp->cn_thread;
351140714Sjeff	int vfslocked;
352140714Sjeff	int tvfslocked;
3531541Srgrimes
3541541Srgrimes	/*
3551541Srgrimes	 * Setup: break out flag bits into variables.
3561541Srgrimes	 */
357140714Sjeff	vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
358140714Sjeff	ndp->ni_cnd.cn_flags &= ~GIANTHELD;
3591541Srgrimes	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
360144229Sjeff	KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
361144229Sjeff	    ("CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT."));
3621541Srgrimes	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
3631541Srgrimes	if (cnp->cn_nameiop == DELETE ||
36422874Sbde	    (wantparent && cnp->cn_nameiop != CREATE &&
36522874Sbde	     cnp->cn_nameiop != LOOKUP))
3661541Srgrimes		docache = 0;
3671541Srgrimes	rdonly = cnp->cn_flags & RDONLY;
368144286Sjeff	cnp->cn_flags &= ~ISSYMLINK;
3691541Srgrimes	ndp->ni_dvp = NULL;
370144286Sjeff	/*
371144286Sjeff	 * We use shared locks until we hit the parent of the last cn then
372144286Sjeff	 * we adjust based on the requesting flags.
373144286Sjeff	 */
374144613Sjeff	if (lookup_shared)
375144613Sjeff		cnp->cn_lkflags = LK_SHARED;
376144613Sjeff	else
377144613Sjeff		cnp->cn_lkflags = LK_EXCLUSIVE;
3781541Srgrimes	dp = ndp->ni_startdir;
3791541Srgrimes	ndp->ni_startdir = NULLVP;
380144286Sjeff	vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td);
3811541Srgrimes
3821541Srgrimesdirloop:
3831541Srgrimes	/*
3841541Srgrimes	 * Search a new directory.
3851541Srgrimes	 *
3861541Srgrimes	 * The last component of the filename is left accessible via
3871541Srgrimes	 * cnp->cn_nameptr for callers that need the name. Callers needing
3881541Srgrimes	 * the name set the SAVENAME flag. When done, they assume
3891541Srgrimes	 * responsibility for freeing the pathname buffer.
3901541Srgrimes	 */
3911541Srgrimes	cnp->cn_consume = 0;
3921541Srgrimes	for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
39351906Sphk		continue;
3941541Srgrimes	cnp->cn_namelen = cp - cnp->cn_nameptr;
3951541Srgrimes	if (cnp->cn_namelen > NAME_MAX) {
3961541Srgrimes		error = ENAMETOOLONG;
3971541Srgrimes		goto bad;
3981541Srgrimes	}
3991541Srgrimes#ifdef NAMEI_DIAGNOSTIC
4001541Srgrimes	{ char c = *cp;
4011541Srgrimes	*cp = '\0';
4021541Srgrimes	printf("{%s}: ", cnp->cn_nameptr);
4031541Srgrimes	*cp = c; }
4041541Srgrimes#endif
4051541Srgrimes	ndp->ni_pathlen -= cnp->cn_namelen;
4061541Srgrimes	ndp->ni_next = cp;
4079804Sbde
4089804Sbde	/*
4099804Sbde	 * Replace multiple slashes by a single slash and trailing slashes
4109804Sbde	 * by a null.  This must be done before VOP_LOOKUP() because some
4119804Sbde	 * fs's don't know about trailing slashes.  Remember if there were
4129804Sbde	 * trailing slashes to handle symlinks, existing non-directories
4139804Sbde	 * and non-existing files that won't be directories specially later.
4149804Sbde	 */
4159804Sbde	trailing_slash = 0;
4169804Sbde	while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
4179804Sbde		cp++;
4189804Sbde		ndp->ni_pathlen--;
4199804Sbde		if (*cp == '\0') {
4209804Sbde			trailing_slash = 1;
4219804Sbde			*ndp->ni_next = '\0';	/* XXX for direnter() ... */
4229804Sbde		}
4239804Sbde	}
4249804Sbde	ndp->ni_next = cp;
4259804Sbde
4261541Srgrimes	cnp->cn_flags |= MAKEENTRY;
4271541Srgrimes	if (*cp == '\0' && docache == 0)
4281541Srgrimes		cnp->cn_flags &= ~MAKEENTRY;
4291541Srgrimes	if (cnp->cn_namelen == 2 &&
4301541Srgrimes	    cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
4311541Srgrimes		cnp->cn_flags |= ISDOTDOT;
4321541Srgrimes	else
4331541Srgrimes		cnp->cn_flags &= ~ISDOTDOT;
4341541Srgrimes	if (*ndp->ni_next == 0)
4351541Srgrimes		cnp->cn_flags |= ISLASTCN;
4361541Srgrimes	else
4371541Srgrimes		cnp->cn_flags &= ~ISLASTCN;
4381541Srgrimes
4391541Srgrimes
4401541Srgrimes	/*
4411541Srgrimes	 * Check for degenerate name (e.g. / or "")
4421541Srgrimes	 * which is a way of talking about a directory,
4431541Srgrimes	 * e.g. like "/." or ".".
4441541Srgrimes	 */
4451541Srgrimes	if (cnp->cn_nameptr[0] == '\0') {
44622521Sdyson		if (dp->v_type != VDIR) {
44722521Sdyson			error = ENOTDIR;
44822521Sdyson			goto bad;
44922521Sdyson		}
4501541Srgrimes		if (cnp->cn_nameiop != LOOKUP) {
4511541Srgrimes			error = EISDIR;
4521541Srgrimes			goto bad;
4531541Srgrimes		}
4541541Srgrimes		if (wantparent) {
4551541Srgrimes			ndp->ni_dvp = dp;
4561541Srgrimes			VREF(dp);
4571541Srgrimes		}
4581541Srgrimes		ndp->ni_vp = dp;
4591541Srgrimes		if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
46083366Sjulian			VOP_UNLOCK(dp, 0, td);
46154655Seivind		/* XXX This should probably move to the top of function. */
4621541Srgrimes		if (cnp->cn_flags & SAVESTART)
4631541Srgrimes			panic("lookup: SAVESTART");
464140714Sjeff		goto success;
4651541Srgrimes	}
4661541Srgrimes
4671541Srgrimes	/*
4681541Srgrimes	 * Handle "..": two special cases.
4691541Srgrimes	 * 1. If at root directory (e.g. after chroot)
4701541Srgrimes	 *    or at absolute root directory
4711541Srgrimes	 *    then ignore it so can't get out.
4721541Srgrimes	 * 2. If this vnode is the root of a mounted
4731541Srgrimes	 *    filesystem, then replace it with the
4741541Srgrimes	 *    vnode which was mounted on so we take the
47596755Strhodes	 *    .. in the other filesystem.
47651649Sphk	 * 3. If the vnode is the top directory of
47751649Sphk	 *    the jail or chroot, don't let them out.
4781541Srgrimes	 */
4791541Srgrimes	if (cnp->cn_flags & ISDOTDOT) {
4801541Srgrimes		for (;;) {
48151649Sphk			if (dp == ndp->ni_rootdir ||
48251649Sphk			    dp == ndp->ni_topdir ||
48351649Sphk			    dp == rootvnode) {
4841541Srgrimes				ndp->ni_dvp = dp;
4851541Srgrimes				ndp->ni_vp = dp;
4861541Srgrimes				VREF(dp);
4871541Srgrimes				goto nextname;
4881541Srgrimes			}
489101308Sjeff			if ((dp->v_vflag & VV_ROOT) == 0 ||
4901541Srgrimes			    (cnp->cn_flags & NOCROSSMOUNT))
4911541Srgrimes				break;
49269405Salfred			if (dp->v_mount == NULL) {	/* forced unmount */
49369405Salfred				error = EBADF;
49469405Salfred				goto bad;
49569405Salfred			}
4961541Srgrimes			tdp = dp;
497144833Sjeff			dp = dp->v_mount->mnt_vnodecovered;
498140714Sjeff			tvfslocked = vfslocked;
499144833Sjeff			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
500144833Sjeff			VREF(dp);
5011541Srgrimes			vput(tdp);
502140714Sjeff			VFS_UNLOCK_GIANT(tvfslocked);
503144286Sjeff			vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td);
5041541Srgrimes		}
5051541Srgrimes	}
5061541Srgrimes
5071541Srgrimes	/*
5081541Srgrimes	 * We now have a segment name to search for, and a directory to search.
5091541Srgrimes	 */
5101541Srgrimesunionlookup:
511101127Srwatson#ifdef MAC
512105479Srwatson	if ((cnp->cn_flags & NOMACCHECK) == 0) {
513105479Srwatson		error = mac_check_vnode_lookup(td->td_ucred, dp, cnp);
514105479Srwatson		if (error)
515105479Srwatson			goto bad;
516105479Srwatson	}
517101127Srwatson#endif
5181541Srgrimes	ndp->ni_dvp = dp;
51922521Sdyson	ndp->ni_vp = NULL;
52024624Sdfr	ASSERT_VOP_LOCKED(dp, "lookup");
521144286Sjeff	/*
522144286Sjeff	 * If we have a shared lock we may need to upgrade the lock for the
523144286Sjeff	 * last operation.
524144286Sjeff	 */
525144286Sjeff	if (VOP_ISLOCKED(dp, td) == LK_SHARED &&
526144286Sjeff	    (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT))
527144286Sjeff		vn_lock(dp, LK_UPGRADE|LK_RETRY, td);
528144286Sjeff	/*
529144286Sjeff	 * If we're looking up the last component and we need an exclusive
530144286Sjeff	 * lock, adjust our lkflags.
531144286Sjeff	 */
532144286Sjeff	if ((cnp->cn_flags & (ISLASTCN|LOCKSHARED|LOCKLEAF)) ==
533144286Sjeff	    (ISLASTCN|LOCKLEAF))
534144286Sjeff		cnp->cn_lkflags = LK_EXCLUSIVE;
535138345Sphk#ifdef NAMEI_DIAGNOSTIC
536138345Sphk	vprint("lookup in", dp);
537138345Sphk#endif
53843301Sdillon	if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
53942408Seivind		KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
5401541Srgrimes#ifdef NAMEI_DIAGNOSTIC
5411541Srgrimes		printf("not found\n");
5421541Srgrimes#endif
5431541Srgrimes		if ((error == ENOENT) &&
544101308Sjeff		    (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) &&
5451541Srgrimes		    (dp->v_mount->mnt_flag & MNT_UNION)) {
5461541Srgrimes			tdp = dp;
547144833Sjeff			dp = dp->v_mount->mnt_vnodecovered;
548140714Sjeff			tvfslocked = vfslocked;
549144833Sjeff			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
550144833Sjeff			VREF(dp);
551144203Sjeff			vput(tdp);
552140714Sjeff			VFS_UNLOCK_GIANT(tvfslocked);
553144286Sjeff			vn_lock(dp, cnp->cn_lkflags | LK_RETRY, td);
5541541Srgrimes			goto unionlookup;
5551541Srgrimes		}
5561541Srgrimes
5571541Srgrimes		if (error != EJUSTRETURN)
5581541Srgrimes			goto bad;
5591541Srgrimes		/*
5601541Srgrimes		 * If creating and at end of pathname, then can consider
5611541Srgrimes		 * allowing file to be created.
5621541Srgrimes		 */
56311644Sdg		if (rdonly) {
5641541Srgrimes			error = EROFS;
5651541Srgrimes			goto bad;
5661541Srgrimes		}
5679804Sbde		if (*cp == '\0' && trailing_slash &&
5689804Sbde		     !(cnp->cn_flags & WILLBEDIR)) {
5699804Sbde			error = ENOENT;
5709804Sbde			goto bad;
5719804Sbde		}
572144203Sjeff		if ((cnp->cn_flags & LOCKPARENT) == 0)
573144203Sjeff			VOP_UNLOCK(dp, 0, td);
5741541Srgrimes		/*
575144203Sjeff		 * This is a temporary assert to make sure I know what the
576144203Sjeff		 * behavior here was.
577144203Sjeff		 */
578144203Sjeff		KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0,
579144203Sjeff		   ("lookup: Unhandled case."));
580144203Sjeff		/*
5811541Srgrimes		 * We return with ni_vp NULL to indicate that the entry
5821541Srgrimes		 * doesn't currently exist, leaving a pointer to the
5831541Srgrimes		 * (possibly locked) directory inode in ndp->ni_dvp.
5841541Srgrimes		 */
5851541Srgrimes		if (cnp->cn_flags & SAVESTART) {
5861541Srgrimes			ndp->ni_startdir = ndp->ni_dvp;
5871541Srgrimes			VREF(ndp->ni_startdir);
5881541Srgrimes		}
589140714Sjeff		goto success;
5901541Srgrimes	}
5911541Srgrimes#ifdef NAMEI_DIAGNOSTIC
5921541Srgrimes	printf("found\n");
5931541Srgrimes#endif
594144203Sjeff	/*
5951541Srgrimes	 * Take into account any additional components consumed by
5961541Srgrimes	 * the underlying filesystem.
5971541Srgrimes	 */
5981541Srgrimes	if (cnp->cn_consume > 0) {
5991541Srgrimes		cnp->cn_nameptr += cnp->cn_consume;
6001541Srgrimes		ndp->ni_next += cnp->cn_consume;
6011541Srgrimes		ndp->ni_pathlen -= cnp->cn_consume;
6021541Srgrimes		cnp->cn_consume = 0;
6031541Srgrimes	}
6041541Srgrimes
6051541Srgrimes	dp = ndp->ni_vp;
6061541Srgrimes
6071541Srgrimes	/*
6081541Srgrimes	 * Check to see if the vnode has been mounted on;
60996755Strhodes	 * if so find the root of the mounted filesystem.
6101541Srgrimes	 */
6111541Srgrimes	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
6121541Srgrimes	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
613144833Sjeff		KASSERT(dp != ndp->ni_dvp, ("XXX"));
61483366Sjulian		if (vfs_busy(mp, 0, 0, td))
6151541Srgrimes			continue;
616144833Sjeff		vput(dp);
617140714Sjeff		tvfslocked = VFS_LOCK_GIANT(mp);
618144833Sjeff		VFS_UNLOCK_GIANT(vfslocked);
619144833Sjeff		vfslocked = tvfslocked;
620144286Sjeff		error = VFS_ROOT(mp, cnp->cn_lkflags, &tdp, td);
62183366Sjulian		vfs_unbusy(mp, td);
62265805Sbp		if (error) {
62365805Sbp			dpunlocked = 1;
6241541Srgrimes			goto bad2;
62565805Sbp		}
6261541Srgrimes		ndp->ni_vp = dp = tdp;
6271541Srgrimes	}
6281541Srgrimes
62910219Sdfr	/*
63010219Sdfr	 * Check for symbolic link
63110219Sdfr	 */
63210219Sdfr	if ((dp->v_type == VLNK) &&
63310219Sdfr	    ((cnp->cn_flags & FOLLOW) || trailing_slash ||
63410219Sdfr	     *ndp->ni_next == '/')) {
63510219Sdfr		cnp->cn_flags |= ISSYMLINK;
63669405Salfred		if (dp->v_mount == NULL) {
63769405Salfred			/* We can't know whether the directory was mounted with
63869405Salfred			 * NOSYMFOLLOW, so we can't follow safely. */
63969405Salfred			error = EBADF;
64069405Salfred			goto bad2;
64169405Salfred		}
64235105Swosch		if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
64335105Swosch			error = EACCES;
64435105Swosch			goto bad2;
64535105Swosch		}
646144833Sjeff		/*
647144833Sjeff		 * Symlink code always expects an unlocked dvp.
648144833Sjeff		 */
649144833Sjeff		if (ndp->ni_dvp != ndp->ni_vp)
650144833Sjeff			VOP_UNLOCK(ndp->ni_dvp, 0, td);
651140714Sjeff		goto success;
65210219Sdfr	}
65310219Sdfr
65410219Sdfr	/*
65510219Sdfr	 * Check for bogus trailing slashes.
65610219Sdfr	 */
65710219Sdfr	if (trailing_slash && dp->v_type != VDIR) {
65810219Sdfr		error = ENOTDIR;
65910219Sdfr		goto bad2;
66010219Sdfr	}
66110219Sdfr
6621541Srgrimesnextname:
6631541Srgrimes	/*
6641541Srgrimes	 * Not a symbolic link.  If more pathname,
6651541Srgrimes	 * continue at next component, else return.
6661541Srgrimes	 */
667144203Sjeff	KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/',
668144203Sjeff	    ("lookup: invalid path state."));
6691541Srgrimes	if (*ndp->ni_next == '/') {
6701541Srgrimes		cnp->cn_nameptr = ndp->ni_next;
6711541Srgrimes		while (*cnp->cn_nameptr == '/') {
6721541Srgrimes			cnp->cn_nameptr++;
6731541Srgrimes			ndp->ni_pathlen--;
6741541Srgrimes		}
675144833Sjeff		if (ndp->ni_dvp != dp)
676144833Sjeff			vput(ndp->ni_dvp);
677144833Sjeff		else
678144833Sjeff			vrele(ndp->ni_dvp);
6791541Srgrimes		goto dirloop;
6801541Srgrimes	}
6811541Srgrimes	/*
68296755Strhodes	 * Disallow directory write attempts on read-only filesystems.
6831541Srgrimes	 */
68411644Sdg	if (rdonly &&
68511644Sdg	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
68611644Sdg		error = EROFS;
68711644Sdg		goto bad2;
6881541Srgrimes	}
6891541Srgrimes	if (cnp->cn_flags & SAVESTART) {
6901541Srgrimes		ndp->ni_startdir = ndp->ni_dvp;
6911541Srgrimes		VREF(ndp->ni_startdir);
6921541Srgrimes	}
693144833Sjeff	if (!wantparent) {
694144833Sjeff		if (ndp->ni_dvp != dp)
695144833Sjeff			vput(ndp->ni_dvp);
696144833Sjeff		else
697144833Sjeff			vrele(ndp->ni_dvp);
698144833Sjeff	} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp)
699144833Sjeff		VOP_UNLOCK(ndp->ni_dvp, 0, td);
70032071Sdyson
7011541Srgrimes	if ((cnp->cn_flags & LOCKLEAF) == 0)
70283366Sjulian		VOP_UNLOCK(dp, 0, td);
703140714Sjeffsuccess:
704140714Sjeff	if (vfslocked)
705140714Sjeff		ndp->ni_cnd.cn_flags |= GIANTHELD;
7061541Srgrimes	return (0);
7071541Srgrimes
7081541Srgrimesbad2:
709144833Sjeff	if (dp != ndp->ni_dvp)
710144203Sjeff		vput(ndp->ni_dvp);
711144203Sjeff	else
712144203Sjeff		vrele(ndp->ni_dvp);
7131541Srgrimesbad:
714144833Sjeff	if (!dpunlocked)
71565805Sbp		vput(dp);
716140714Sjeff	VFS_UNLOCK_GIANT(vfslocked);
717140714Sjeff	ndp->ni_cnd.cn_flags &= ~GIANTHELD;
7181541Srgrimes	ndp->ni_vp = NULL;
7191541Srgrimes	return (error);
7201541Srgrimes}
7211541Srgrimes
7223148Sphk/*
7233148Sphk * relookup - lookup a path name component
7243148Sphk *    Used by lookup to re-aquire things.
7253148Sphk */
7263148Sphkint
7273148Sphkrelookup(dvp, vpp, cnp)
7283148Sphk	struct vnode *dvp, **vpp;
7293148Sphk	struct componentname *cnp;
7303148Sphk{
73183366Sjulian	struct thread *td = cnp->cn_thread;
73222521Sdyson	struct vnode *dp = 0;		/* the directory we are searching */
7333148Sphk	int wantparent;			/* 1 => wantparent or lockparent flag */
7343148Sphk	int rdonly;			/* lookup read-only flag bit */
7353148Sphk	int error = 0;
7361541Srgrimes
737144203Sjeff	KASSERT(cnp->cn_flags & ISLASTCN,
738144203Sjeff	    ("relookup: Not given last component."));
7393148Sphk	/*
7403148Sphk	 * Setup: break out flag bits into variables.
7413148Sphk	 */
7423148Sphk	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
743145004Sjeff	KASSERT(wantparent, ("relookup: parent not wanted."));
7443148Sphk	rdonly = cnp->cn_flags & RDONLY;
7453148Sphk	cnp->cn_flags &= ~ISSYMLINK;
7463148Sphk	dp = dvp;
747144286Sjeff	cnp->cn_lkflags = LK_EXCLUSIVE;
74883366Sjulian	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
7493148Sphk
7503148Sphk	/*
7513148Sphk	 * Search a new directory.
7523148Sphk	 *
7533148Sphk	 * The last component of the filename is left accessible via
7543148Sphk	 * cnp->cn_nameptr for callers that need the name. Callers needing
7553148Sphk	 * the name set the SAVENAME flag. When done, they assume
7563148Sphk	 * responsibility for freeing the pathname buffer.
7573148Sphk	 */
7583148Sphk#ifdef NAMEI_DIAGNOSTIC
7593148Sphk	printf("{%s}: ", cnp->cn_nameptr);
7603148Sphk#endif
7613148Sphk
7623148Sphk	/*
7633148Sphk	 * Check for degenerate name (e.g. / or "")
7643148Sphk	 * which is a way of talking about a directory,
7653148Sphk	 * e.g. like "/." or ".".
7663148Sphk	 */
7673148Sphk	if (cnp->cn_nameptr[0] == '\0') {
7683148Sphk		if (cnp->cn_nameiop != LOOKUP || wantparent) {
7693148Sphk			error = EISDIR;
7703148Sphk			goto bad;
7713148Sphk		}
7723148Sphk		if (dp->v_type != VDIR) {
7733148Sphk			error = ENOTDIR;
7743148Sphk			goto bad;
7753148Sphk		}
7763148Sphk		if (!(cnp->cn_flags & LOCKLEAF))
77783366Sjulian			VOP_UNLOCK(dp, 0, td);
7783148Sphk		*vpp = dp;
77954655Seivind		/* XXX This should probably move to the top of function. */
7803148Sphk		if (cnp->cn_flags & SAVESTART)
7813148Sphk			panic("lookup: SAVESTART");
7823148Sphk		return (0);
7833148Sphk	}
7843148Sphk
7853148Sphk	if (cnp->cn_flags & ISDOTDOT)
7863148Sphk		panic ("relookup: lookup on dot-dot");
7873148Sphk
7883148Sphk	/*
7893148Sphk	 * We now have a segment name to search for, and a directory to search.
7903148Sphk	 */
791138345Sphk#ifdef NAMEI_DIAGNOSTIC
792138345Sphk	vprint("search in:", dp);
793138345Sphk#endif
79443311Sdillon	if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
79542408Seivind		KASSERT(*vpp == NULL, ("leaf should be empty"));
7963148Sphk		if (error != EJUSTRETURN)
7973148Sphk			goto bad;
7983148Sphk		/*
7993148Sphk		 * If creating and at end of pathname, then can consider
8003148Sphk		 * allowing file to be created.
8013148Sphk		 */
80211644Sdg		if (rdonly) {
8033148Sphk			error = EROFS;
8043148Sphk			goto bad;
8053148Sphk		}
8063148Sphk		/* ASSERT(dvp == ndp->ni_startdir) */
8073148Sphk		if (cnp->cn_flags & SAVESTART)
8083148Sphk			VREF(dvp);
809144203Sjeff		if ((cnp->cn_flags & LOCKPARENT) == 0)
810144203Sjeff			VOP_UNLOCK(dp, 0, td);
8113148Sphk		/*
812144203Sjeff		 * This is a temporary assert to make sure I know what the
813144203Sjeff		 * behavior here was.
814144203Sjeff		 */
815144203Sjeff		KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0,
816144203Sjeff		   ("relookup: Unhandled case."));
817144203Sjeff		/*
8183148Sphk		 * We return with ni_vp NULL to indicate that the entry
8193148Sphk		 * doesn't currently exist, leaving a pointer to the
8203148Sphk		 * (possibly locked) directory inode in ndp->ni_dvp.
8213148Sphk		 */
8223148Sphk		return (0);
8233148Sphk	}
8243148Sphk	dp = *vpp;
8253148Sphk
8263148Sphk	/*
82796755Strhodes	 * Disallow directory write attempts on read-only filesystems.
8283148Sphk	 */
82911644Sdg	if (rdonly &&
83011644Sdg	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
831145004Sjeff		printf("this is it?\n");
832145004Sjeff		if (dvp == dp)
833145004Sjeff			vrele(dvp);
834145004Sjeff		else
835145004Sjeff			vput(dvp);
83611644Sdg		error = EROFS;
837145004Sjeff		goto bad;
8383148Sphk	}
839145004Sjeff	/*
840145004Sjeff	 * Set the parent lock/ref state to the requested state.
841145004Sjeff	 */
842145004Sjeff	if ((cnp->cn_flags & LOCKPARENT) == 0 && dvp != dp) {
843145004Sjeff		if (wantparent)
844145004Sjeff			VOP_UNLOCK(dvp, 0, td);
845145004Sjeff		else
846145004Sjeff			vput(dvp);
847145004Sjeff	} else if (!wantparent)
848145004Sjeff		vrele(dvp);
849145004Sjeff	/*
850145004Sjeff	 * Check for symbolic link
851145004Sjeff	 */
852145004Sjeff	KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW),
853145004Sjeff	    ("relookup: symlink found.\n"));
854145004Sjeff
8553148Sphk	/* ASSERT(dvp == ndp->ni_startdir) */
8563148Sphk	if (cnp->cn_flags & SAVESTART)
8573148Sphk		VREF(dvp);
85822521Sdyson
8593148Sphk	if ((cnp->cn_flags & LOCKLEAF) == 0)
86083366Sjulian		VOP_UNLOCK(dp, 0, td);
8613148Sphk	return (0);
8623148Sphkbad:
8633148Sphk	vput(dp);
8643148Sphk	*vpp = NULL;
8653148Sphk	return (error);
8663148Sphk}
867141471Sjhb
868141471Sjhb/*
869144661Sjeff * Free data allocated by namei(); see namei(9) for details.
870144661Sjeff */
871144661Sjeffvoid
872144661SjeffNDFREE(ndp, flags)
873144661Sjeff     struct nameidata *ndp;
874144661Sjeff     const u_int flags;
875144661Sjeff{
876144833Sjeff	int unlock_dvp;
877144833Sjeff	int unlock_vp;
878144661Sjeff
879144833Sjeff	unlock_dvp = 0;
880144833Sjeff	unlock_vp = 0;
881144833Sjeff
882144661Sjeff	if (!(flags & NDF_NO_FREE_PNBUF) &&
883144661Sjeff	    (ndp->ni_cnd.cn_flags & HASBUF)) {
884144661Sjeff		uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf);
885144661Sjeff		ndp->ni_cnd.cn_flags &= ~HASBUF;
886144661Sjeff	}
887144833Sjeff	if (!(flags & NDF_NO_VP_UNLOCK) &&
888144833Sjeff	    (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp)
889144833Sjeff		unlock_vp = 1;
890144833Sjeff	if (!(flags & NDF_NO_VP_RELE) && ndp->ni_vp) {
891144833Sjeff		if (unlock_vp) {
892144833Sjeff			vput(ndp->ni_vp);
893144833Sjeff			unlock_vp = 0;
894144833Sjeff		} else
895144833Sjeff			vrele(ndp->ni_vp);
896144833Sjeff		ndp->ni_vp = NULL;
897144833Sjeff	}
898144833Sjeff	if (unlock_vp)
899144833Sjeff		VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_thread);
900144661Sjeff	if (!(flags & NDF_NO_DVP_UNLOCK) &&
901144661Sjeff	    (ndp->ni_cnd.cn_flags & LOCKPARENT) &&
902144661Sjeff	    ndp->ni_dvp != ndp->ni_vp)
903144833Sjeff		unlock_dvp = 1;
904144661Sjeff	if (!(flags & NDF_NO_DVP_RELE) &&
905144661Sjeff	    (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) {
906144833Sjeff		if (unlock_dvp) {
907144833Sjeff			vput(ndp->ni_dvp);
908144833Sjeff			unlock_dvp = 0;
909144833Sjeff		} else
910144833Sjeff			vrele(ndp->ni_dvp);
911144661Sjeff		ndp->ni_dvp = NULL;
912144661Sjeff	}
913144833Sjeff	if (unlock_dvp)
914144833Sjeff		VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_thread);
915144661Sjeff	if (!(flags & NDF_NO_STARTDIR_RELE) &&
916144661Sjeff	    (ndp->ni_cnd.cn_flags & SAVESTART)) {
917144661Sjeff		vrele(ndp->ni_startdir);
918144661Sjeff		ndp->ni_startdir = NULL;
919144661Sjeff	}
920144661Sjeff}
921144661Sjeff
922144661Sjeff/*
923141471Sjhb * Determine if there is a suitable alternate filename under the specified
924141471Sjhb * prefix for the specified path.  If the create flag is set, then the
925141471Sjhb * alternate prefix will be used so long as the parent directory exists.
926141471Sjhb * This is used by the various compatiblity ABIs so that Linux binaries prefer
927141471Sjhb * files under /compat/linux for example.  The chosen path (whether under
928141471Sjhb * the prefix or under /) is returned in a kernel malloc'd buffer pointed
929141471Sjhb * to by pathbuf.  The caller is responsible for free'ing the buffer from
930141471Sjhb * the M_TEMP bucket if one is returned.
931141471Sjhb */
932141471Sjhbint
933141471Sjhbkern_alternate_path(struct thread *td, const char *prefix, char *path,
934141471Sjhb    enum uio_seg pathseg, char **pathbuf, int create)
935141471Sjhb{
936141471Sjhb	struct nameidata nd, ndroot;
937141471Sjhb	char *ptr, *buf, *cp;
938141471Sjhb	size_t len, sz;
939141471Sjhb	int error;
940141471Sjhb
941141471Sjhb	buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
942141471Sjhb	*pathbuf = buf;
943141471Sjhb
944141471Sjhb	/* Copy the prefix into the new pathname as a starting point. */
945141471Sjhb	len = strlcpy(buf, prefix, MAXPATHLEN);
946141471Sjhb	if (len >= MAXPATHLEN) {
947141471Sjhb		*pathbuf = NULL;
948141471Sjhb		free(buf, M_TEMP);
949141471Sjhb		return (EINVAL);
950141471Sjhb	}
951141471Sjhb	sz = MAXPATHLEN - len;
952141471Sjhb	ptr = buf + len;
953141471Sjhb
954141471Sjhb	/* Append the filename to the prefix. */
955141471Sjhb	if (pathseg == UIO_SYSSPACE)
956141471Sjhb		error = copystr(path, ptr, sz, &len);
957141471Sjhb	else
958141471Sjhb		error = copyinstr(path, ptr, sz, &len);
959141471Sjhb
960141471Sjhb	if (error) {
961141471Sjhb		*pathbuf = NULL;
962141471Sjhb		free(buf, M_TEMP);
963141471Sjhb		return (error);
964141471Sjhb	}
965141471Sjhb
966141471Sjhb	/* Only use a prefix with absolute pathnames. */
967141471Sjhb	if (*ptr != '/') {
968141471Sjhb		error = EINVAL;
969141471Sjhb		goto keeporig;
970141471Sjhb	}
971141471Sjhb
972141471Sjhb	/* XXX: VFS_LOCK_GIANT? */
973141471Sjhb	mtx_lock(&Giant);
974141471Sjhb
975141471Sjhb	/*
976141471Sjhb	 * We know that there is a / somewhere in this pathname.
977141471Sjhb	 * Search backwards for it, to find the file's parent dir
978141471Sjhb	 * to see if it exists in the alternate tree. If it does,
979141471Sjhb	 * and we want to create a file (cflag is set). We don't
980141471Sjhb	 * need to worry about the root comparison in this case.
981141471Sjhb	 */
982141471Sjhb
983141471Sjhb	if (create) {
984141471Sjhb		for (cp = &ptr[len] - 1; *cp != '/'; cp--);
985141471Sjhb		*cp = '\0';
986141471Sjhb
987141471Sjhb		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
988141471Sjhb		error = namei(&nd);
989141471Sjhb		*cp = '/';
990141471Sjhb		if (error != 0)
991141471Sjhb			goto nd_failed;
992141471Sjhb	} else {
993141471Sjhb		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
994141471Sjhb
995141471Sjhb		error = namei(&nd);
996141471Sjhb		if (error != 0)
997141471Sjhb			goto nd_failed;
998141471Sjhb
999141471Sjhb		/*
1000141471Sjhb		 * We now compare the vnode of the prefix to the one
1001141471Sjhb		 * vnode asked. If they resolve to be the same, then we
1002141471Sjhb		 * ignore the match so that the real root gets used.
1003141471Sjhb		 * This avoids the problem of traversing "../.." to find the
1004141471Sjhb		 * root directory and never finding it, because "/" resolves
1005141471Sjhb		 * to the emulation root directory. This is expensive :-(
1006141471Sjhb		 */
1007141471Sjhb		NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, prefix, td);
1008141471Sjhb
1009141471Sjhb		/* We shouldn't ever get an error from this namei(). */
1010141471Sjhb		error = namei(&ndroot);
1011141471Sjhb		if (error == 0) {
1012141471Sjhb			if (nd.ni_vp == ndroot.ni_vp)
1013141471Sjhb				error = ENOENT;
1014141471Sjhb
1015141471Sjhb			NDFREE(&ndroot, NDF_ONLY_PNBUF);
1016141471Sjhb			vrele(ndroot.ni_vp);
1017141471Sjhb		}
1018141471Sjhb	}
1019141471Sjhb
1020141471Sjhb	NDFREE(&nd, NDF_ONLY_PNBUF);
1021141471Sjhb	vrele(nd.ni_vp);
1022141471Sjhb
1023141471Sjhbnd_failed:
1024141471Sjhb	/* XXX: VFS_UNLOCK_GIANT? */
1025141471Sjhb	mtx_unlock(&Giant);
1026141471Sjhb
1027141471Sjhbkeeporig:
1028141471Sjhb	/* If there was an error, use the original path name. */
1029141471Sjhb	if (error)
1030141471Sjhb		bcopy(ptr, buf, len);
1031141471Sjhb	return (error);
1032141471Sjhb}
1033