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