vfs_lookup.c revision 35105
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.26 1998/02/15 04:17:07 dyson 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		if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
506			error = EACCES;
507			goto bad2;
508		}
509		return (0);
510	}
511
512	/*
513	 * Check for bogus trailing slashes.
514	 */
515	if (trailing_slash && dp->v_type != VDIR) {
516		error = ENOTDIR;
517		goto bad2;
518	}
519
520nextname:
521	/*
522	 * Not a symbolic link.  If more pathname,
523	 * continue at next component, else return.
524	 */
525	if (*ndp->ni_next == '/') {
526		cnp->cn_nameptr = ndp->ni_next;
527		while (*cnp->cn_nameptr == '/') {
528			cnp->cn_nameptr++;
529			ndp->ni_pathlen--;
530		}
531		if (ndp->ni_dvp != ndp->ni_vp) {
532		    ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup");
533		}
534		vrele(ndp->ni_dvp);
535		goto dirloop;
536	}
537	/*
538	 * Disallow directory write attempts on read-only file systems.
539	 */
540	if (rdonly &&
541	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
542		error = EROFS;
543		goto bad2;
544	}
545	if (cnp->cn_flags & SAVESTART) {
546		ndp->ni_startdir = ndp->ni_dvp;
547		VREF(ndp->ni_startdir);
548	}
549	if (!wantparent)
550		vrele(ndp->ni_dvp);
551
552	if ((cnp->cn_flags & LOCKLEAF) == 0)
553		VOP_UNLOCK(dp, 0, p);
554	return (0);
555
556bad2:
557	if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
558		VOP_UNLOCK(ndp->ni_dvp, 0, p);
559	vrele(ndp->ni_dvp);
560bad:
561	vput(dp);
562	ndp->ni_vp = NULL;
563	return (error);
564}
565
566/*
567 * relookup - lookup a path name component
568 *    Used by lookup to re-aquire things.
569 */
570int
571relookup(dvp, vpp, cnp)
572	struct vnode *dvp, **vpp;
573	struct componentname *cnp;
574{
575	struct proc *p = cnp->cn_proc;
576	struct vnode *dp = 0;		/* the directory we are searching */
577	int docache;			/* == 0 do not cache last component */
578	int wantparent;			/* 1 => wantparent or lockparent flag */
579	int rdonly;			/* lookup read-only flag bit */
580	int error = 0;
581#ifdef NAMEI_DIAGNOSTIC
582	int newhash;			/* DEBUG: check name hash */
583	char *cp;			/* DEBUG: check name ptr/len */
584#endif
585
586	/*
587	 * Setup: break out flag bits into variables.
588	 */
589	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
590	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
591	if (cnp->cn_nameiop == DELETE ||
592	    (wantparent && cnp->cn_nameiop != CREATE))
593		docache = 0;
594	rdonly = cnp->cn_flags & RDONLY;
595	cnp->cn_flags &= ~ISSYMLINK;
596	dp = dvp;
597	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
598
599/* dirloop: */
600	/*
601	 * Search a new directory.
602	 *
603	 * The cn_hash value is for use by vfs_cache.
604	 * The last component of the filename is left accessible via
605	 * cnp->cn_nameptr for callers that need the name. Callers needing
606	 * the name set the SAVENAME flag. When done, they assume
607	 * responsibility for freeing the pathname buffer.
608	 */
609#ifdef NAMEI_DIAGNOSTIC
610	for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
611		newhash += (unsigned char)*cp;
612	if (newhash != cnp->cn_hash)
613		panic("relookup: bad hash");
614	if (cnp->cn_namelen != cp - cnp->cn_nameptr)
615		panic ("relookup: bad len");
616	if (*cp != 0)
617		panic("relookup: not last component");
618	printf("{%s}: ", cnp->cn_nameptr);
619#endif
620
621	/*
622	 * Check for degenerate name (e.g. / or "")
623	 * which is a way of talking about a directory,
624	 * e.g. like "/." or ".".
625	 */
626	if (cnp->cn_nameptr[0] == '\0') {
627		if (cnp->cn_nameiop != LOOKUP || wantparent) {
628			error = EISDIR;
629			goto bad;
630		}
631		if (dp->v_type != VDIR) {
632			error = ENOTDIR;
633			goto bad;
634		}
635		if (!(cnp->cn_flags & LOCKLEAF))
636			VOP_UNLOCK(dp, 0, p);
637		*vpp = dp;
638		if (cnp->cn_flags & SAVESTART)
639			panic("lookup: SAVESTART");
640		return (0);
641	}
642
643	if (cnp->cn_flags & ISDOTDOT)
644		panic ("relookup: lookup on dot-dot");
645
646	/*
647	 * We now have a segment name to search for, and a directory to search.
648	 */
649	if (error = VOP_LOOKUP(dp, vpp, cnp)) {
650#ifdef DIAGNOSTIC
651		if (*vpp != NULL)
652			panic("leaf should be empty");
653#endif
654		if (error != EJUSTRETURN)
655			goto bad;
656		/*
657		 * If creating and at end of pathname, then can consider
658		 * allowing file to be created.
659		 */
660		if (rdonly) {
661			error = EROFS;
662			goto bad;
663		}
664		/* ASSERT(dvp == ndp->ni_startdir) */
665		if (cnp->cn_flags & SAVESTART)
666			VREF(dvp);
667		/*
668		 * We return with ni_vp NULL to indicate that the entry
669		 * doesn't currently exist, leaving a pointer to the
670		 * (possibly locked) directory inode in ndp->ni_dvp.
671		 */
672		return (0);
673	}
674	dp = *vpp;
675
676#ifdef DIAGNOSTIC
677	/*
678	 * Check for symbolic link
679	 */
680	if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
681		panic ("relookup: symlink found.\n");
682#endif
683
684	/*
685	 * Disallow directory write attempts on read-only file systems.
686	 */
687	if (rdonly &&
688	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
689		error = EROFS;
690		goto bad2;
691	}
692	/* ASSERT(dvp == ndp->ni_startdir) */
693	if (cnp->cn_flags & SAVESTART)
694		VREF(dvp);
695
696	if (!wantparent)
697		vrele(dvp);
698
699	if (dp->v_type == VREG &&
700		((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF))
701		vfs_object_create(dp, cnp->cn_proc, cnp->cn_cred, 1);
702
703	if ((cnp->cn_flags & LOCKLEAF) == 0)
704		VOP_UNLOCK(dp, 0, p);
705	return (0);
706
707bad2:
708	if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
709		VOP_UNLOCK(dvp, 0, p);
710	vrele(dvp);
711bad:
712	vput(dp);
713	*vpp = NULL;
714	return (error);
715}
716