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