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.5 1997/09/29 10:10:53 wosch Exp $ 30.\" 31.Dd November 24, 1997 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 EACCES 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_ABORTOP 9 , 434.Xr VOP_ACCESS 9 , 435.Xr VOP_CREATE 9 , 436.Xr VOP_MKDIR 9 , 437.Xr VOP_MKNOD 9 , 438.Xr VOP_RENAME 9 , 439.Xr VOP_SYMLINK 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