|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1989, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * (c) UNIX System Laboratories, Inc. ! 30: * All or some portions of this file are derived from material licensed ! 31: * to the University of California by American Telephone and Telegraph ! 32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 33: * the permission of UNIX System Laboratories, Inc. ! 34: * ! 35: * Redistribution and use in source and binary forms, with or without ! 36: * modification, are permitted provided that the following conditions ! 37: * are met: ! 38: * 1. Redistributions of source code must retain the above copyright ! 39: * notice, this list of conditions and the following disclaimer. ! 40: * 2. Redistributions in binary form must reproduce the above copyright ! 41: * notice, this list of conditions and the following disclaimer in the ! 42: * documentation and/or other materials provided with the distribution. ! 43: * 3. All advertising materials mentioning features or use of this software ! 44: * must display the following acknowledgement: ! 45: * This product includes software developed by the University of ! 46: * California, Berkeley and its contributors. ! 47: * 4. Neither the name of the University nor the names of its contributors ! 48: * may be used to endorse or promote products derived from this software ! 49: * without specific prior written permission. ! 50: * ! 51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 61: * SUCH DAMAGE. ! 62: * ! 63: * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 ! 64: */ ! 65: ! 66: #include <sys/param.h> ! 67: #include <sys/syslimits.h> ! 68: #include <sys/time.h> ! 69: #include <sys/namei.h> ! 70: #include <sys/vm.h> ! 71: #include <sys/vnode.h> ! 72: #include <sys/mount.h> ! 73: #include <sys/errno.h> ! 74: #include <sys/malloc.h> ! 75: #include <sys/filedesc.h> ! 76: #include <sys/proc.h> ! 77: ! 78: #if KTRACE ! 79: #include <sys/ktrace.h> ! 80: #endif ! 81: ! 82: /* ! 83: * Convert a pathname into a pointer to a locked inode. ! 84: * ! 85: * The FOLLOW flag is set when symbolic links are to be followed ! 86: * when they occur at the end of the name translation process. ! 87: * Symbolic links are always followed for all other pathname ! 88: * components other than the last. ! 89: * ! 90: * The segflg defines whether the name is to be copied from user ! 91: * space or kernel space. ! 92: * ! 93: * Overall outline of namei: ! 94: * ! 95: * copy in name ! 96: * get starting directory ! 97: * while (!done && !error) { ! 98: * call lookup to search path. ! 99: * if symbolic link, massage name in buffer and continue ! 100: * } ! 101: */ ! 102: int ! 103: namei(ndp) ! 104: register struct nameidata *ndp; ! 105: { ! 106: register struct filedesc *fdp; /* pointer to file descriptor state */ ! 107: register char *cp; /* pointer into pathname argument */ ! 108: register struct vnode *dp; /* the directory we are searching */ ! 109: struct iovec aiov; /* uio for reading symbolic links */ ! 110: struct uio auio; ! 111: int error, linklen; ! 112: struct componentname *cnp = &ndp->ni_cnd; ! 113: struct proc *p = cnp->cn_proc; ! 114: ! 115: ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; ! 116: #if DIAGNOSTIC ! 117: if (!cnp->cn_cred || !cnp->cn_proc) ! 118: panic ("namei: bad cred/proc"); ! 119: if (cnp->cn_nameiop & (~OPMASK)) ! 120: panic ("namei: nameiop contaminated with flags"); ! 121: if (cnp->cn_flags & OPMASK) ! 122: panic ("namei: flags contaminated with nameiops"); ! 123: #endif ! 124: fdp = cnp->cn_proc->p_fd; ! 125: ! 126: /* ! 127: * Get a buffer for the name to be translated, and copy the ! 128: * name into the buffer. ! 129: */ ! 130: if ((cnp->cn_flags & HASBUF) == 0) { ! 131: MALLOC_ZONE(cnp->cn_pnbuf, caddr_t, ! 132: MAXPATHLEN, M_NAMEI, M_WAITOK); ! 133: cnp->cn_pnlen = MAXPATHLEN; ! 134: } ! 135: if (ndp->ni_segflg == UIO_SYSSPACE) ! 136: error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, ! 137: MAXPATHLEN, &ndp->ni_pathlen); ! 138: else ! 139: error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, ! 140: MAXPATHLEN, &ndp->ni_pathlen); ! 141: if (error) { ! 142: _FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 143: ndp->ni_vp = NULL; ! 144: return (error); ! 145: } ! 146: ndp->ni_loopcnt = 0; ! 147: // kprintf("namei: path =%s\n", cnp->cn_pnbuf); ! 148: #if KTRACE ! 149: if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) ! 150: ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); ! 151: #endif ! 152: ! 153: /* ! 154: * Get starting point for the translation. ! 155: */ ! 156: if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) ! 157: ndp->ni_rootdir = rootvnode; ! 158: dp = fdp->fd_cdir; ! 159: VREF(dp); ! 160: for (;;) { ! 161: /* ! 162: * Check if root directory should replace current directory. ! 163: * Done at start of translation and after symbolic link. ! 164: */ ! 165: cnp->cn_nameptr = cnp->cn_pnbuf; ! 166: if (*(cnp->cn_nameptr) == '/') { ! 167: vrele(dp); ! 168: while (*(cnp->cn_nameptr) == '/') { ! 169: cnp->cn_nameptr++; ! 170: ndp->ni_pathlen--; ! 171: } ! 172: dp = ndp->ni_rootdir; ! 173: VREF(dp); ! 174: } ! 175: ndp->ni_startdir = dp; ! 176: if (error = lookup(ndp)) { ! 177: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 178: return (error); ! 179: } ! 180: /* ! 181: * Check for symbolic link ! 182: */ ! 183: if ((cnp->cn_flags & ISSYMLINK) == 0) { ! 184: if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { ! 185: FREE_ZONE(cnp->cn_pnbuf, ! 186: cnp->cn_pnlen, M_NAMEI); ! 187: } else { ! 188: cnp->cn_flags |= HASBUF; ! 189: } ! 190: return (0); ! 191: } ! 192: if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) ! 193: VOP_UNLOCK(ndp->ni_dvp, 0, p); ! 194: if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { ! 195: error = ELOOP; ! 196: break; ! 197: } ! 198: if (ndp->ni_pathlen > 1) { ! 199: MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); ! 200: } else { ! 201: cp = cnp->cn_pnbuf; ! 202: } ! 203: aiov.iov_base = cp; ! 204: aiov.iov_len = MAXPATHLEN; ! 205: auio.uio_iov = &aiov; ! 206: auio.uio_iovcnt = 1; ! 207: auio.uio_offset = 0; ! 208: auio.uio_rw = UIO_READ; ! 209: auio.uio_segflg = UIO_SYSSPACE; ! 210: auio.uio_procp = (struct proc *)0; ! 211: auio.uio_resid = MAXPATHLEN; ! 212: if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) { ! 213: if (ndp->ni_pathlen > 1) ! 214: _FREE_ZONE(cp, MAXPATHLEN, M_NAMEI); ! 215: break; ! 216: } ! 217: linklen = MAXPATHLEN - auio.uio_resid; ! 218: if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { ! 219: if (ndp->ni_pathlen > 1) ! 220: _FREE_ZONE(cp, MAXPATHLEN, M_NAMEI); ! 221: error = ENAMETOOLONG; ! 222: break; ! 223: } ! 224: if (ndp->ni_pathlen > 1) { ! 225: bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); ! 226: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 227: cnp->cn_pnbuf = cp; ! 228: cnp->cn_pnlen = MAXPATHLEN; ! 229: } else ! 230: cnp->cn_pnbuf[linklen] = '\0'; ! 231: ndp->ni_pathlen += linklen; ! 232: vput(ndp->ni_vp); ! 233: dp = ndp->ni_dvp; ! 234: } ! 235: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 236: vrele(ndp->ni_dvp); ! 237: vput(ndp->ni_vp); ! 238: ndp->ni_vp = NULL; ! 239: return (error); ! 240: } ! 241: ! 242: /* ! 243: * Search a pathname. ! 244: * This is a very central and rather complicated routine. ! 245: * ! 246: * The pathname is pointed to by ni_ptr and is of length ni_pathlen. ! 247: * The starting directory is taken from ni_startdir. The pathname is ! 248: * descended until done, or a symbolic link is encountered. The variable ! 249: * ni_more is clear if the path is completed; it is set to one if a ! 250: * symbolic link needing interpretation is encountered. ! 251: * ! 252: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on ! 253: * whether the name is to be looked up, created, renamed, or deleted. ! 254: * When CREATE, RENAME, or DELETE is specified, information usable in ! 255: * creating, renaming, or deleting a directory entry may be calculated. ! 256: * If flag has LOCKPARENT or'ed into it, the parent directory is returned ! 257: * locked. If flag has WANTPARENT or'ed into it, the parent directory is ! 258: * returned unlocked. Otherwise the parent directory is not returned. If ! 259: * the target of the pathname exists and LOCKLEAF is or'ed into the flag ! 260: * the target is returned locked, otherwise it is returned unlocked. ! 261: * When creating or renaming and LOCKPARENT is specified, the target may not ! 262: * be ".". When deleting and LOCKPARENT is specified, the target may be ".". ! 263: * ! 264: * Overall outline of lookup: ! 265: * ! 266: * dirloop: ! 267: * identify next component of name at ndp->ni_ptr ! 268: * handle degenerate case where name is null string ! 269: * if .. and crossing mount points and on mounted filesys, find parent ! 270: * call VOP_LOOKUP routine for next component name ! 271: * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set ! 272: * component vnode returned in ni_vp (if it exists), locked. ! 273: * if result vnode is mounted on and crossing mount points, ! 274: * find mounted on vnode ! 275: * if more components of name, do next level at dirloop ! 276: * return the answer in ni_vp, locked if LOCKLEAF set ! 277: * if LOCKPARENT set, return locked parent in ni_dvp ! 278: * if WANTPARENT set, return unlocked parent in ni_dvp ! 279: */ ! 280: int ! 281: lookup(ndp) ! 282: register struct nameidata *ndp; ! 283: { ! 284: register char *cp; /* pointer into pathname argument */ ! 285: register struct vnode *dp = 0; /* the directory we are searching */ ! 286: struct vnode *tdp; /* saved dp */ ! 287: struct mount *mp; /* mount table entry */ ! 288: int docache; /* == 0 do not cache last component */ ! 289: int wantparent; /* 1 => wantparent or lockparent flag */ ! 290: int rdonly; /* lookup read-only flag bit */ ! 291: int error = 0; ! 292: struct componentname *cnp = &ndp->ni_cnd; ! 293: struct proc *p = cnp->cn_proc; ! 294: int i; ! 295: ! 296: /* ! 297: * Setup: break out flag bits into variables. ! 298: */ ! 299: wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); ! 300: docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; ! 301: if (cnp->cn_nameiop == DELETE || ! 302: (wantparent && cnp->cn_nameiop != CREATE)) ! 303: docache = 0; ! 304: rdonly = cnp->cn_flags & RDONLY; ! 305: ndp->ni_dvp = NULL; ! 306: cnp->cn_flags &= ~ISSYMLINK; ! 307: dp = ndp->ni_startdir; ! 308: ndp->ni_startdir = NULLVP; ! 309: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); ! 310: ! 311: dirloop: ! 312: /* ! 313: * Search a new directory. ! 314: * ! 315: * The cn_hash value is for use by vfs_cache. ! 316: * The last component of the filename is left accessible via ! 317: * cnp->cn_nameptr for callers that need the name. Callers needing ! 318: * the name set the SAVENAME flag. When done, they assume ! 319: * responsibility for freeing the pathname buffer. ! 320: */ ! 321: cnp->cn_consume = 0; ! 322: cnp->cn_hash = 0; ! 323: for (cp = cnp->cn_nameptr, i=1; *cp != 0 && *cp != '/'; i++, cp++) ! 324: cnp->cn_hash += (unsigned char)*cp * i; ! 325: cnp->cn_namelen = cp - cnp->cn_nameptr; ! 326: if (cnp->cn_namelen > NAME_MAX) { ! 327: error = ENAMETOOLONG; ! 328: goto bad; ! 329: } ! 330: #ifdef NAMEI_DIAGNOSTIC ! 331: { char c = *cp; ! 332: *cp = '\0'; ! 333: printf("{%s}: ", cnp->cn_nameptr); ! 334: *cp = c; } ! 335: #endif ! 336: ndp->ni_pathlen -= cnp->cn_namelen; ! 337: ndp->ni_next = cp; ! 338: cnp->cn_flags |= MAKEENTRY; ! 339: if (*cp == '\0' && docache == 0) ! 340: cnp->cn_flags &= ~MAKEENTRY; ! 341: if (cnp->cn_namelen == 2 && ! 342: cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') ! 343: cnp->cn_flags |= ISDOTDOT; ! 344: else ! 345: cnp->cn_flags &= ~ISDOTDOT; ! 346: if (*ndp->ni_next == 0) ! 347: cnp->cn_flags |= ISLASTCN; ! 348: else ! 349: cnp->cn_flags &= ~ISLASTCN; ! 350: ! 351: ! 352: /* ! 353: * Check for degenerate name (e.g. / or "") ! 354: * which is a way of talking about a directory, ! 355: * e.g. like "/." or ".". ! 356: */ ! 357: if (cnp->cn_nameptr[0] == '\0') { ! 358: if (dp->v_type != VDIR) { ! 359: error = ENOTDIR; ! 360: goto bad; ! 361: } ! 362: if (cnp->cn_nameiop != LOOKUP) { ! 363: error = EISDIR; ! 364: goto bad; ! 365: } ! 366: if (wantparent) { ! 367: ndp->ni_dvp = dp; ! 368: VREF(dp); ! 369: } ! 370: ndp->ni_vp = dp; ! 371: if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) ! 372: VOP_UNLOCK(dp, 0, p); ! 373: if (cnp->cn_flags & SAVESTART) ! 374: panic("lookup: SAVESTART"); ! 375: return (0); ! 376: } ! 377: ! 378: /* ! 379: * Handle "..": two special cases. ! 380: * 1. If at root directory (e.g. after chroot) ! 381: * or at absolute root directory ! 382: * then ignore it so can't get out. ! 383: * 2. If this vnode is the root of a mounted ! 384: * filesystem, then replace it with the ! 385: * vnode which was mounted on so we take the ! 386: * .. in the other file system. ! 387: */ ! 388: if (cnp->cn_flags & ISDOTDOT) { ! 389: for (;;) { ! 390: if (dp == ndp->ni_rootdir || dp == rootvnode) { ! 391: ndp->ni_dvp = dp; ! 392: ndp->ni_vp = dp; ! 393: VREF(dp); ! 394: goto nextname; ! 395: } ! 396: if ((dp->v_flag & VROOT) == 0 || ! 397: (cnp->cn_flags & NOCROSSMOUNT)) ! 398: break; ! 399: tdp = dp; ! 400: dp = dp->v_mount->mnt_vnodecovered; ! 401: vput(tdp); ! 402: VREF(dp); ! 403: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); ! 404: } ! 405: } ! 406: ! 407: /* ! 408: * We now have a segment name to search for, and a directory to search. ! 409: */ ! 410: unionlookup: ! 411: ndp->ni_dvp = dp; ! 412: ndp->ni_vp = NULL; ! 413: if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { ! 414: #if DIAGNOSTIC ! 415: if (ndp->ni_vp != NULL) ! 416: panic("leaf should be empty"); ! 417: #endif ! 418: #ifdef NAMEI_DIAGNOSTIC ! 419: printf("not found\n"); ! 420: #endif ! 421: if ((error == ENOENT) && ! 422: (dp->v_flag & VROOT) && ! 423: (dp->v_mount->mnt_flag & MNT_UNION)) { ! 424: tdp = dp; ! 425: dp = dp->v_mount->mnt_vnodecovered; ! 426: vput(tdp); ! 427: VREF(dp); ! 428: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); ! 429: goto unionlookup; ! 430: } ! 431: ! 432: if (error != EJUSTRETURN) ! 433: goto bad; ! 434: /* ! 435: * If creating and at end of pathname, then can consider ! 436: * allowing file to be created. ! 437: */ ! 438: if (rdonly) { ! 439: error = EROFS; ! 440: goto bad; ! 441: } ! 442: /* ! 443: * We return with ni_vp NULL to indicate that the entry ! 444: * doesn't currently exist, leaving a pointer to the ! 445: * (possibly locked) directory inode in ndp->ni_dvp. ! 446: */ ! 447: if (cnp->cn_flags & SAVESTART) { ! 448: ndp->ni_startdir = ndp->ni_dvp; ! 449: VREF(ndp->ni_startdir); ! 450: } ! 451: return (0); ! 452: } ! 453: #ifdef NAMEI_DIAGNOSTIC ! 454: printf("found\n"); ! 455: #endif ! 456: ! 457: /* ! 458: * Take into account any additional components consumed by ! 459: * the underlying filesystem. ! 460: */ ! 461: if (cnp->cn_consume > 0) { ! 462: cnp->cn_nameptr += cnp->cn_consume; ! 463: ndp->ni_next += cnp->cn_consume; ! 464: ndp->ni_pathlen -= cnp->cn_consume; ! 465: cnp->cn_consume = 0; ! 466: } ! 467: ! 468: dp = ndp->ni_vp; ! 469: /* ! 470: * Check to see if the vnode has been mounted on; ! 471: * if so find the root of the mounted file system. ! 472: */ ! 473: while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && ! 474: (cnp->cn_flags & NOCROSSMOUNT) == 0) { ! 475: if (vfs_busy(mp, 0, 0, p)) ! 476: continue; ! 477: error = VFS_ROOT(mp, &tdp); ! 478: vfs_unbusy(mp, p); ! 479: if (error) ! 480: goto bad2; ! 481: vput(dp); ! 482: ndp->ni_vp = dp = tdp; ! 483: } ! 484: ! 485: /* ! 486: * Check for symbolic link ! 487: */ ! 488: if ((dp->v_type == VLNK) && ! 489: ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { ! 490: cnp->cn_flags |= ISSYMLINK; ! 491: return (0); ! 492: } ! 493: ! 494: nextname: ! 495: /* ! 496: * Not a symbolic link. If more pathname, ! 497: * continue at next component, else return. ! 498: */ ! 499: if (*ndp->ni_next == '/') { ! 500: cnp->cn_nameptr = ndp->ni_next; ! 501: while (*cnp->cn_nameptr == '/') { ! 502: cnp->cn_nameptr++; ! 503: ndp->ni_pathlen--; ! 504: } ! 505: vrele(ndp->ni_dvp); ! 506: goto dirloop; ! 507: } ! 508: /* ! 509: * Disallow directory write attempts on read-only file systems. ! 510: */ ! 511: if (rdonly && ! 512: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { ! 513: error = EROFS; ! 514: goto bad2; ! 515: } ! 516: if (cnp->cn_flags & SAVESTART) { ! 517: ndp->ni_startdir = ndp->ni_dvp; ! 518: VREF(ndp->ni_startdir); ! 519: } ! 520: if (!wantparent) ! 521: vrele(ndp->ni_dvp); ! 522: if ((cnp->cn_flags & LOCKLEAF) == 0) ! 523: VOP_UNLOCK(dp, 0, p); ! 524: return (0); ! 525: ! 526: bad2: ! 527: if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') ! 528: VOP_UNLOCK(ndp->ni_dvp, 0, p); ! 529: vrele(ndp->ni_dvp); ! 530: bad: ! 531: vput(dp); ! 532: ndp->ni_vp = NULL; ! 533: return (error); ! 534: } ! 535: ! 536: /* ! 537: * relookup - lookup a path name component ! 538: * Used by lookup to re-aquire things. ! 539: */ ! 540: int ! 541: relookup(dvp, vpp, cnp) ! 542: struct vnode *dvp, **vpp; ! 543: struct componentname *cnp; ! 544: { ! 545: struct proc *p = cnp->cn_proc; ! 546: struct vnode *dp = 0; /* the directory we are searching */ ! 547: int docache; /* == 0 do not cache last component */ ! 548: int wantparent; /* 1 => wantparent or lockparent flag */ ! 549: int rdonly; /* lookup read-only flag bit */ ! 550: int error = 0; ! 551: #ifdef NAMEI_DIAGNOSTIC ! 552: int newhash; /* DEBUG: check name hash */ ! 553: char *cp; /* DEBUG: check name ptr/len */ ! 554: #endif ! 555: ! 556: /* ! 557: * Setup: break out flag bits into variables. ! 558: */ ! 559: wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); ! 560: docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; ! 561: if (cnp->cn_nameiop == DELETE || ! 562: (wantparent && cnp->cn_nameiop != CREATE)) ! 563: docache = 0; ! 564: rdonly = cnp->cn_flags & RDONLY; ! 565: cnp->cn_flags &= ~ISSYMLINK; ! 566: dp = dvp; ! 567: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); ! 568: ! 569: /* dirloop: */ ! 570: /* ! 571: * Search a new directory. ! 572: * ! 573: * The cn_hash value is for use by vfs_cache. ! 574: * The last component of the filename is left accessible via ! 575: * cnp->cn_nameptr for callers that need the name. Callers needing ! 576: * the name set the SAVENAME flag. When done, they assume ! 577: * responsibility for freeing the pathname buffer. ! 578: */ ! 579: #ifdef NAMEI_DIAGNOSTIC ! 580: for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) ! 581: newhash += (unsigned char)*cp; ! 582: if (newhash != cnp->cn_hash) ! 583: panic("relookup: bad hash"); ! 584: if (cnp->cn_namelen != cp - cnp->cn_nameptr) ! 585: panic ("relookup: bad len"); ! 586: if (*cp != 0) ! 587: panic("relookup: not last component"); ! 588: printf("{%s}: ", cnp->cn_nameptr); ! 589: #endif ! 590: ! 591: /* ! 592: * Check for degenerate name (e.g. / or "") ! 593: * which is a way of talking about a directory, ! 594: * e.g. like "/." or ".". ! 595: */ ! 596: if (cnp->cn_nameptr[0] == '\0') { ! 597: if (cnp->cn_nameiop != LOOKUP || wantparent) { ! 598: error = EISDIR; ! 599: goto bad; ! 600: } ! 601: if (dp->v_type != VDIR) { ! 602: error = ENOTDIR; ! 603: goto bad; ! 604: } ! 605: if (!(cnp->cn_flags & LOCKLEAF)) ! 606: VOP_UNLOCK(dp, 0, p); ! 607: *vpp = dp; ! 608: if (cnp->cn_flags & SAVESTART) ! 609: panic("lookup: SAVESTART"); ! 610: return (0); ! 611: } ! 612: ! 613: if (cnp->cn_flags & ISDOTDOT) ! 614: panic ("relookup: lookup on dot-dot"); ! 615: ! 616: /* ! 617: * We now have a segment name to search for, and a directory to search. ! 618: */ ! 619: if (error = VOP_LOOKUP(dp, vpp, cnp)) { ! 620: #if DIAGNOSTIC ! 621: if (*vpp != NULL) ! 622: panic("leaf should be empty"); ! 623: #endif ! 624: if (error != EJUSTRETURN) ! 625: goto bad; ! 626: /* ! 627: * If creating and at end of pathname, then can consider ! 628: * allowing file to be created. ! 629: */ ! 630: if (rdonly) { ! 631: error = EROFS; ! 632: goto bad; ! 633: } ! 634: /* ASSERT(dvp == ndp->ni_startdir) */ ! 635: if (cnp->cn_flags & SAVESTART) ! 636: VREF(dvp); ! 637: /* ! 638: * We return with ni_vp NULL to indicate that the entry ! 639: * doesn't currently exist, leaving a pointer to the ! 640: * (possibly locked) directory inode in ndp->ni_dvp. ! 641: */ ! 642: return (0); ! 643: } ! 644: dp = *vpp; ! 645: ! 646: #if DIAGNOSTIC ! 647: /* ! 648: * Check for symbolic link ! 649: */ ! 650: if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW)) ! 651: panic ("relookup: symlink found.\n"); ! 652: #endif ! 653: ! 654: /* ! 655: * Disallow directory write attempts on read-only file systems. ! 656: */ ! 657: if (rdonly && ! 658: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { ! 659: error = EROFS; ! 660: goto bad2; ! 661: } ! 662: /* ASSERT(dvp == ndp->ni_startdir) */ ! 663: if (cnp->cn_flags & SAVESTART) ! 664: VREF(dvp); ! 665: ! 666: if (!wantparent) ! 667: vrele(dvp); ! 668: if ((cnp->cn_flags & LOCKLEAF) == 0) ! 669: VOP_UNLOCK(dp, 0, p); ! 670: return (0); ! 671: ! 672: bad2: ! 673: if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) ! 674: VOP_UNLOCK(dvp, 0, p); ! 675: vrele(dvp); ! 676: bad: ! 677: vput(dp); ! 678: *vpp = NULL; ! 679: return (error); ! 680: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.