1 /* $OpenBSD: vfs_lookup.c,v 1.88 2023/01/06 19:08:36 miod Exp $ */ 2 /* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)vfs_lookup.c 8.6 (Berkeley) 11/21/94 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/syslimits.h> 43 #include <sys/namei.h> 44 #include <sys/vnode.h> 45 #include <sys/lock.h> 46 #include <sys/mount.h> 47 #include <sys/errno.h> 48 #include <sys/pool.h> 49 #include <sys/filedesc.h> 50 #include <sys/proc.h> 51 #include <sys/pledge.h> 52 #include <sys/file.h> 53 #include <sys/fcntl.h> 54 55 #ifdef KTRACE 56 #include <sys/ktrace.h> 57 #endif 58 59 int 60 component_push(struct componentname *cnp, char *component, size_t len) 61 { 62 if (cnp->cn_rpi + len + 1 >= MAXPATHLEN) 63 return 0; 64 if (cnp->cn_rpi > 1) 65 cnp->cn_rpbuf[cnp->cn_rpi++] = '/'; 66 memcpy(cnp->cn_rpbuf + cnp->cn_rpi, component, len); 67 cnp->cn_rpi+=len; 68 cnp->cn_rpbuf[cnp->cn_rpi] = '\0'; 69 return 1; 70 } 71 72 void 73 component_pop(struct componentname *cnp) 74 { 75 while(cnp->cn_rpi && cnp->cn_rpbuf[cnp->cn_rpi] != '/' ) 76 cnp->cn_rpi--; 77 if (cnp->cn_rpi == 0 && cnp->cn_rpbuf[0] == '/') 78 cnp->cn_rpi++; 79 cnp->cn_rpbuf[cnp->cn_rpi] = '\0'; 80 } 81 82 void 83 ndinitat(struct nameidata *ndp, u_long op, u_long flags, 84 enum uio_seg segflg, int dirfd, const char *namep, struct proc *p) 85 { 86 memset(ndp, 0, sizeof(*ndp)); 87 ndp->ni_cnd.cn_nameiop = op; 88 ndp->ni_cnd.cn_flags = flags; 89 ndp->ni_segflg = segflg; 90 ndp->ni_dirfd = dirfd; 91 ndp->ni_dirp = namep; 92 ndp->ni_cnd.cn_proc = p; 93 } 94 95 /* 96 * Convert a pathname into a pointer to a vnode. 97 * 98 * The FOLLOW flag is set when symbolic links are to be followed 99 * when they occur at the end of the name translation process. 100 * Symbolic links are always followed for all other pathname 101 * components other than the last. 102 * 103 * If the LOCKLEAF flag is set, a locked vnode is returned. 104 * 105 * The segflg defines whether the name is to be copied from user 106 * space or kernel space. 107 * 108 * Overall outline of namei: 109 * 110 * copy in name 111 * get starting directory 112 * while (!done && !error) { 113 * call lookup to search path. 114 * if symbolic link, massage name in buffer and continue 115 * } 116 */ 117 int 118 namei(struct nameidata *ndp) 119 { 120 struct filedesc *fdp; /* pointer to file descriptor state */ 121 char *cp; /* pointer into pathname argument */ 122 struct vnode *dp; /* the directory we are searching */ 123 struct iovec aiov; /* uio for reading symbolic links */ 124 struct uio auio; 125 int error, linklen; 126 struct componentname *cnp = &ndp->ni_cnd; 127 struct proc *p = cnp->cn_proc; 128 129 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 130 #ifdef DIAGNOSTIC 131 if (!cnp->cn_cred || !cnp->cn_proc) 132 panic ("namei: bad cred/proc"); 133 if (cnp->cn_nameiop & (~OPMASK)) 134 panic ("namei: nameiop contaminated with flags"); 135 if (cnp->cn_flags & OPMASK) 136 panic ("namei: flags contaminated with nameiops"); 137 #endif 138 fdp = cnp->cn_proc->p_fd; 139 140 /* 141 * Get a buffer for the name to be translated, and copy the 142 * name into the buffer. 143 */ 144 if ((cnp->cn_flags & HASBUF) == 0) 145 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK); 146 if (ndp->ni_segflg == UIO_SYSSPACE) { 147 ndp->ni_pathlen = strlcpy(cnp->cn_pnbuf, ndp->ni_dirp, 148 MAXPATHLEN); 149 if (ndp->ni_pathlen >= MAXPATHLEN) { 150 error = ENAMETOOLONG; 151 } else { 152 error = 0; 153 ndp->ni_pathlen++; /* ni_pathlen includes NUL */ 154 } 155 } else 156 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 157 MAXPATHLEN, &ndp->ni_pathlen); 158 159 /* 160 * Fail on null pathnames 161 */ 162 if (error == 0 && ndp->ni_pathlen == 1) 163 error = ENOENT; 164 165 if (error) 166 goto fail; 167 168 #ifdef KTRACE 169 if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 170 ktrnamei(cnp->cn_proc, cnp->cn_pnbuf); 171 #endif 172 173 /* 174 * Strip trailing slashes, as requested 175 */ 176 if (cnp->cn_flags & STRIPSLASHES) { 177 char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2; 178 179 cp = end; 180 while (cp >= cnp->cn_pnbuf && (*cp == '/')) 181 cp--; 182 183 /* Still some remaining characters in the buffer */ 184 if (cp >= cnp->cn_pnbuf) { 185 ndp->ni_pathlen -= (end - cp); 186 *(cp + 1) = '\0'; 187 } 188 } 189 190 ndp->ni_loopcnt = 0; 191 192 /* 193 * Get starting point for the translation. 194 */ 195 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL || 196 (ndp->ni_cnd.cn_flags & KERNELPATH)) 197 ndp->ni_rootdir = rootvnode; 198 199 if (ndp->ni_cnd.cn_flags & KERNELPATH) { 200 ndp->ni_cnd.cn_flags |= BYPASSUNVEIL; 201 } else { 202 error = pledge_namei(p, ndp, cnp->cn_pnbuf); 203 if (error) 204 goto fail; 205 } 206 207 /* 208 * Check if starting from root directory or current directory. 209 */ 210 if (cnp->cn_pnbuf[0] == '/') { 211 dp = ndp->ni_rootdir; 212 vref(dp); 213 if (cnp->cn_flags & REALPATH && cnp->cn_rpi == 0) { 214 cnp->cn_rpbuf[0] = '/'; 215 cnp->cn_rpbuf[1] = '\0'; 216 cnp->cn_rpi = 1; 217 } 218 } else if (ndp->ni_dirfd == AT_FDCWD) { 219 dp = fdp->fd_cdir; 220 vref(dp); 221 unveil_start_relative(p, ndp, dp); 222 unveil_check_component(p, ndp, dp); 223 } else { 224 struct file *fp = fd_getfile(fdp, ndp->ni_dirfd); 225 if (fp == NULL) { 226 error = EBADF; 227 goto fail; 228 } 229 dp = (struct vnode *)fp->f_data; 230 if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) { 231 FRELE(fp, p); 232 error = ENOTDIR; 233 goto fail; 234 } 235 vref(dp); 236 unveil_start_relative(p, ndp, dp); 237 unveil_check_component(p, ndp, dp); 238 FRELE(fp, p); 239 } 240 for (;;) { 241 if (!dp->v_mount) { 242 /* Give up if the directory is no longer mounted */ 243 vrele(dp); 244 error = ENOENT; 245 goto fail; 246 } 247 248 cnp->cn_nameptr = cnp->cn_pnbuf; 249 ndp->ni_startdir = dp; 250 if ((error = vfs_lookup(ndp)) != 0) 251 goto fail; 252 253 /* 254 * If not a symbolic link, return search result. 255 */ 256 if ((cnp->cn_flags & ISSYMLINK) == 0) { 257 if ((error = unveil_check_final(p, ndp))) { 258 if ((cnp->cn_flags & LOCKPARENT) && 259 (cnp->cn_flags & ISLASTCN) && 260 (ndp->ni_vp != ndp->ni_dvp)) 261 vput(ndp->ni_dvp); 262 if (ndp->ni_vp) { 263 if ((cnp->cn_flags & LOCKLEAF)) 264 vput(ndp->ni_vp); 265 else 266 vrele(ndp->ni_vp); 267 } 268 goto fail; 269 } 270 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 271 pool_put(&namei_pool, cnp->cn_pnbuf); 272 else 273 cnp->cn_flags |= HASBUF; 274 return (0); 275 } 276 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 277 VOP_UNLOCK(ndp->ni_dvp); 278 if (ndp->ni_loopcnt++ >= SYMLOOP_MAX) { 279 error = ELOOP; 280 break; 281 } 282 if (ndp->ni_pathlen > 1) 283 cp = pool_get(&namei_pool, PR_WAITOK); 284 else 285 cp = cnp->cn_pnbuf; 286 aiov.iov_base = cp; 287 aiov.iov_len = MAXPATHLEN; 288 auio.uio_iov = &aiov; 289 auio.uio_iovcnt = 1; 290 auio.uio_offset = 0; 291 auio.uio_rw = UIO_READ; 292 auio.uio_segflg = UIO_SYSSPACE; 293 auio.uio_procp = cnp->cn_proc; 294 auio.uio_resid = MAXPATHLEN; 295 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 296 if (error) { 297 badlink: 298 if (ndp->ni_pathlen > 1) 299 pool_put(&namei_pool, cp); 300 break; 301 } 302 linklen = MAXPATHLEN - auio.uio_resid; 303 if (linklen == 0) { 304 error = ENOENT; 305 goto badlink; 306 } 307 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 308 error = ENAMETOOLONG; 309 goto badlink; 310 } 311 if (ndp->ni_pathlen > 1) { 312 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); 313 pool_put(&namei_pool, cnp->cn_pnbuf); 314 cnp->cn_pnbuf = cp; 315 } else 316 cnp->cn_pnbuf[linklen] = '\0'; 317 ndp->ni_pathlen += linklen; 318 vput(ndp->ni_vp); 319 dp = ndp->ni_dvp; 320 /* 321 * Check if root directory should replace current directory. 322 */ 323 if (cnp->cn_pnbuf[0] == '/') { 324 vrele(dp); 325 dp = ndp->ni_rootdir; 326 vref(dp); 327 ndp->ni_unveil_match = NULL; 328 unveil_check_component(p, ndp, dp); 329 if (cnp->cn_flags & REALPATH) { 330 cnp->cn_rpbuf[0] = '/'; 331 cnp->cn_rpbuf[1] = '\0'; 332 cnp->cn_rpi = 1; 333 } 334 } else if (cnp->cn_flags & REALPATH) { 335 component_pop(cnp); 336 } 337 } 338 vrele(ndp->ni_dvp); 339 vput(ndp->ni_vp); 340 fail: 341 pool_put(&namei_pool, cnp->cn_pnbuf); 342 ndp->ni_vp = NULL; 343 return (error); 344 } 345 346 /* 347 * Search a pathname. 348 * This is a very central and rather complicated routine. 349 * 350 * The pathname is pointed to by ni_cnd.cn_nameptr and is of length 351 * ni_pathlen. The starting directory is taken from ni_startdir. The 352 * pathname is descended until done, or a symbolic link is encountered. 353 * If the path is completed the flag ISLASTCN is set in ni_cnd.cn_flags. 354 * If a symbolic link need interpretation is encountered, the flag ISSYMLINK 355 * is set in ni_cnd.cn_flags. 356 * 357 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 358 * whether the name is to be looked up, created, renamed, or deleted. 359 * When CREATE, RENAME, or DELETE is specified, information usable in 360 * creating, renaming, or deleting a directory entry may be calculated. 361 * If flag has LOCKPARENT or'ed into it, the parent directory is returned 362 * locked. If flag has WANTPARENT or'ed into it, the parent directory is 363 * returned unlocked. Otherwise the parent directory is not returned. If 364 * the target of the pathname exists and LOCKLEAF is or'ed into the flag 365 * the target is returned locked, otherwise it is returned unlocked. 366 * When creating or renaming and LOCKPARENT is specified, the target may not 367 * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 368 * 369 * Overall outline of lookup: 370 * 371 * dirloop: 372 * identify next component of name at ndp->ni_ptr 373 * handle degenerate case where name is null string 374 * if .. and crossing mount points and on mounted filesys, find parent 375 * call VOP_LOOKUP routine for next component name 376 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 377 * component vnode returned in ni_vp (if it exists), locked. 378 * if result vnode is mounted on and crossing mount points, 379 * find mounted on vnode 380 * if more components of name, do next level at dirloop 381 * return the answer in ni_vp, locked if LOCKLEAF set 382 * if LOCKPARENT set, return locked parent in ni_dvp 383 * if WANTPARENT set, return unlocked parent in ni_dvp 384 */ 385 int 386 vfs_lookup(struct nameidata *ndp) 387 { 388 char *cp; /* pointer into pathname argument */ 389 struct vnode *dp = NULL; /* the directory we are searching */ 390 struct vnode *tdp; /* saved dp */ 391 struct mount *mp; /* mount table entry */ 392 int docache; /* == 0 do not cache last component */ 393 int wantparent; /* 1 => wantparent or lockparent flag */ 394 int rdonly; /* lookup read-only flag bit */ 395 int error = 0; 396 int dpunlocked = 0; /* dp has already been unlocked */ 397 int slashes; 398 struct componentname *cnp = &ndp->ni_cnd; 399 /* 400 * Setup: break out flag bits into variables. 401 */ 402 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 403 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 404 if (cnp->cn_nameiop == DELETE || 405 (wantparent && cnp->cn_nameiop != CREATE)) 406 docache = 0; 407 rdonly = cnp->cn_flags & RDONLY; 408 ndp->ni_dvp = NULL; 409 cnp->cn_flags &= ~ISSYMLINK; 410 dp = ndp->ni_startdir; 411 ndp->ni_startdir = NULLVP; 412 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 413 414 /* 415 * If we have a leading string of slashes, remove them, and just make 416 * sure the current node is a directory. 417 */ 418 cp = cnp->cn_nameptr; 419 if (*cp == '/') { 420 do { 421 cp++; 422 } while (*cp == '/'); 423 ndp->ni_pathlen -= cp - cnp->cn_nameptr; 424 cnp->cn_nameptr = cp; 425 426 if (dp->v_type != VDIR) { 427 error = ENOTDIR; 428 goto bad; 429 } 430 431 /* 432 * If we've exhausted the path name, then just return the 433 * current node. If the caller requested the parent node (i.e. 434 * it's a CREATE, DELETE, or RENAME), and we don't have one 435 * (because this is the root directory), then we must fail. 436 */ 437 if (cnp->cn_nameptr[0] == '\0') { 438 if (ndp->ni_dvp == NULL && wantparent) { 439 error = EISDIR; 440 goto bad; 441 } 442 ndp->ni_vp = dp; 443 cnp->cn_flags |= ISLASTCN; 444 goto terminal; 445 } 446 } 447 448 dirloop: 449 /* 450 * Search a new directory. 451 * 452 * The last component of the filename is left accessible via 453 * cnp->cn_nameptr for callers that need the name. Callers needing 454 * the name set the SAVENAME flag. When done, they assume 455 * responsibility for freeing the pathname buffer. 456 */ 457 cnp->cn_consume = 0; 458 459 /* XXX: Figure out the length of the last component. */ 460 cp = cnp->cn_nameptr; 461 while (*cp && (*cp != '/')) 462 cp++; 463 cnp->cn_namelen = cp - cnp->cn_nameptr; 464 if (cnp->cn_namelen > NAME_MAX) { 465 error = ENAMETOOLONG; 466 goto bad; 467 } 468 469 #ifdef NAMEI_DIAGNOSTIC 470 { char c = *cp; 471 *cp = '\0'; 472 printf("{%s}: ", cnp->cn_nameptr); 473 *cp = c; } 474 #endif 475 if (cnp->cn_flags & REALPATH) { 476 size_t len = cp - cnp->cn_nameptr; 477 if (len == 2 && cnp->cn_nameptr[0] == '.' && 478 cnp->cn_nameptr[1] == '.') 479 component_pop(cnp); 480 else if (!(len == 1 && cnp->cn_nameptr[0] == '.')) { 481 if (!component_push(cnp, cnp->cn_nameptr, len)) { 482 error = ENAMETOOLONG; 483 goto bad; 484 } 485 } 486 } 487 488 ndp->ni_pathlen -= cnp->cn_namelen; 489 ndp->ni_next = cp; 490 /* 491 * If this component is followed by a slash, then move the pointer to 492 * the next component forward, and remember that this component must be 493 * a directory. 494 */ 495 if (*cp == '/') { 496 do { 497 cp++; 498 } while (*cp == '/'); 499 slashes = cp - ndp->ni_next; 500 ndp->ni_pathlen -= slashes; 501 ndp->ni_next = cp; 502 cnp->cn_flags |= REQUIREDIR; 503 } else { 504 slashes = 0; 505 cnp->cn_flags &= ~REQUIREDIR; 506 } 507 /* 508 * We do special processing on the last component, whether or not it's 509 * a directory. Cache all intervening lookups, but not the final one. 510 */ 511 if (*cp == '\0') { 512 if (docache) 513 cnp->cn_flags |= MAKEENTRY; 514 else 515 cnp->cn_flags &= ~MAKEENTRY; 516 cnp->cn_flags |= ISLASTCN; 517 } else { 518 cnp->cn_flags |= MAKEENTRY; 519 cnp->cn_flags &= ~ISLASTCN; 520 } 521 if (cnp->cn_namelen == 2 && 522 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 523 cnp->cn_flags |= ISDOTDOT; 524 else 525 cnp->cn_flags &= ~ISDOTDOT; 526 527 /* 528 * Handle "..": two special cases. 529 * 1. If at root directory (e.g. after chroot) 530 * or at absolute root directory 531 * then ignore it so can't get out. 532 * 2. If this vnode is the root of a mounted 533 * filesystem, then replace it with the 534 * vnode which was mounted on so we take the 535 * .. in the other file system. 536 */ 537 if (cnp->cn_flags & ISDOTDOT) { 538 for (;;) { 539 if (dp == ndp->ni_rootdir || dp == rootvnode) { 540 ndp->ni_dvp = dp; 541 ndp->ni_vp = dp; 542 vref(dp); 543 ndp->ni_unveil_match = NULL; 544 goto nextname; 545 } 546 if ((dp->v_flag & VROOT) == 0 || 547 (cnp->cn_flags & NOCROSSMOUNT)) 548 break; 549 tdp = dp; 550 dp = dp->v_mount->mnt_vnodecovered; 551 vput(tdp); 552 vref(dp); 553 unveil_check_component(curproc, ndp, dp); 554 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 555 } 556 } 557 558 /* 559 * We now have a segment name to search for, and a directory to search. 560 */ 561 ndp->ni_dvp = dp; 562 ndp->ni_vp = NULL; 563 cnp->cn_flags &= ~PDIRUNLOCK; 564 unveil_check_component(curproc, ndp, dp); 565 566 if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 567 #ifdef DIAGNOSTIC 568 if (ndp->ni_vp != NULL) 569 panic("leaf should be empty"); 570 #endif 571 #ifdef NAMEI_DIAGNOSTIC 572 printf("not found\n"); 573 #endif 574 /* 575 * Allow for unveiling a file in a directory which we cannot 576 * create ourselves. 577 */ 578 if (ndp->ni_pledge == PLEDGE_UNVEIL && 579 (error == EPERM || error == EACCES || error == EROFS)) 580 error = EJUSTRETURN; 581 582 if (error != EJUSTRETURN) 583 goto bad; 584 /* 585 * If this was not the last component, or there were trailing 586 * slashes, then the name must exist. 587 */ 588 if (cnp->cn_flags & REQUIREDIR) { 589 error = ENOENT; 590 goto bad; 591 } 592 /* 593 * If creating and at end of pathname, then can consider 594 * allowing file to be created. Check for a read only 595 * filesystem and disallow this unless we are unveil'ing 596 */ 597 if (ndp->ni_pledge != PLEDGE_UNVEIL && (rdonly || 598 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 599 error = EROFS; 600 goto bad; 601 } 602 /* 603 * We return with ni_vp NULL to indicate that the entry 604 * doesn't currently exist, leaving a pointer to the 605 * (possibly locked) directory inode in ndp->ni_dvp. 606 */ 607 if (cnp->cn_flags & SAVESTART) { 608 ndp->ni_startdir = ndp->ni_dvp; 609 vref(ndp->ni_startdir); 610 } 611 return (0); 612 } 613 #ifdef NAMEI_DIAGNOSTIC 614 printf("found\n"); 615 #endif 616 617 /* 618 * Take into account any additional components consumed by the 619 * underlying filesystem. This will include any trailing slashes after 620 * the last component consumed. 621 */ 622 if (cnp->cn_consume > 0) { 623 if (cnp->cn_consume >= slashes) { 624 cnp->cn_flags &= ~REQUIREDIR; 625 } 626 627 ndp->ni_pathlen -= cnp->cn_consume - slashes; 628 ndp->ni_next += cnp->cn_consume - slashes; 629 cnp->cn_consume = 0; 630 if (ndp->ni_next[0] == '\0') 631 cnp->cn_flags |= ISLASTCN; 632 } 633 634 dp = ndp->ni_vp; 635 /* 636 * Check to see if the vnode has been mounted on; 637 * if so find the root of the mounted file system. 638 */ 639 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 640 (cnp->cn_flags & NOCROSSMOUNT) == 0) { 641 if (vfs_busy(mp, VB_READ|VB_WAIT)) 642 continue; 643 VOP_UNLOCK(dp); 644 error = VFS_ROOT(mp, &tdp); 645 vfs_unbusy(mp); 646 if (error) { 647 dpunlocked = 1; 648 goto bad2; 649 } 650 vrele(dp); 651 ndp->ni_vp = dp = tdp; 652 } 653 654 /* 655 * Check for symbolic link. Back up over any slashes that we skipped, 656 * as we will need them again. 657 */ 658 if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) { 659 ndp->ni_pathlen += slashes; 660 ndp->ni_next -= slashes; 661 cnp->cn_flags |= ISSYMLINK; 662 return (0); 663 } 664 665 /* 666 * Check for directory, if the component was followed by a series of 667 * slashes. 668 */ 669 if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { 670 error = ENOTDIR; 671 goto bad2; 672 } 673 674 nextname: 675 /* 676 * Not a symbolic link. If this was not the last component, then 677 * continue at the next component, else return. 678 */ 679 if (!(cnp->cn_flags & ISLASTCN)) { 680 cnp->cn_nameptr = ndp->ni_next; 681 vrele(ndp->ni_dvp); 682 goto dirloop; 683 } 684 685 terminal: 686 /* 687 * Check for read-only file systems. 688 */ 689 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 690 /* 691 * Disallow directory write attempts on read-only 692 * file systems. 693 */ 694 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 695 (wantparent && 696 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 697 error = EROFS; 698 goto bad2; 699 } 700 } 701 if (ndp->ni_dvp != NULL) { 702 if (cnp->cn_flags & SAVESTART) { 703 ndp->ni_startdir = ndp->ni_dvp; 704 vref(ndp->ni_startdir); 705 } 706 if (!wantparent) 707 vrele(ndp->ni_dvp); 708 } 709 if ((cnp->cn_flags & LOCKLEAF) == 0) 710 VOP_UNLOCK(dp); 711 return (0); 712 713 bad2: 714 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) && 715 ((cnp->cn_flags & PDIRUNLOCK) == 0)) 716 VOP_UNLOCK(ndp->ni_dvp); 717 vrele(ndp->ni_dvp); 718 bad: 719 if (dpunlocked) 720 vrele(dp); 721 else 722 vput(dp); 723 ndp->ni_vp = NULL; 724 return (error); 725 } 726 727 /* 728 * Reacquire a path name component. 729 */ 730 int 731 vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) 732 { 733 struct vnode *dp = NULL; /* the directory we are searching */ 734 int wantparent; /* 1 => wantparent or lockparent flag */ 735 int rdonly; /* lookup read-only flag bit */ 736 int error = 0; 737 #ifdef NAMEI_DIAGNOSTIC 738 char *cp; /* DEBUG: check name ptr/len */ 739 #endif 740 741 /* 742 * Setup: break out flag bits into variables. 743 */ 744 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 745 rdonly = cnp->cn_flags & RDONLY; 746 cnp->cn_flags &= ~ISSYMLINK; 747 dp = dvp; 748 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 749 750 /* dirloop: */ 751 /* 752 * Search a new directory. 753 * 754 * The last component of the filename is left accessible via 755 * cnp->cn_nameptr for callers that need the name. Callers needing 756 * the name set the SAVENAME flag. When done, they assume 757 * responsibility for freeing the pathname buffer. 758 */ 759 760 #ifdef NAMEI_DIAGNOSTIC 761 /* XXX: Figure out the length of the last component. */ 762 cp = cnp->cn_nameptr; 763 while (*cp && (*cp != '/')) { 764 cp++; 765 } 766 if (cnp->cn_namelen != cp - cnp->cn_nameptr) 767 panic("relookup: bad len"); 768 if (*cp != 0) 769 panic("relookup: not last component"); 770 printf("{%s}: ", cnp->cn_nameptr); 771 #endif 772 773 /* 774 * Check for degenerate name (e.g. / or "") 775 * which is a way of talking about a directory, 776 * e.g. like "/." or ".". 777 */ 778 if (cnp->cn_nameptr[0] == '\0') 779 panic("relookup: null name"); 780 781 if (cnp->cn_flags & ISDOTDOT) 782 panic ("relookup: lookup on dot-dot"); 783 784 /* 785 * We now have a segment name to search for, and a directory to search. 786 */ 787 if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 788 #ifdef DIAGNOSTIC 789 if (*vpp != NULL) 790 panic("leaf should be empty"); 791 #endif 792 if (error != EJUSTRETURN) 793 goto bad; 794 /* 795 * If creating and at end of pathname, then can consider 796 * allowing file to be created. 797 */ 798 if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) { 799 error = EROFS; 800 goto bad; 801 } 802 /* ASSERT(dvp == ndp->ni_startdir) */ 803 if (cnp->cn_flags & SAVESTART) 804 vref(dvp); 805 /* 806 * We return with ni_vp NULL to indicate that the entry 807 * doesn't currently exist, leaving a pointer to the 808 * (possibly locked) directory inode in ndp->ni_dvp. 809 */ 810 return (0); 811 } 812 dp = *vpp; 813 814 #ifdef DIAGNOSTIC 815 /* 816 * Check for symbolic link 817 */ 818 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW)) 819 panic ("relookup: symlink found."); 820 #endif 821 822 /* 823 * Check for read-only file systems. 824 */ 825 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 826 /* 827 * Disallow directory write attempts on read-only 828 * file systems. 829 */ 830 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 831 (wantparent && 832 (dvp->v_mount->mnt_flag & MNT_RDONLY))) { 833 error = EROFS; 834 goto bad2; 835 } 836 } 837 /* ASSERT(dvp == ndp->ni_startdir) */ 838 if (cnp->cn_flags & SAVESTART) 839 vref(dvp); 840 if (!wantparent) 841 vrele(dvp); 842 if ((cnp->cn_flags & LOCKLEAF) == 0) 843 VOP_UNLOCK(dp); 844 return (0); 845 846 bad2: 847 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 848 VOP_UNLOCK(dvp); 849 vrele(dvp); 850 bad: 851 vput(dp); 852 *vpp = NULL; 853 return (error); 854 } 855 856 857