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