xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 52181)
123401Smckusick /*
237715Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337715Smckusick  * All rights reserved.
423401Smckusick  *
544457Sbostic  * %sccs.include.redist.c%
637715Smckusick  *
7*52181Smckusick  *	@(#)vfs_lookup.c	7.34 (Berkeley) 01/13/92
823401Smckusick  */
930Sbill 
1017100Sbloom #include "param.h"
1149736Smckusick #include "syslimits.h"
1237715Smckusick #include "time.h"
1337715Smckusick #include "namei.h"
1437715Smckusick #include "vnode.h"
1517100Sbloom #include "mount.h"
1637715Smckusick #include "errno.h"
1731650Smckusick #include "malloc.h"
1845914Smckusick #include "filedesc.h"
1945924Smckusick #include "proc.h"
2037715Smckusick 
2137582Smarc #ifdef KTRACE
2237582Smarc #include "ktrace.h"
2337582Smarc #endif
2430Sbill 
2530Sbill /*
2627268Smckusick  * Convert a pathname into a pointer to a locked inode.
2730Sbill  *
2816688Smckusick  * The FOLLOW flag is set when symbolic links are to be followed
299166Ssam  * when they occur at the end of the name translation process.
3027268Smckusick  * Symbolic links are always followed for all other pathname
3127268Smckusick  * components other than the last.
329166Ssam  *
3327268Smckusick  * The segflg defines whether the name is to be copied from user
3427268Smckusick  * space or kernel space.
3527268Smckusick  *
3615798Smckusick  * Overall outline of namei:
3715798Smckusick  *
387534Sroot  *	copy in name
397534Sroot  *	get starting directory
4049736Smckusick  *	while (!done && !error) {
4149736Smckusick  *		call lookup to search path.
4249736Smckusick  *		if symbolic link, massage name in buffer and continue
4349736Smckusick  *	}
4449736Smckusick  */
4549736Smckusick namei(ndp, p)
4649736Smckusick 	register struct nameidata *ndp;
4749736Smckusick 	struct proc *p;
4849736Smckusick {
4949736Smckusick 	register struct filedesc *fdp;	/* pointer to file descriptor state */
5049736Smckusick 	register char *cp;		/* pointer into pathname argument */
5149736Smckusick 	register struct vnode *dp;	/* the directory we are searching */
5249736Smckusick 	struct iovec aiov;		/* uio for reading symbolic links */
5349736Smckusick 	struct uio auio;
5449736Smckusick 	int error, linklen;
5549736Smckusick 
5649736Smckusick 	ndp->ni_cred = p->p_ucred;
5749736Smckusick 	fdp = p->p_fd;
5849736Smckusick 
5949736Smckusick 	/*
6049736Smckusick 	 * Get a buffer for the name to be translated, and copy the
6149736Smckusick 	 * name into the buffer.
6249736Smckusick 	 */
6349810Smckusick 	if ((ndp->ni_nameiop & HASBUF) == 0)
6449810Smckusick 		MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
6549736Smckusick 	if (ndp->ni_segflg == UIO_SYSSPACE)
6649736Smckusick 		error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
6749736Smckusick 			    MAXPATHLEN, &ndp->ni_pathlen);
6849736Smckusick 	else
6949736Smckusick 		error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
7049736Smckusick 			    MAXPATHLEN, &ndp->ni_pathlen);
7149736Smckusick 	if (error) {
7249736Smckusick 		free(ndp->ni_pnbuf, M_NAMEI);
7349736Smckusick 		ndp->ni_vp = NULL;
7449736Smckusick 		return (error);
7549736Smckusick 	}
7649736Smckusick 	ndp->ni_loopcnt = 0;
7749736Smckusick #ifdef KTRACE
7849736Smckusick 	if (KTRPOINT(p, KTR_NAMEI))
7949736Smckusick 		ktrnamei(p->p_tracep, ndp->ni_pnbuf);
8049736Smckusick #endif
8149736Smckusick 
8249736Smckusick 	/*
8349736Smckusick 	 * Get starting point for the translation.
8449736Smckusick 	 */
8549736Smckusick 	if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
8649736Smckusick 		ndp->ni_rootdir = rootdir;
8749736Smckusick 	dp = fdp->fd_cdir;
8849736Smckusick 	VREF(dp);
8949736Smckusick 	for (;;) {
9049736Smckusick 		/*
9149736Smckusick 		 * Check if root directory should replace current directory.
9249736Smckusick 		 * Done at start of translation and after symbolic link.
9349736Smckusick 		 */
9449736Smckusick 		ndp->ni_ptr = ndp->ni_pnbuf;
9549736Smckusick 		if (*ndp->ni_ptr == '/') {
9649736Smckusick 			vrele(dp);
9749736Smckusick 			while (*ndp->ni_ptr == '/') {
9849736Smckusick 				ndp->ni_ptr++;
9949736Smckusick 				ndp->ni_pathlen--;
10049736Smckusick 			}
10149736Smckusick 			dp = ndp->ni_rootdir;
10249736Smckusick 			VREF(dp);
10349736Smckusick 		}
10449736Smckusick 		ndp->ni_startdir = dp;
10549736Smckusick 		if (error = lookup(ndp, p)) {
10649736Smckusick 			FREE(ndp->ni_pnbuf, M_NAMEI);
10749736Smckusick 			return (error);
10849736Smckusick 		}
10949736Smckusick 		/*
11049736Smckusick 		 * Check for symbolic link
11149736Smckusick 		 */
11249736Smckusick 		if (ndp->ni_more == 0) {
11349736Smckusick 			if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0)
11449736Smckusick 				FREE(ndp->ni_pnbuf, M_NAMEI);
11549736Smckusick 			else
11649736Smckusick 				ndp->ni_nameiop |= HASBUF;
11749736Smckusick 			return (0);
11849736Smckusick 		}
11949736Smckusick 		if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
12049736Smckusick 			VOP_UNLOCK(ndp->ni_dvp);
12149736Smckusick 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
12249736Smckusick 			error = ELOOP;
12349736Smckusick 			break;
12449736Smckusick 		}
12549736Smckusick 		if (ndp->ni_pathlen > 1)
12649736Smckusick 			MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
12749736Smckusick 		else
12849736Smckusick 			cp = ndp->ni_pnbuf;
12949736Smckusick 		aiov.iov_base = cp;
13049736Smckusick 		aiov.iov_len = MAXPATHLEN;
13149736Smckusick 		auio.uio_iov = &aiov;
13249736Smckusick 		auio.uio_iovcnt = 1;
13349736Smckusick 		auio.uio_offset = 0;
13449736Smckusick 		auio.uio_rw = UIO_READ;
13549736Smckusick 		auio.uio_segflg = UIO_SYSSPACE;
13649736Smckusick 		auio.uio_procp = (struct proc *)0;
13749736Smckusick 		auio.uio_resid = MAXPATHLEN;
13849736Smckusick 		if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) {
13949736Smckusick 			if (ndp->ni_pathlen > 1)
14049736Smckusick 				free(cp, M_NAMEI);
14149736Smckusick 			break;
14249736Smckusick 		}
14349736Smckusick 		linklen = MAXPATHLEN - auio.uio_resid;
14449736Smckusick 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
14549736Smckusick 			if (ndp->ni_pathlen > 1)
14649736Smckusick 				free(cp, M_NAMEI);
14749736Smckusick 			error = ENAMETOOLONG;
14849736Smckusick 			break;
14949736Smckusick 		}
15049736Smckusick 		if (ndp->ni_pathlen > 1) {
15149736Smckusick 			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
15249736Smckusick 			FREE(ndp->ni_pnbuf, M_NAMEI);
15349736Smckusick 			ndp->ni_pnbuf = cp;
15449736Smckusick 		} else
15549736Smckusick 			ndp->ni_pnbuf[linklen] = '\0';
15649736Smckusick 		ndp->ni_pathlen += linklen;
15749736Smckusick 		vput(ndp->ni_vp);
15849736Smckusick 		dp = ndp->ni_dvp;
15949736Smckusick 	}
16049736Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
16149736Smckusick 	vrele(ndp->ni_dvp);
16249736Smckusick 	vput(ndp->ni_vp);
16349736Smckusick 	ndp->ni_vp = NULL;
16449736Smckusick 	return (error);
16549736Smckusick }
16649736Smckusick 
16749736Smckusick /*
16849736Smckusick  * Search a pathname.
16949736Smckusick  * This is a very central and rather complicated routine.
17049736Smckusick  *
17149736Smckusick  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
17249736Smckusick  * The starting directory is taken from ni_startdir. The pathname is
17349736Smckusick  * descended until done, or a symbolic link is encountered. The variable
17449736Smckusick  * ni_more is clear if the path is completed; it is set to one if a
17549736Smckusick  * symbolic link needing interpretation is encountered.
17649736Smckusick  *
17749736Smckusick  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
17849736Smckusick  * whether the name is to be looked up, created, renamed, or deleted.
17949736Smckusick  * When CREATE, RENAME, or DELETE is specified, information usable in
18049736Smckusick  * creating, renaming, or deleting a directory entry may be calculated.
18149736Smckusick  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
18249736Smckusick  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
18349736Smckusick  * returned unlocked. Otherwise the parent directory is not returned. If
18449736Smckusick  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
18549736Smckusick  * the target is returned locked, otherwise it is returned unlocked.
18649736Smckusick  * When creating or renaming and LOCKPARENT is specified, the target may not
18749736Smckusick  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
18849736Smckusick  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
18949736Smckusick  *
19049736Smckusick  * Overall outline of lookup:
19149736Smckusick  *
1927534Sroot  * dirloop:
19349736Smckusick  *	identify next component of name at ndp->ni_ptr
1947534Sroot  *	handle degenerate case where name is null string
19549736Smckusick  *	if .. and crossing mount points and on mounted filesys, find parent
19649736Smckusick  *	call VOP_LOOKUP routine for next component name
19749736Smckusick  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
19849736Smckusick  *	    component vnode returned in ni_vp (if it exists), locked.
19949736Smckusick  *	if result vnode is mounted on and crossing mount points,
20049736Smckusick  *	    find mounted on vnode
2017534Sroot  *	if more components of name, do next level at dirloop
20249736Smckusick  *	return the answer in ni_vp, locked if LOCKLEAF set
20349736Smckusick  *	    if LOCKPARENT set, return locked parent in ni_dvp
20449736Smckusick  *	    if WANTPARENT set, return unlocked parent in ni_dvp
20530Sbill  */
20649736Smckusick lookup(ndp, p)
20716688Smckusick 	register struct nameidata *ndp;
20847540Skarels 	struct proc *p;
20930Sbill {
2107534Sroot 	register char *cp;		/* pointer into pathname argument */
21137715Smckusick 	register struct vnode *dp = 0;	/* the directory we are searching */
21237715Smckusick 	struct vnode *tdp;		/* saved dp */
21337715Smckusick 	struct mount *mp;		/* mount table entry */
21418109Smckusick 	int docache;			/* == 0 do not cache last component */
21537715Smckusick 	int flag;			/* LOOKUP, CREATE, RENAME or DELETE */
21637715Smckusick 	int wantparent;			/* 1 => wantparent or lockparent flag */
217*52181Smckusick 	int rdonly;			/* lookup read-only flag bit */
21837715Smckusick 	int error = 0;
21930Sbill 
22041337Smckusick 	/*
22141337Smckusick 	 * Setup: break out flag bits into variables.
22241337Smckusick 	 */
22346508Smckusick 	flag = ndp->ni_nameiop & OPMASK;
22437715Smckusick 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
22516688Smckusick 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
22646746Smckusick 	if (flag == DELETE || (wantparent && flag != CREATE))
22715798Smckusick 		docache = 0;
228*52181Smckusick 	rdonly = ndp->ni_nameiop & RDONLY;
22949736Smckusick 	ndp->ni_dvp = NULL;
23049736Smckusick 	ndp->ni_more = 0;
23149736Smckusick 	dp = ndp->ni_startdir;
23249736Smckusick 	ndp->ni_startdir = NULLVP;
23337715Smckusick 	VOP_LOCK(dp);
2347534Sroot 
2356571Smckusic dirloop:
23630Sbill 	/*
23749736Smckusick 	 * Search a new directory.
23849736Smckusick 	 *
23949736Smckusick 	 * The ni_hash value is for use by vfs_cache.
24049736Smckusick 	 * The last component of the filename is left accessible via
24149736Smckusick 	 * ndp->ptr for callers that need the name. Callers needing
24249736Smckusick 	 * the name set the SAVENAME flag. When done, they assume
24349736Smckusick 	 * responsibility for freeing the pathname buffer.
2447534Sroot 	 */
24549736Smckusick 	ndp->ni_hash = 0;
24649841Smckusick 	for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
24749736Smckusick 		ndp->ni_hash += (unsigned char)*cp;
24849736Smckusick 	ndp->ni_namelen = cp - ndp->ni_ptr;
24949736Smckusick 	if (ndp->ni_namelen >= NAME_MAX) {
25049736Smckusick 		error = ENAMETOOLONG;
25149736Smckusick 		goto bad;
25249736Smckusick 	}
25337743Smckusick #ifdef NAMEI_DIAGNOSTIC
25449736Smckusick 	{ char c = *cp;
25549736Smckusick 	*cp = '\0';
25649736Smckusick 	printf("{%s}: ", ndp->ni_ptr);
25749736Smckusick 	*cp = c; }
25837743Smckusick #endif
25949736Smckusick 	ndp->ni_pathlen -= ndp->ni_namelen;
26049736Smckusick 	ndp->ni_next = cp;
26137715Smckusick 	ndp->ni_makeentry = 1;
26218109Smckusick 	if (*cp == '\0' && docache == 0)
26337715Smckusick 		ndp->ni_makeentry = 0;
26437715Smckusick 	ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
26549736Smckusick 		ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
2667534Sroot 
2677534Sroot 	/*
2687534Sroot 	 * Check for degenerate name (e.g. / or "")
2697534Sroot 	 * which is a way of talking about a directory,
2707534Sroot 	 * e.g. like "/." or ".".
2717534Sroot 	 */
27237715Smckusick 	if (ndp->ni_ptr[0] == '\0') {
27337715Smckusick 		if (flag != LOOKUP || wantparent) {
27437715Smckusick 			error = EISDIR;
2757534Sroot 			goto bad;
2765972Swnj 		}
27749736Smckusick 		if (dp->v_type != VDIR) {
27849736Smckusick 			error = ENOTDIR;
27949736Smckusick 			goto bad;
28049736Smckusick 		}
28137715Smckusick 		if (!(ndp->ni_nameiop & LOCKLEAF))
28237715Smckusick 			VOP_UNLOCK(dp);
28337715Smckusick 		ndp->ni_vp = dp;
28449736Smckusick 		if (ndp->ni_nameiop & SAVESTART)
28549736Smckusick 			panic("lookup: SAVESTART");
28637715Smckusick 		return (0);
2875972Swnj 	}
2887534Sroot 
2896571Smckusic 	/*
29037715Smckusick 	 * Handle "..": two special cases.
29137715Smckusick 	 * 1. If at root directory (e.g. after chroot)
29237715Smckusick 	 *    then ignore it so can't get out.
29337715Smckusick 	 * 2. If this vnode is the root of a mounted
29449736Smckusick 	 *    filesystem, then replace it with the
29537715Smckusick 	 *    vnode which was mounted on so we take the
29637715Smckusick 	 *    .. in the other file system.
29736547Smckusick 	 */
29837715Smckusick 	if (ndp->ni_isdotdot) {
29936547Smckusick 		for (;;) {
30049736Smckusick 			if (dp == ndp->ni_rootdir) {
30137715Smckusick 				ndp->ni_dvp = dp;
30238390Smckusick 				ndp->ni_vp = dp;
30338347Smckusick 				VREF(dp);
30437715Smckusick 				goto nextname;
30536547Smckusick 			}
30641337Smckusick 			if ((dp->v_flag & VROOT) == 0 ||
30749736Smckusick 			    (ndp->ni_nameiop & NOCROSSMOUNT))
30836547Smckusick 				break;
30937715Smckusick 			tdp = dp;
31041400Smckusick 			dp = dp->v_mount->mnt_vnodecovered;
31137715Smckusick 			vput(tdp);
31238390Smckusick 			VREF(dp);
31337715Smckusick 			VOP_LOCK(dp);
31436547Smckusick 		}
31536547Smckusick 	}
31636547Smckusick 
31736547Smckusick 	/*
31815798Smckusick 	 * We now have a segment name to search for, and a directory to search.
31915798Smckusick 	 */
32048025Smckusick 	if (error = VOP_LOOKUP(dp, ndp, p)) {
32149736Smckusick #ifdef DIAGNOSTIC
32237715Smckusick 		if (ndp->ni_vp != NULL)
32337715Smckusick 			panic("leaf should be empty");
32449736Smckusick #endif
32537582Smarc #ifdef NAMEI_DIAGNOSTIC
32637715Smckusick 		printf("not found\n");
32737582Smarc #endif
32838581Smckusick 		if (flag == LOOKUP || flag == DELETE ||
32938581Smckusick 		    error != ENOENT || *cp != 0)
33038581Smckusick 			goto bad;
3315972Swnj 		/*
33237715Smckusick 		 * If creating and at end of pathname, then can consider
33337715Smckusick 		 * allowing file to be created.
3345972Swnj 		 */
335*52181Smckusick 		if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
33637715Smckusick 			error = EROFS;
3377534Sroot 			goto bad;
33838581Smckusick 		}
3395972Swnj 		/*
34037715Smckusick 		 * We return with ni_vp NULL to indicate that the entry
34137715Smckusick 		 * doesn't currently exist, leaving a pointer to the
34237715Smckusick 		 * (possibly locked) directory inode in ndp->ni_dvp.
3435972Swnj 		 */
34449736Smckusick 		if (ndp->ni_nameiop & SAVESTART) {
34549736Smckusick 			ndp->ni_startdir = ndp->ni_dvp;
34649736Smckusick 			VREF(ndp->ni_startdir);
34749736Smckusick 		}
34849736Smckusick 		return (0);
3497534Sroot 	}
35037582Smarc #ifdef NAMEI_DIAGNOSTIC
35137715Smckusick 	printf("found\n");
35237582Smarc #endif
3537534Sroot 
35449736Smckusick 	dp = ndp->ni_vp;
3557534Sroot 	/*
35637715Smckusick 	 * Check for symbolic link
3577534Sroot 	 */
35837715Smckusick 	if ((dp->v_type == VLNK) &&
35937715Smckusick 	    ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
36049736Smckusick 		ndp->ni_more = 1;
36149736Smckusick 		return (0);
36215798Smckusick 	}
36315798Smckusick 
3647534Sroot 	/*
36537715Smckusick 	 * Check to see if the vnode has been mounted on;
36637715Smckusick 	 * if so find the root of the mounted file system.
3677534Sroot 	 */
36837715Smckusick mntloop:
36941337Smckusick 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
37041337Smckusick 	       (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
37152116Smarc 		if (mp->mnt_flag & MNT_MLOCK) {
37241400Smckusick 			mp->mnt_flag |= MNT_MWAIT;
37337715Smckusick 			sleep((caddr_t)mp, PVFS);
37437715Smckusick 			goto mntloop;
37521014Smckusick 		}
37649736Smckusick 		if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
3777534Sroot 			goto bad2;
37837715Smckusick 		vput(dp);
37937715Smckusick 		ndp->ni_vp = dp = tdp;
38030Sbill 	}
3817534Sroot 
38237715Smckusick nextname:
38330Sbill 	/*
3847534Sroot 	 * Not a symbolic link.  If more pathname,
3857534Sroot 	 * continue at next component, else return.
38630Sbill 	 */
38749736Smckusick 	if (*ndp->ni_next == '/') {
38849736Smckusick 		ndp->ni_ptr = ndp->ni_next;
38937715Smckusick 		while (*ndp->ni_ptr == '/') {
39037715Smckusick 			ndp->ni_ptr++;
39137715Smckusick 			ndp->ni_pathlen--;
39237715Smckusick 		}
39337715Smckusick 		vrele(ndp->ni_dvp);
3947534Sroot 		goto dirloop;
39530Sbill 	}
3967534Sroot 	/*
39738400Smckusick 	 * Check for read-only file systems.
3987534Sroot 	 */
39938400Smckusick 	if (flag == DELETE || flag == RENAME) {
40038267Smckusick 		/*
40138400Smckusick 		 * Disallow directory write attempts on read-only
40238400Smckusick 		 * file systems.
40338267Smckusick 		 */
404*52181Smckusick 		if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
405*52181Smckusick 		    (wantparent &&
406*52181Smckusick 		     (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
40738267Smckusick 			error = EROFS;
40838267Smckusick 			goto bad2;
40938267Smckusick 		}
41038267Smckusick 	}
41149736Smckusick 	if (ndp->ni_nameiop & SAVESTART) {
41249736Smckusick 		ndp->ni_startdir = ndp->ni_dvp;
41349736Smckusick 		VREF(ndp->ni_startdir);
41449736Smckusick 	}
41537715Smckusick 	if (!wantparent)
41637715Smckusick 		vrele(ndp->ni_dvp);
41737715Smckusick 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
41837715Smckusick 		VOP_UNLOCK(dp);
41937715Smckusick 	return (0);
4207534Sroot 
42137715Smckusick bad2:
42249736Smckusick 	if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
42338001Smckusick 		VOP_UNLOCK(ndp->ni_dvp);
42437715Smckusick 	vrele(ndp->ni_dvp);
42537715Smckusick bad:
42637715Smckusick 	vput(dp);
42737715Smckusick 	ndp->ni_vp = NULL;
42810849Ssam 	return (error);
4295972Swnj }
430