|
|
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: /* $NetBSD: cd9660_lookup.c,v 1.13 1994/12/24 15:30:03 cgd Exp $ */ ! 26: ! 27: /*- ! 28: * Copyright (c) 1989, 1993, 1994 ! 29: * The Regents of the University of California. All rights reserved. ! 30: * ! 31: * This code is derived from software contributed to Berkeley ! 32: * by Pace Willisson ([email protected]). The Rock Ridge Extension ! 33: * Support code is derived from software contributed to Berkeley ! 34: * by Atsushi Murai ([email protected]). ! 35: * ! 36: * Redistribution and use in source and binary forms, with or without ! 37: * modification, are permitted provided that the following conditions ! 38: * are met: ! 39: * 1. Redistributions of source code must retain the above copyright ! 40: * notice, this list of conditions and the following disclaimer. ! 41: * 2. Redistributions in binary form must reproduce the above copyright ! 42: * notice, this list of conditions and the following disclaimer in the ! 43: * documentation and/or other materials provided with the distribution. ! 44: * 3. All advertising materials mentioning features or use of this software ! 45: * must display the following acknowledgement: ! 46: * This product includes software developed by the University of ! 47: * California, Berkeley and its contributors. ! 48: * 4. Neither the name of the University nor the names of its contributors ! 49: * may be used to endorse or promote products derived from this software ! 50: * without specific prior written permission. ! 51: * ! 52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 62: * SUCH DAMAGE. ! 63: * ! 64: * from: @(#)ufs_lookup.c 7.33 (Berkeley) 5/19/91 ! 65: * ! 66: * @(#)cd9660_lookup.c 8.5 (Berkeley) 12/5/94 ! 67: */ ! 68: ! 69: #include <sys/param.h> ! 70: #include <sys/namei.h> ! 71: #include <sys/buf.h> ! 72: #include <sys/file.h> ! 73: #include <sys/vnode.h> ! 74: #include <sys/mount.h> ! 75: ! 76: #include <isofs/cd9660/iso.h> ! 77: #include <isofs/cd9660/cd9660_node.h> ! 78: #include <isofs/cd9660/iso_rrip.h> ! 79: #include <isofs/cd9660/cd9660_rrip.h> ! 80: ! 81: struct nchstats iso_nchstats; ! 82: ! 83: /* ! 84: * Convert a component of a pathname into a pointer to a locked inode. ! 85: * This is a very central and rather complicated routine. ! 86: * If the file system is not maintained in a strict tree hierarchy, ! 87: * this can result in a deadlock situation (see comments in code below). ! 88: * ! 89: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on ! 90: * whether the name is to be looked up, created, renamed, or deleted. ! 91: * When CREATE, RENAME, or DELETE is specified, information usable in ! 92: * creating, renaming, or deleting a directory entry may be calculated. ! 93: * If flag has LOCKPARENT or'ed into it and the target of the pathname ! 94: * exists, lookup returns both the target and its parent directory locked. ! 95: * When creating or renaming and LOCKPARENT is specified, the target may ! 96: * not be ".". When deleting and LOCKPARENT is specified, the target may ! 97: * be "."., but the caller must check to ensure it does an vrele and iput ! 98: * instead of two iputs. ! 99: * ! 100: * Overall outline of ufs_lookup: ! 101: * ! 102: * check accessibility of directory ! 103: * look for name in cache, if found, then if at end of path ! 104: * and deleting or creating, drop it, else return name ! 105: * search for name in directory, to found or notfound ! 106: * notfound: ! 107: * if creating, return locked directory, leaving info on available slots ! 108: * else return error ! 109: * found: ! 110: * if at end of path and deleting, return information to allow delete ! 111: * if at end of path and rewriting (RENAME and LOCKPARENT), lock target ! 112: * inode and return info to allow rewrite ! 113: * if not at end, add name to cache; if at end and neither creating ! 114: * nor deleting, add name to cache ! 115: * ! 116: * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. ! 117: */ ! 118: int ! 119: cd9660_lookup(ap) ! 120: struct vop_lookup_args /* { ! 121: struct vnode *a_dvp; ! 122: struct vnode **a_vpp; ! 123: struct componentname *a_cnp; ! 124: } */ *ap; ! 125: { ! 126: register struct vnode *vdp; /* vnode for directory being searched */ ! 127: register struct iso_node *dp; /* inode for directory being searched */ ! 128: register struct iso_mnt *imp; /* file system that directory is in */ ! 129: struct buf *bp; /* a buffer of directory entries */ ! 130: struct iso_directory_record *ep = NULL;/* the current directory entry */ ! 131: int entryoffsetinblock; /* offset of ep in bp's buffer */ ! 132: int saveoffset = 0; /* offset of last directory entry in dir */ ! 133: int numdirpasses; /* strategy for directory search */ ! 134: doff_t endsearch; /* offset to end directory search */ ! 135: struct vnode *pdp; /* saved dp during symlink work */ ! 136: struct vnode *tdp; /* returned by cd9660_vget_internal */ ! 137: u_long bmask; /* block offset mask */ ! 138: int lockparent; /* 1 => lockparent flag is set */ ! 139: int wantparent; /* 1 => wantparent or lockparent flag */ ! 140: int error; ! 141: ino_t ino = 0; ! 142: int reclen; ! 143: u_short namelen; ! 144: char altname[NAME_MAX]; ! 145: int res; ! 146: int assoc, len; ! 147: char *name; ! 148: struct vnode **vpp = ap->a_vpp; ! 149: struct componentname *cnp = ap->a_cnp; ! 150: struct ucred *cred = cnp->cn_cred; ! 151: int flags = cnp->cn_flags; ! 152: int nameiop = cnp->cn_nameiop; ! 153: struct proc *p = cnp->cn_proc; ! 154: int devBlockSize=0; ! 155: ! 156: bp = NULL; ! 157: *vpp = NULL; ! 158: vdp = ap->a_dvp; ! 159: dp = VTOI(vdp); ! 160: imp = dp->i_mnt; ! 161: lockparent = flags & LOCKPARENT; ! 162: wantparent = flags & (LOCKPARENT|WANTPARENT); ! 163: ! 164: /* ! 165: * Check accessiblity of directory. ! 166: */ ! 167: if (vdp->v_type != VDIR) ! 168: return (ENOTDIR); ! 169: if ( (error = VOP_ACCESS(vdp, VEXEC, cred, p)) ) ! 170: return (error); ! 171: ! 172: /* ! 173: * We now have a segment name to search for, and a directory to search. ! 174: * ! 175: * Before tediously performing a linear scan of the directory, ! 176: * check the name cache to see if the directory/name pair ! 177: * we are looking for is known already. ! 178: */ ! 179: if ( (error = cache_lookup(vdp, vpp, cnp)) ) { ! 180: int vpid; /* capability number of vnode */ ! 181: ! 182: if (error == ENOENT) ! 183: return (error); ! 184: #ifdef PARANOID ! 185: if ((vdp->v_flag & VROOT) && (flags & ISDOTDOT)) ! 186: panic("cd9660_lookup: .. through root"); ! 187: #endif ! 188: /* ! 189: * Get the next vnode in the path. ! 190: * See comment below starting `Step through' for ! 191: * an explaination of the locking protocol. ! 192: */ ! 193: pdp = vdp; ! 194: dp = VTOI(*vpp); ! 195: vdp = *vpp; ! 196: vpid = vdp->v_id; ! 197: if (pdp == vdp) { ! 198: VREF(vdp); ! 199: error = 0; ! 200: } else if (flags & ISDOTDOT) { ! 201: VOP_UNLOCK(pdp, 0, p); ! 202: error = vget(vdp, LK_EXCLUSIVE | LK_RETRY, p); ! 203: if (!error && lockparent && (flags & ISLASTCN)) ! 204: error = VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, p); ! 205: } else { ! 206: error = vget(vdp, LK_EXCLUSIVE | LK_RETRY, p); ! 207: if (!lockparent || error || !(flags & ISLASTCN)) ! 208: VOP_UNLOCK(pdp, 0, p); ! 209: } ! 210: /* ! 211: * Check that the capability number did not change ! 212: * while we were waiting for the lock. ! 213: */ ! 214: if (!error) { ! 215: if (vpid == vdp->v_id) ! 216: return (0); ! 217: vput(vdp); ! 218: if (lockparent && pdp != vdp && (flags & ISLASTCN)) ! 219: VOP_UNLOCK(pdp, 0, p); ! 220: } ! 221: if ( (error = VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, p)) ) ! 222: return (error); ! 223: vdp = pdp; ! 224: dp = VTOI(pdp); ! 225: *vpp = NULL; ! 226: } ! 227: ! 228: len = cnp->cn_namelen; ! 229: name = cnp->cn_nameptr; ! 230: /* ! 231: * A leading `=' means, we are looking for an associated file ! 232: */ ! 233: if ( (assoc = (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR)) ) { ! 234: len--; ! 235: name++; ! 236: } ! 237: ! 238: /* ! 239: * If there is cached information on a previous search of ! 240: * this directory, pick up where we last left off. ! 241: * We cache only lookups as these are the most common ! 242: * and have the greatest payoff. Caching CREATE has little ! 243: * benefit as it usually must search the entire directory ! 244: * to determine that the entry does not exist. Caching the ! 245: * location of the last DELETE or RENAME has not reduced ! 246: * profiling time and hence has been removed in the interest ! 247: * of simplicity. ! 248: */ ! 249: bmask = imp->im_bmask; ! 250: if (nameiop != LOOKUP || dp->i_diroff == 0 || ! 251: dp->i_diroff > dp->i_size) { ! 252: entryoffsetinblock = 0; ! 253: dp->i_offset = 0; ! 254: numdirpasses = 1; ! 255: } else { ! 256: dp->i_offset = dp->i_diroff; ! 257: if ((entryoffsetinblock = dp->i_offset & bmask) && ! 258: (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp))) ! 259: return (error); ! 260: numdirpasses = 2; ! 261: iso_nchstats.ncs_2passes++; ! 262: } ! 263: endsearch = dp->i_size; ! 264: ! 265: searchloop: ! 266: while (dp->i_offset < endsearch) { ! 267: /* ! 268: * If offset is on a block boundary, ! 269: * read the next directory block. ! 270: * Release previous if it exists. ! 271: */ ! 272: if ((dp->i_offset & bmask) == 0) { ! 273: if (bp != NULL) ! 274: brelse(bp); ! 275: if ( (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) ) ! 276: return (error); ! 277: entryoffsetinblock = 0; ! 278: } ! 279: /* ! 280: * Get pointer to next entry. ! 281: */ ! 282: ep = (struct iso_directory_record *) ! 283: ((char *)bp->b_data + entryoffsetinblock); ! 284: ! 285: reclen = isonum_711(ep->length); ! 286: if (reclen == 0) { ! 287: /* skip to next block, if any */ ! 288: dp->i_offset = ! 289: (dp->i_offset & ~bmask) + imp->logical_block_size; ! 290: continue; ! 291: } ! 292: ! 293: if (reclen < ISO_DIRECTORY_RECORD_SIZE) ! 294: /* illegal entry, stop */ ! 295: break; ! 296: ! 297: if (entryoffsetinblock + reclen > imp->logical_block_size) ! 298: /* entries are not allowed to cross boundaries */ ! 299: break; ! 300: ! 301: namelen = isonum_711(ep->name_len); ! 302: ! 303: if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen) ! 304: /* illegal entry, stop */ ! 305: break; ! 306: ! 307: /* ! 308: * Check for a name match. ! 309: */ ! 310: switch (imp->iso_ftype) { ! 311: default: ! 312: if ((!(isonum_711(ep->flags) & associatedBit)) == !assoc) { ! 313: if ((len == 1 ! 314: && *name == '.') ! 315: || (flags & ISDOTDOT)) { ! 316: if (namelen == 1 ! 317: && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) { ! 318: /* ! 319: * Save directory entry's inode number and ! 320: * release directory buffer. ! 321: */ ! 322: dp->i_ino = isodirino(ep, imp); ! 323: goto found; ! 324: } ! 325: if (namelen != 1 ! 326: || ep->name[0] != 0) ! 327: goto notfound; ! 328: } else if (!(res = isofncmp(name,len, ! 329: ep->name,namelen))) { ! 330: if ( isonum_711(ep->flags) & directoryBit ) ! 331: ino = isodirino(ep, imp); ! 332: else { ! 333: ino = (bp->b_blkno << imp->im_bshift) + entryoffsetinblock; ! 334: } ! 335: saveoffset = dp->i_offset; ! 336: } else if (ino) ! 337: goto foundino; ! 338: #ifdef NOSORTBUG /* On some CDs directory entries are not sorted correctly */ ! 339: else if (res < 0) ! 340: goto notfound; ! 341: else if (res > 0 && numdirpasses == 2) ! 342: numdirpasses++; ! 343: #endif ! 344: } ! 345: break; ! 346: case ISO_FTYPE_RRIP: ! 347: if ( isonum_711(ep->flags) & directoryBit ) ! 348: ino = isodirino(ep, imp); ! 349: else { ! 350: ino = (bp->b_blkno << imp->im_bshift) + entryoffsetinblock; ! 351: } ! 352: dp->i_ino = ino; ! 353: cd9660_rrip_getname(ep,altname,&namelen,&dp->i_ino,imp); ! 354: if (namelen == cnp->cn_namelen ! 355: && !bcmp(name,altname,namelen)) ! 356: goto found; ! 357: ino = 0; ! 358: break; ! 359: } ! 360: dp->i_offset += reclen; ! 361: entryoffsetinblock += reclen; ! 362: } ! 363: ! 364: if (ino) { ! 365: foundino: ! 366: dp->i_ino = ino; ! 367: if (saveoffset != dp->i_offset) { ! 368: if (lblkno(imp, dp->i_offset) != ! 369: lblkno(imp, saveoffset)) { ! 370: if (bp != NULL) ! 371: brelse(bp); ! 372: if ( (error = VOP_BLKATOFF(vdp, (off_t)saveoffset, NULL, &bp)) ) ! 373: return (error); ! 374: } ! 375: entryoffsetinblock = saveoffset & bmask; ! 376: ep = (struct iso_directory_record *) ! 377: ((char *)bp->b_data + entryoffsetinblock); ! 378: dp->i_offset = saveoffset; ! 379: } ! 380: goto found; ! 381: } ! 382: notfound: ! 383: /* ! 384: * If we started in the middle of the directory and failed ! 385: * to find our target, we must check the beginning as well. ! 386: */ ! 387: if (numdirpasses == 2) { ! 388: numdirpasses--; ! 389: dp->i_offset = 0; ! 390: endsearch = dp->i_diroff; ! 391: goto searchloop; ! 392: } ! 393: if (bp != NULL) ! 394: brelse(bp); ! 395: ! 396: /* ! 397: * Insert name into cache (as non-existent) if appropriate. ! 398: */ ! 399: if (cnp->cn_flags & MAKEENTRY) ! 400: cache_enter(vdp, *vpp, cnp); ! 401: if (nameiop == CREATE || nameiop == RENAME) { ! 402: /* ! 403: * return EROFS (NOT EJUSTRETURN). The caller will then unlock ! 404: * the parent for us. ! 405: */ ! 406: return (EROFS); ! 407: } ! 408: return (ENOENT); ! 409: ! 410: found: ! 411: if (numdirpasses == 2) ! 412: iso_nchstats.ncs_pass2++; ! 413: ! 414: /* ! 415: * Found component in pathname. ! 416: * If the final component of path name, save information ! 417: * in the cache as to where the entry was found. ! 418: */ ! 419: if ((flags & ISLASTCN) && nameiop == LOOKUP) ! 420: dp->i_diroff = dp->i_offset; ! 421: ! 422: /* ! 423: * Step through the translation in the name. We do not `iput' the ! 424: * directory because we may need it again if a symbolic link ! 425: * is relative to the current directory. Instead we save it ! 426: * unlocked as "pdp". We must get the target inode before unlocking ! 427: * the directory to insure that the inode will not be removed ! 428: * before we get it. We prevent deadlock by always fetching ! 429: * inodes from the root, moving down the directory tree. Thus ! 430: * when following backward pointers ".." we must unlock the ! 431: * parent directory before getting the requested directory. ! 432: * There is a potential race condition here if both the current ! 433: * and parent directories are removed before the `iget' for the ! 434: * inode associated with ".." returns. We hope that this occurs ! 435: * infrequently since we cannot avoid this race condition without ! 436: * implementing a sophisticated deadlock detection algorithm. ! 437: * Note also that this simple deadlock detection scheme will not ! 438: * work if the file system has any hard links other than ".." ! 439: * that point backwards in the directory structure. ! 440: */ ! 441: pdp = vdp; ! 442: /* ! 443: * If ino is different from dp->i_ino, ! 444: * it's a relocated directory. ! 445: */ ! 446: if (flags & ISDOTDOT) { ! 447: VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ ! 448: error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, ! 449: dp->i_ino != ino, ep, p); ! 450: VTOI(tdp)->i_parent = VTOI(pdp)->i_number; ! 451: brelse(bp); ! 452: if (error) { ! 453: VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, p); ! 454: return (error); ! 455: } ! 456: if (lockparent && (flags & ISLASTCN) && ! 457: (error = VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, p))) { ! 458: vput(tdp); ! 459: return (error); ! 460: } ! 461: *vpp = tdp; ! 462: } else if (dp->i_number == dp->i_ino) { ! 463: brelse(bp); ! 464: VREF(vdp); /* we want ourself, ie "." */ ! 465: *vpp = vdp; ! 466: } else { ! 467: error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, ! 468: dp->i_ino != ino, ep, p); ! 469: VTOI(tdp)->i_parent = VTOI(pdp)->i_number; /* save parent inode number */ ! 470: brelse(bp); ! 471: if (error) ! 472: return (error); ! 473: if (!lockparent || !(flags & ISLASTCN)) ! 474: VOP_UNLOCK(pdp, 0, p); ! 475: *vpp = tdp; ! 476: } ! 477: ! 478: /* ! 479: * Insert name into cache if appropriate. ! 480: */ ! 481: if (cnp->cn_flags & MAKEENTRY) ! 482: cache_enter(vdp, *vpp, cnp); ! 483: return (0); ! 484: } ! 485: ! 486: /* ! 487: * Return buffer with the contents of block "offset" from the beginning of ! 488: * directory "ip". If "res" is non-zero, fill it in with a pointer to the ! 489: * remaining space in the directory. ! 490: */ ! 491: int ! 492: cd9660_blkatoff(ap) ! 493: struct vop_blkatoff_args /* { ! 494: struct vnode *a_vp; ! 495: off_t a_offset; ! 496: char **a_res; ! 497: struct buf **a_bpp; ! 498: } */ *ap; ! 499: { ! 500: struct iso_node *ip; ! 501: register struct iso_mnt *imp; ! 502: struct buf *bp; ! 503: daddr_t lbn; ! 504: int bsize, error; ! 505: ! 506: ip = VTOI(ap->a_vp); ! 507: imp = ip->i_mnt; ! 508: lbn = lblkno(imp, ap->a_offset); ! 509: bsize = blksize(imp, ip, lbn); ! 510: ! 511: if ( (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) ) { ! 512: brelse(bp); ! 513: *ap->a_bpp = NULL; ! 514: return (error); ! 515: } ! 516: if (ap->a_res) ! 517: *ap->a_res = (char *)bp->b_data + blkoff(imp, ap->a_offset); ! 518: *ap->a_bpp = bp; ! 519: return (0); ! 520: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.