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