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