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