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