1 /* $OpenBSD: vfs_lookup.c,v 1.85 2021/07/16 07:59:38 claudio 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, dp); 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 * then ignore it so can't get out. 527 * 2. If this vnode is the root of a mounted 528 * filesystem, then replace it with the 529 * vnode which was mounted on so we take the 530 * .. in the other file system. 531 */ 532 if (cnp->cn_flags & ISDOTDOT) { 533 for (;;) { 534 if (dp == ndp->ni_rootdir || dp == rootvnode) { 535 ndp->ni_dvp = dp; 536 ndp->ni_vp = dp; 537 vref(dp); 538 ndp->ni_unveil_match = NULL; 539 goto nextname; 540 } 541 if ((dp->v_flag & VROOT) == 0 || 542 (cnp->cn_flags & NOCROSSMOUNT)) 543 break; 544 tdp = dp; 545 dp = dp->v_mount->mnt_vnodecovered; 546 vput(tdp); 547 vref(dp); 548 unveil_check_component(curproc, ndp, dp); 549 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 550 } 551 } 552 553 /* 554 * We now have a segment name to search for, and a directory to search. 555 */ 556 ndp->ni_dvp = dp; 557 ndp->ni_vp = NULL; 558 cnp->cn_flags &= ~PDIRUNLOCK; 559 unveil_check_component(curproc, ndp, dp); 560 561 if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { 562 #ifdef DIAGNOSTIC 563 if (ndp->ni_vp != NULL) 564 panic("leaf should be empty"); 565 #endif 566 #ifdef NAMEI_DIAGNOSTIC 567 printf("not found\n"); 568 #endif 569 /* 570 * Allow for unveiling a file in a directory which we cannot 571 * create ourselves. 572 */ 573 if (ndp->ni_pledge == PLEDGE_UNVEIL && 574 (error == EPERM || error == EACCES || error == EROFS)) 575 error = EJUSTRETURN; 576 577 if (error != EJUSTRETURN) 578 goto bad; 579 /* 580 * If this was not the last component, or there were trailing 581 * slashes, then the name must exist. 582 */ 583 if (cnp->cn_flags & REQUIREDIR) { 584 error = ENOENT; 585 goto bad; 586 } 587 /* 588 * If creating and at end of pathname, then can consider 589 * allowing file to be created. Check for a read only 590 * filesystem and disallow this unless we are unveil'ing 591 */ 592 if (ndp->ni_pledge != PLEDGE_UNVEIL && (rdonly || 593 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 594 error = EROFS; 595 goto bad; 596 } 597 /* 598 * We return with ni_vp NULL to indicate that the entry 599 * doesn't currently exist, leaving a pointer to the 600 * (possibly locked) directory inode in ndp->ni_dvp. 601 */ 602 if (cnp->cn_flags & SAVESTART) { 603 ndp->ni_startdir = ndp->ni_dvp; 604 vref(ndp->ni_startdir); 605 } 606 return (0); 607 } 608 #ifdef NAMEI_DIAGNOSTIC 609 printf("found\n"); 610 #endif 611 612 /* 613 * Take into account any additional components consumed by the 614 * underlying filesystem. This will include any trailing slashes after 615 * the last component consumed. 616 */ 617 if (cnp->cn_consume > 0) { 618 if (cnp->cn_consume >= slashes) { 619 cnp->cn_flags &= ~REQUIREDIR; 620 } 621 622 ndp->ni_pathlen -= cnp->cn_consume - slashes; 623 ndp->ni_next += cnp->cn_consume - slashes; 624 cnp->cn_consume = 0; 625 if (ndp->ni_next[0] == '\0') 626 cnp->cn_flags |= ISLASTCN; 627 } 628 629 dp = ndp->ni_vp; 630 /* 631 * Check to see if the vnode has been mounted on; 632 * if so find the root of the mounted file system. 633 */ 634 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 635 (cnp->cn_flags & NOCROSSMOUNT) == 0) { 636 if (vfs_busy(mp, VB_READ|VB_WAIT)) 637 continue; 638 VOP_UNLOCK(dp); 639 error = VFS_ROOT(mp, &tdp); 640 vfs_unbusy(mp); 641 if (error) { 642 dpunlocked = 1; 643 goto bad2; 644 } 645 vrele(dp); 646 ndp->ni_vp = dp = tdp; 647 } 648 649 /* 650 * Check for symbolic link. Back up over any slashes that we skipped, 651 * as we will need them again. 652 */ 653 if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) { 654 ndp->ni_pathlen += slashes; 655 ndp->ni_next -= slashes; 656 cnp->cn_flags |= ISSYMLINK; 657 return (0); 658 } 659 660 /* 661 * Check for directory, if the component was followed by a series of 662 * slashes. 663 */ 664 if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { 665 error = ENOTDIR; 666 goto bad2; 667 } 668 669 nextname: 670 /* 671 * Not a symbolic link. If this was not the last component, then 672 * continue at the next component, else return. 673 */ 674 if (!(cnp->cn_flags & ISLASTCN)) { 675 cnp->cn_nameptr = ndp->ni_next; 676 vrele(ndp->ni_dvp); 677 goto dirloop; 678 } 679 680 terminal: 681 /* 682 * Check for read-only file systems. 683 */ 684 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 685 /* 686 * Disallow directory write attempts on read-only 687 * file systems. 688 */ 689 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 690 (wantparent && 691 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 692 error = EROFS; 693 goto bad2; 694 } 695 } 696 if (ndp->ni_dvp != NULL) { 697 if (cnp->cn_flags & SAVESTART) { 698 ndp->ni_startdir = ndp->ni_dvp; 699 vref(ndp->ni_startdir); 700 } 701 if (!wantparent) 702 vrele(ndp->ni_dvp); 703 } 704 if ((cnp->cn_flags & LOCKLEAF) == 0) 705 VOP_UNLOCK(dp); 706 return (0); 707 708 bad2: 709 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) && 710 ((cnp->cn_flags & PDIRUNLOCK) == 0)) 711 VOP_UNLOCK(ndp->ni_dvp); 712 vrele(ndp->ni_dvp); 713 bad: 714 if (dpunlocked) 715 vrele(dp); 716 else 717 vput(dp); 718 ndp->ni_vp = NULL; 719 return (error); 720 } 721 722 /* 723 * Reacquire a path name component. 724 */ 725 int 726 vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) 727 { 728 struct vnode *dp = 0; /* the directory we are searching */ 729 int wantparent; /* 1 => wantparent or lockparent flag */ 730 int rdonly; /* lookup read-only flag bit */ 731 int error = 0; 732 #ifdef NAMEI_DIAGNOSTIC 733 char *cp; /* DEBUG: check name ptr/len */ 734 #endif 735 736 /* 737 * Setup: break out flag bits into variables. 738 */ 739 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); 740 rdonly = cnp->cn_flags & RDONLY; 741 cnp->cn_flags &= ~ISSYMLINK; 742 dp = dvp; 743 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 744 745 /* dirloop: */ 746 /* 747 * Search a new directory. 748 * 749 * The last component of the filename is left accessible via 750 * cnp->cn_nameptr for callers that need the name. Callers needing 751 * the name set the SAVENAME flag. When done, they assume 752 * responsibility for freeing the pathname buffer. 753 */ 754 755 #ifdef NAMEI_DIAGNOSTIC 756 /* XXX: Figure out the length of the last component. */ 757 cp = cnp->cn_nameptr; 758 while (*cp && (*cp != '/')) { 759 cp++; 760 } 761 if (cnp->cn_namelen != cp - cnp->cn_nameptr) 762 panic("relookup: bad len"); 763 if (*cp != 0) 764 panic("relookup: not last component"); 765 printf("{%s}: ", cnp->cn_nameptr); 766 #endif 767 768 /* 769 * Check for degenerate name (e.g. / or "") 770 * which is a way of talking about a directory, 771 * e.g. like "/." or ".". 772 */ 773 if (cnp->cn_nameptr[0] == '\0') 774 panic("relookup: null name"); 775 776 if (cnp->cn_flags & ISDOTDOT) 777 panic ("relookup: lookup on dot-dot"); 778 779 /* 780 * We now have a segment name to search for, and a directory to search. 781 */ 782 if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { 783 #ifdef DIAGNOSTIC 784 if (*vpp != NULL) 785 panic("leaf should be empty"); 786 #endif 787 if (error != EJUSTRETURN) 788 goto bad; 789 /* 790 * If creating and at end of pathname, then can consider 791 * allowing file to be created. 792 */ 793 if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) { 794 error = EROFS; 795 goto bad; 796 } 797 /* ASSERT(dvp == ndp->ni_startdir) */ 798 if (cnp->cn_flags & SAVESTART) 799 vref(dvp); 800 /* 801 * We return with ni_vp NULL to indicate that the entry 802 * doesn't currently exist, leaving a pointer to the 803 * (possibly locked) directory inode in ndp->ni_dvp. 804 */ 805 return (0); 806 } 807 dp = *vpp; 808 809 #ifdef DIAGNOSTIC 810 /* 811 * Check for symbolic link 812 */ 813 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW)) 814 panic ("relookup: symlink found."); 815 #endif 816 817 /* 818 * Check for read-only file systems. 819 */ 820 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 821 /* 822 * Disallow directory write attempts on read-only 823 * file systems. 824 */ 825 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 826 (wantparent && 827 (dvp->v_mount->mnt_flag & MNT_RDONLY))) { 828 error = EROFS; 829 goto bad2; 830 } 831 } 832 /* ASSERT(dvp == ndp->ni_startdir) */ 833 if (cnp->cn_flags & SAVESTART) 834 vref(dvp); 835 if (!wantparent) 836 vrele(dvp); 837 if ((cnp->cn_flags & LOCKLEAF) == 0) 838 VOP_UNLOCK(dp); 839 return (0); 840 841 bad2: 842 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) 843 VOP_UNLOCK(dvp); 844 vrele(dvp); 845 bad: 846 vput(dp); 847 *vpp = NULL; 848 return (error); 849 } 850 851 852