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