xref: /freebsd/share/man/man9/VOP_LOOKUP.9 (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
1.\" -*- nroff -*-
2.\"
3.\" Copyright (c) 1996 Doug Rabson
4.\"
5.\" All rights reserved.
6.\"
7.\" This program is free software.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
19.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
22.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28.\"
29.\" $Id: VOP_LOOKUP.9,v 1.3 1997/03/07 03:32:26 mpp Exp $
30.\"
31.Dd July 24, 1996
32.Os FreeBSD
33.Dt VOP_LOOKUP 9
34.Sh NAME
35.Nm VOP_LOOKUP
36.Nd lookup a component of a pathname
37.Sh SYNOPSIS
38.Fd #include <sys/param.h>
39.Fd #include <sys/vnode.h>
40.Fd #include <sys/namei.h>
41.Ft int
42.Fn VOP_LOOKUP "struct vnode *dvp" "struct vnode **vpp" "struct componentname *cnp"
43.Sh DESCRIPTION
44This VFS entry point looks up a single pathname component in a given directory.
45.Pp
46Its arguments are:
47.Bl -tag -width vpp
48.It Ar dvp
49the locked vnode of the directory to search
50.It Ar vpp
51the address of a variable where the resulting locked vnode should be stored
52.It Ar cnp
53the pathname component to be searched for
54.El
55.Pp
56.Fa Cnp
57is a pointer to a componentname structure defined as follows:
58.Bd -literal
59struct componentname {
60	/*
61	 * Arguments to lookup.
62	 */
63	u_long	cn_nameiop;	/* namei operation */
64	u_long	cn_flags;	/* flags to namei */
65	struct	proc *cn_proc;	/* process requesting lookup */
66	struct	ucred *cn_cred;	/* credentials */
67	/*
68	 * Shared between lookup and commit routines.
69	 */
70	char	*cn_pnbuf;	/* pathname buffer */
71	char	*cn_nameptr;	/* pointer to looked up name */
72	long	cn_namelen;	/* length of looked up component */
73	u_long	cn_hash;	/* hash value of looked up name */
74	long	cn_consume;	/* chars to consume in lookup() */
75};
76.Ed
77.Pp
78Convert a component of a pathname into a pointer to a locked vnode.
79This is a very central and rather complicated routine.
80If the file system is not maintained in a strict tree hierarchy,
81this can result in a deadlock situation.
82.Pp
83The
84.Fa cnp->cn_nameiop
85argument is
86.Dv LOOKUP ,
87.Dv CREATE ,
88.Dv RENAME ,
89or
90.Dv DELETE
91depending on the intended use of the object.
92When
93.Dv CREATE ,
94.Dv RENAME ,
95or
96.Dv DELETE
97is specified, information usable in
98creating, renaming, or deleting a directory entry may be calculated.
99.Pp
100Overall outline of VOP_LOOKUP:
101.Bd -filled -offset indent
102Check accessibility of directory.
103Look for name in cache, if found, then return name.
104Search for name in directory, goto to found or notfound as appropriate.
105.Ed
106.Pp
107notfound:
108.Bd -filled -offset indent
109If creating or renaming and at end of pathname,
110return
111.Dv EJUSTRETURN ,
112leaving info on available slots else return
113.Dv ENOENT .
114.Ed
115.Pp
116found:
117.Bd -filled -offset indent
118If at end of path and deleting, return information to allow delete.
119If at end of path and renaming, lock target
120inode and return info to allow rename.
121If not at end, add name to cache; if at end and neither creating
122nor deleting, add name to cache.
123.Ed
124.Sh LOCKS
125The directory,
126.Fa dvp
127should be locked on entry.
128If an error (note: the return value
129.Dv EJUSTRETURN
130is not considered an error)
131is detected, it will be returned locked.
132Otherwise, it will be unlocked unless both
133.Dv LOCKPARENT
134and
135.Dv ISLASTCN
136are specified in
137.Fa cnp->cn_flags .
138If an entry is found in the directory, it will be returned locked.
139.Sh RETURN VALUES
140Zero is returned with
141.Fa *vpp
142set to the locked vnode of the file if the component is found.
143If the component being searched for is ".", then the vnode just has
144an extra reference added to it with
145.Xr vref 9 .
146The caller must take care to release the locks appropriately in this
147case.
148.Pp
149If the component is not found and the operation is
150.Dv CREATE
151or
152.Dv RENAME ,
153the flag
154.Dv ISLASTCN
155is specified and the operation would succeed, the special return value
156.Dv EJUSTRETURN
157is returned.
158Otherwise, an appropriate error code is returned.
159.Sh PSEUDOCODE
160.Bd -literal
161int
162vop_lookup(struct vnode *dvp,
163	   struct vnode **vpp,
164	   struct componentname *cnp)
165{
166    int error;
167    int nameiop = cnp->cn_nameiop;
168    int flags = cnp->cn_flags;
169    int lockparent = flags & LOCKPARENT;
170    int islastcn = flags & ISLASTCN;
171    struct vnode *vp = NULL;
172
173    /*
174     * Check accessibility of directory.
175     */
176    if (dvp->v_type != VDIR)
177	return ENOTDIR;
178
179    error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc);
180    if (error)
181	return (error);
182
183    if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
184	(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
185	return (EROFS);
186
187    /*
188     * Check name cache for directory/name pair.  This returns ENOENT
189     * if the name is known not to exist, -1 if the name was found, or
190     * zero if not.
191     */
192    error = cache_lookup(dvp, vpp, cnp);
193    if (error) {
194	int vpid;
195
196	if (error = ENOENT)
197	    return error;
198
199	vp = *vpp;
200	if (dvp == vp) {	/* lookup on "." */
201	    VREF(vp);
202	    error = 0;
203	} else if (flags & ISDOTDOT) {
204            /*
205	     * We need to unlock the directory before getting
206	     * the locked vnode for ".." to avoid deadlocks.
207	     */
208	    VOP_UNLOCK(dvp);
209	    error = vget(vp, 1);
210	    if (!error) {
211		if (lockparent && islastcn)
212		    error = VOP_LOCK(dvp);
213	    }
214	} else {
215	    error = vget(vp, 1);
216	    if (error || !(lockparent && islastcn)) {
217		VOP_UNLOCK(dvp);
218	    }
219	}
220
221	/*
222	 * Check that the capability number did not change
223	 * while we were waiting for the lock.
224	 */
225	if (!error) {
226	    if (vpid == vp->v_id) {
227		/*
228		 * dvp is locked if lockparent && islastcn.
229		 * vp is locked.
230		 */
231		return (0);
232	    }
233	    vput(vp);
234
235	    if (dvp != vp && lockparent && islastcn)
236		VOP_UNLOCK(pdp);
237	}
238
239	/*
240	 * Re-lock dvp for the directory search below.
241	 */
242	error = VOP_LOCK(dvp);
243	if (error) {
244	    return (error);
245	}
246
247	*vpp = NULL;
248    }
249
250    /*
251     * Search dvp for the component cnp->cn_nameptr.
252     */
253    ...;
254
255    if (!found) {
256	if ((nameiop == CREATE || nameiop == RENAME)
257	    && islastcn
258	    && directory dvp has not been removed) {
259	    /*
260	     * Check for write access on directory.
261	     */
262
263	    /*
264	     * Possibly record the position of a slot in the directory
265	     * large enough for the new component name.  This can be
266	     * recorded in the vnode private data for dvp.
267	     * Set the SAVENAME flag to hold onto the pathname for use
268	     * later in VOP_CREATE or VOP_RENAME.
269	     */
270	    cnp->cn_flags |= SAVENAME;
271	    if (!lockparent)
272		/*
273		 * Note that the extra data recorded above is only
274		 * useful if lockparent is specified.
275		 */
276		VOP_UNLOCK(dvp);
277
278	    return EJUSTRETURN;
279	}
280
281	/*
282	 * Consider inserting name into cache.
283	 */
284	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
285	    cache_enter(dvp, NULL, cnp);
286
287	return ENOENT;
288    } else {
289	/*
290	 * If deleting, and at end of pathname, return parameters
291	 * which can be used to remove file.  If the wantparent flag
292	 * isn't set, we return only the directory, otherwise we go on
293	 * and lock the inode, being careful with ".".
294	 */
295	if (nameiop == DELETE && islastcn) {
296	    /*
297	     * Check for write access on directory.
298	     */
299	    error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
300	    if (error)
301		return (error);
302
303	    if (found entry is same as dvp) {
304		VREF(dvp);
305		*vpp = dvp;
306		return 0;
307	    }
308
309	    error = VFS_VGET(dvp->v_mount, ..., &vp);
310	    if (error)
311		return error;
312
313	    if (directory is sticky
314		&& cred->cr_uid != 0
315		&& cred->cr_uid != owner of dvp
316		&& owner of vp != cred->cr_uid) {
317		vput(vp);
318		return EPERM;
319	    }
320	    *vpp = vp;
321	    if (!lockparent)
322		VOP_UNLOCK(dvp);
323
324	    return 0;
325	}
326
327	/*
328	 * If rewriting (RENAME), return the inode and the
329	 * information required to rewrite the present directory
330	 * Must get inode of directory entry to verify it's a
331	 * regular file, or empty directory.
332	 */
333	if (nameiop == RENAME && wantparent && islastcn) {
334	    error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
335	    if (error)
336		return (error);
337
338	    /*
339	     * Check for "."
340	     */
341	    if (found entry is same as dvp)
342		return EISDIR;
343
344	    error = VFS_VGET(dvp->v_mount, ..., &vp);
345	    if (error)
346		return error;
347	    *vpp = vp;
348	    /*
349	     * Save the name for use in VOP_RENAME later.
350	     */
351	    cnp->cn_flags |= SAVENAME;
352	    if (!lockparent)
353		VOP_UNLOCK(dvp);
354
355	    return 0;
356	}
357
358	/*
359	 * Step through the translation in the name.  We do not `vput' the
360	 * directory because we may need it again if a symbolic link
361	 * is relative to the current directory.  Instead we save it
362	 * unlocked as "pdp".  We must get the target inode before unlocking
363	 * the directory to insure that the inode will not be removed
364	 * before we get it.  We prevent deadlock by always fetching
365	 * inodes from the root, moving down the directory tree. Thus
366	 * when following backward pointers ".." we must unlock the
367	 * parent directory before getting the requested directory.
368	 * There is a potential race condition here if both the current
369	 * and parent directories are removed before the VFS_VGET for the
370	 * inode associated with ".." returns.  We hope that this occurs
371	 * infrequently since we cannot avoid this race condition without
372	 * implementing a sophisticated deadlock detection algorithm.
373	 * Note also that this simple deadlock detection scheme will not
374	 * work if the file system has any hard links other than ".."
375	 * that point backwards in the directory structure.
376	 */
377	if (flags & ISDOTDOT) {
378	    VOP_UNLOCK(dvp);	/* race to get the inode */
379	    error = VFS_VGET(dvp->v_mount, ..., &vp);
380	    if (error) {
381		VOP_LOCK(dvp);
382		return (error);
383	    }
384	    if (lockparent && islastcn) {
385		error = VOP_LOCK(dvp);
386		if (error) {
387		    vput(vp);
388		    return error;
389		}
390	    }
391	    *vpp = vp;
392	} else if (found entry is same as dvp) {
393	    VREF(dvp);	/* we want ourself, ie "." */
394	    *vpp = dvp;
395	} else {
396	    error = VFS_VGET(dvp->v_mount, ..., &vp);
397	    if (error)
398		return (error);
399	    if (!lockparent || !islastcn)
400		VOP_UNLOCK(dvp);
401	    *vpp = vp;
402	}
403
404	/*
405	 * Insert name into cache if appropriate.
406	 */
407	if (cnp->cn_flags & MAKEENTRY)
408	    cache_enter(dvp, *vpp, cnp);
409	return (0);
410    }
411}
412.Ed
413.Sh ERRORS
414.Bl -tag -width Er
415.It Bq Er ENOTDIR
416The vnode
417.Fa dvp
418does not represent a directory.
419.It Bq Er ENOENT
420The component
421.Fa dvp
422was not found in this directory.
423.It Bq Er EACCESS
424access for the specified operation is denied.
425.It Bq Er EJUSTRETURN
426a
427.Dv CREATE
428or
429.Dv RENAME
430operation would be successful
431.El
432.Sh SEE ALSO
433.Xr VOP_ACCESS 9 ,
434.Xr VOP_CREATE 9 ,
435.Xr VOP_MKNOD 9 ,
436.Xr VOP_MKDIR 9 ,
437.Xr VOP_SYMLINK 9 ,
438.Xr VOP_RENAME 9 ,
439.Xr VOP_ABORTOP 9
440.Sh HISTORY
441The function
442.Nm
443appeared in
444.Bx 4.3 .
445.Sh SEE ALSO
446.Xr vnode 9
447.Sh AUTHORS
448This man page was written by Doug Rabson, with some text from
449comments in ufs_lookup.c.
450