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