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