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