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