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