|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-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: ! 23: // ! 24: // Notes: ! 25: // ----- ! 26: // o the on-disk label structure is packed for M68xxx and has big endian fields ! 27: // ! 28: // o the on-disk label is stored four times in succession, each label taking up ! 29: // round(sizeof(disk_label_t), drive's hard block size) bytes; CD's suffer of ! 30: // the mastering-with-a-different-hard-block-size problem, however we presume ! 31: // that all CDs produced that exhibit this problem have a valid first label ! 32: // at relative byte zero, and hence the next label increment is irrelevant. ! 33: // ! 34: // o the dl_label_blkno block value is absolute with respect to the whole disk, ! 35: // and the implicit block size is the drive's hard block size (eg. hard drive ! 36: // is typically 512 bytes, CD is typically 2048 bytes) ! 37: // ! 38: // o the dl_dt.d_front block value is relative to the containing partition's ! 39: // boundary (ie. relative to the very first label's dl_label_blkno value), ! 40: // and the implicit block size is dl_dt.d_secsize bytes (eg. hd=1024, cd=2048) ! 41: // ! 42: // o the dl_dt.d_partitions[].p_base block value is absolute with respect to the ! 43: // whole disk, and the implicit block size is dl_dt.d_secsize bytes; an offset ! 44: // of dl_dt.d_front is not factored into the p_base value, but should be in ! 45: // order to calculate the actual start position of the partition on the disk ! 46: // ! 47: // o the dl_dt.d_partitions[].p_size block value's implicit block size is ! 48: // dl_dt.d_secsize bytes ! 49: // ! 50: // Policies: ! 51: // -------- ! 52: // o the NeXT partition scheme accepts probes only on "whole" media objects ! 53: // and non-whole media objects with a content hint of 'Apple_Rhapsody_UFS' ! 54: // ! 55: // o the first two out of the four possible on-disk labels are read while the ! 56: // last two are ignored -- this is done in the spirit of minimizing reads; ! 57: // we forfeit some redundancy, however that is acceptable; the second label ! 58: // MUST be checked due to the fact that i386 machines commonly have the 1st ! 59: // label missing (due to the FDISK boot structure), but the second is valid ! 60: // ! 61: // o the default probe score of the NeXT partition scheme is 1000 ! 62: // ! 63: // o the eigth partition is always skipped -- this is due to the many varying ! 64: // preconceptions associated with the 8th partition in unix land: we just ! 65: // ignore it altogether (+ permits us a significant coding simplification) ! 66: // ! 67: // o the checksum for each NeXT label is not validated -- this is done in the ! 68: // spirit of minimizing reads and perhaps a bit of laziness ! 69: // ! 70: ! 71: #include <IOKit/assert.h> ! 72: #include <IOKit/IOLib.h> ! 73: #include <IOKit/storage/IONeXTPartitionScheme.h> ! 74: #include <libkern/OSByteOrder.h> ! 75: ! 76: #define super IOPartitionScheme ! 77: OSDefineMetaClassAndStructors(IONeXTPartitionScheme, IOPartitionScheme); ! 78: ! 79: #define kMinimumBlockSize 512 ! 80: ! 81: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 82: // NeXT Partition Types ! 83: ! 84: static struct { char * type; char * name; } partitionTypes[] = ! 85: { ! 86: { "4.4BSD", "Apple_UFS" }, ! 87: // { "4.1BSD", ... }, // V7 with 1K blocks (4.1, 2.9) ! 88: // { "4.2BSD", ... }, // 4.2BSD fast file system ! 89: // { "4.4LFS", ... }, // 4.4BSD log-structured file system ! 90: { 0, 0 } ! 91: }; ! 92: ! 93: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 94: ! 95: bool IONeXTPartitionScheme::init(OSDictionary * properties = 0) ! 96: { ! 97: // ! 98: // Initialize this object's minimal state. ! 99: // ! 100: ! 101: if (super::init(properties) == false) return false; ! 102: ! 103: _absoluteBase = 0; ! 104: _buffer = 0; ! 105: _bufferSize = 0; ! 106: ! 107: // Validate the compiled size of our important fixed-size structures. ! 108: ! 109: assert(sizeof(disktab_t) == 514); ! 110: assert(sizeof(partition_t) == 46); ! 111: assert(sizeof(disk_label_t) == 7240); ! 112: ! 113: return true; ! 114: } ! 115: ! 116: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 117: ! 118: void IONeXTPartitionScheme::free() ! 119: { ! 120: // ! 121: // Free all of this object's outstanding resources. ! 122: // ! 123: ! 124: if (_buffer) _buffer->release(); ! 125: ! 126: super::free(); ! 127: } ! 128: ! 129: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 130: ! 131: IOService * IONeXTPartitionScheme::probe(IOService * provider, SInt32 * score) ! 132: { ! 133: // ! 134: // Determine whether the provider media contains an NeXT partition map. If ! 135: // it does, we return "this" to indicate success, otherwise we return zero. ! 136: // ! 137: ! 138: IOMedia * media = (IOMedia *) provider; ! 139: ! 140: // State our assumptions. ! 141: ! 142: assert(OSDynamicCast(IOMedia, provider)); ! 143: ! 144: // Ask superclass' opinion about this probe. ! 145: ! 146: if (super::probe(provider, score) == 0) return 0; ! 147: ! 148: // Determine whether this media object is unformatted. ! 149: ! 150: if (media->isFormatted() == false) return 0; ! 151: ! 152: // Determine whether this media's block size is below our assumed minimum. ! 153: ! 154: if (media->getPreferredBlockSize() < kMinimumBlockSize) return 0; ! 155: ! 156: // Determine whether we can rule out the media object as a NeXT partition ! 157: // map container without reading actual data from the media. We rule out ! 158: // all non-whole media objects without an 'Apple_Rhapsody_UFS' hint. ! 159: ! 160: if ( media->isWhole() == false ) ! 161: { ! 162: if ( strcmp(media->getContentHint(), "Apple_Rhapsody_UFS") ) return 0; ! 163: } ! 164: ! 165: // Compute this partition's absolute offset with respect to the whole ! 166: // media, since the disk_label structure requires this information -- ! 167: // we go down the service hierarchy until we reach the whole media ! 168: // object (or run off the end :-). ! 169: ! 170: for (IOService * service = media; service; service = service->getProvider()) ! 171: { ! 172: if ( OSDynamicCast(IOMedia, service) ) // (is this a media object?) ! 173: { ! 174: _absoluteBase += ((IOMedia *)service)->getBase(); ! 175: if (((IOMedia *)service)->isWhole()) break; ! 176: } ! 177: } ! 178: ! 179: // Allocate a buffer large enough to hold one media block. ! 180: ! 181: _bufferSize = media->getPreferredBlockSize(); ! 182: _buffer = IOBufferMemoryDescriptor::withCapacity(_bufferSize, ! 183: kIODirectionIn); ! 184: ! 185: if (_buffer == 0) return 0; ! 186: ! 187: // Search for a valid NeXT label on the provider media. ! 188: ! 189: return identify(media) ? this : 0; ! 190: } ! 191: ! 192: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 193: ! 194: bool IONeXTPartitionScheme::start(IOService * provider) ! 195: { ! 196: // ! 197: // This method is called once we have been attached to the media object. We ! 198: // generate the new media objects that will represent our partitions here. ! 199: // ! 200: ! 201: disk_label_t * label; ! 202: IOMedia * media = (IOMedia *) provider; ! 203: bool success = false; ! 204: ! 205: // State our assumptions. ! 206: ! 207: assert(_buffer); ! 208: assert(_bufferSize >= kMinimumBlockSize); ! 209: ! 210: // Ask our superclass' opinion. ! 211: ! 212: if ( !super::start(provider) ) return false; ! 213: ! 214: // The block size we calculate for the partitions is important to ! 215: // BSD and its filesystems -- if we get it wrong, the filesystem ! 216: // will end up reading and writing the wrong blocks. We use the ! 217: // NeXT label's sector size, NOT the partition's fragment size or ! 218: // it won't work (speaking out of experience). Period. ! 219: ! 220: label = (disk_label_t *) _buffer->getBytesNoCopy(); ! 221: ! 222: UInt64 fsBlockSize = OSSwapBigToHostInt32(label->dl_secsize); ! 223: ! 224: if (fsBlockSize % media->getPreferredBlockSize()) ! 225: { ! 226: IOLog("%s on %s: Bad block size is defined.\n", ! 227: getName(), media->getName()); ! 228: return false; ! 229: } ! 230: ! 231: // Scan through all the partition entries. ! 232: // ! 233: // Due to the different preconceptions associated with the eigth partition, ! 234: // our policy is to ignore the eigth partition altogether. This also makes ! 235: // for a cool coding simplification -- since the first 7 partition entries ! 236: // completely fit in the first 512-byte block, a read of the next block and ! 237: // caching useful global information from the first block is not necessary ! 238: // just to parse the eigth partition entry. ! 239: ! 240: assert( kMinimumBlockSize >= ( (UInt8 *) &(label->dl_part[NPART-1]) - ! 241: (UInt8 *) label) ); ! 242: ! 243: for ( unsigned index = 0; index < NPART - 1; index++ ) ! 244: { ! 245: // Skip all null partition entries (have base of -1 and size of -1). ! 246: ! 247: if ( (SInt32) OSSwapBigToHostInt32(label->dl_part[index].p_base) < 0 || ! 248: (SInt32) OSSwapBigToHostInt32(label->dl_part[index].p_size) <= 0 ) ! 249: continue; // (skip) ! 250: ! 251: // Compute the absolute position and size of the new partition. ! 252: ! 253: UInt64 base; ! 254: UInt64 size; ! 255: ! 256: base = ( (UInt64) OSSwapBigToHostInt32(label->dl_part[index].p_base) + ! 257: (UInt64) OSSwapBigToHostInt16(label->dl_front) ) * ! 258: (UInt64) OSSwapBigToHostInt32(label->dl_secsize); ! 259: size = (UInt64) OSSwapBigToHostInt32(label->dl_part[index].p_size) * ! 260: (UInt64) OSSwapBigToHostInt32(label->dl_secsize); ! 261: ! 262: // Look up a name and a type for this partition. ! 263: ! 264: const char * aName = "Untitled"; ! 265: const char * aHint = 0; ! 266: ! 267: if ( label->dl_part[index].p_mountpt[0] ) ! 268: aName = label->dl_part[index].p_mountpt; ! 269: else if ( label->dl_label[0] ) ! 270: aName = label->dl_label; ! 271: ! 272: for (unsigned n = 0; partitionTypes[n].type; n++) ! 273: { ! 274: if ( !strcmp(label->dl_part[index].p_type, partitionTypes[n].type) ) ! 275: { ! 276: aHint = partitionTypes[n].name; ! 277: break; ! 278: } ! 279: } ! 280: ! 281: if (aHint == 0) aHint = label->dl_part[index].p_type; ! 282: ! 283: // Ensure the partition definition does not leave the confines of the ! 284: // containing media (especially that base is an absolute position). ! 285: ! 286: if ( base < _absoluteBase || ! 287: base - _absoluteBase + size > media->getSize() ) ! 288: { ! 289: IOLog("%s on %s: \"%s\" (partition %d) exceeds confines of " ! 290: "containing media.\n", ! 291: getName(), media->getName(), aName, index+1); ! 292: continue; // (skip) ! 293: } ! 294: ! 295: // The partition base may be unaligned with respect the whole media's ! 296: // block boundaries. We warn the user in this event since every read ! 297: // or write is going to cause deblocking. ! 298: ! 299: if ( (_absoluteBase + base) % media->getPreferredBlockSize() ) ! 300: { ! 301: IOLog("%s on %s: Access to \"%s\" (partition %d) may be slow due " ! 302: "to a misaligned block boundary.\n", ! 303: getName(), media->getName(), aName, index + 1); ! 304: } ! 305: ! 306: // Create the new media object. ! 307: ! 308: IOMedia * newMedia = new IOMedia; ! 309: ! 310: if ( !newMedia || ! 311: !newMedia->init( // base (bytes; relative to provider media) ! 312: base - _absoluteBase, ! 313: // size (bytes) ! 314: size, ! 315: // natural block size (bytes) ! 316: fsBlockSize, ! 317: // is ejectable ! 318: media->isEjectable(), ! 319: // is whole ! 320: false, ! 321: // is writable ! 322: media->isWritable(), ! 323: // content hint ! 324: aHint ) || ! 325: !newMedia->attach(this) ) ! 326: { ! 327: IOLog("%s on %s: Unable to create media object for \"%s\" " ! 328: "(partition %d).\n", ! 329: getName(), media->getName(), aName, index + 1); ! 330: ! 331: if (newMedia) newMedia->release(); ! 332: continue; // (skip) ! 333: } ! 334: ! 335: newMedia->setName(aName); ! 336: ! 337: // Set a location value (the partition number) for this partition. ! 338: ! 339: char location[12]; ! 340: sprintf(location, "%d", index + 1); ! 341: newMedia->setLocation(location); ! 342: ! 343: // Create the "Partition ID" key. ! 344: ! 345: newMedia->setProperty(kIOMediaPartitionID, index + 1, 32); ! 346: ! 347: // Register the media object with the matching system. ! 348: ! 349: newMedia->registerService(); ! 350: ! 351: // Release our retain on the new media object (in registry). ! 352: ! 353: newMedia->release(); ! 354: ! 355: success = true; ! 356: } // (for all partition entries) ! 357: ! 358: // Release our buffer now that we no longer need it. ! 359: ! 360: _buffer->release(); ! 361: ! 362: _buffer = 0; ! 363: _bufferSize = 0; ! 364: ! 365: // Return success if we found at least one partition. ! 366: ! 367: return success; ! 368: } ! 369: ! 370: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 371: ! 372: bool IONeXTPartitionScheme::identify(IOMedia * media) ! 373: { ! 374: // ! 375: // Searches for the existence of a NeXT partition map on the given media. ! 376: // ! 377: ! 378: UInt32 labelIncrement; // (in bytes) ! 379: bool success = false; ! 380: ! 381: // State our assumptions. ! 382: ! 383: assert(_buffer); ! 384: assert(_bufferSize >= kMinimumBlockSize); ! 385: ! 386: // Open the media object for access. ! 387: ! 388: if ( media->open(this, 0, kAccessReader) == false ) return false; ! 389: ! 390: // Search through the four (NLABELS) possible label positions. ! 391: // ! 392: // In the spirit of minimizing reads, however, we cheat and only check the ! 393: // first two of the four possible label positions. Note that it is common ! 394: // on i386 machines that the first label is non-existent, while the second ! 395: // is valid, hence why we check the first TWO labels. ! 396: ! 397: labelIncrement=IORound(sizeof(disk_label_t),media->getPreferredBlockSize()); ! 398: ! 399: for (unsigned index = 0; index < 2; index++) // ("2" was "NLABELS") ! 400: { ! 401: // Read the appropriate block into our buffer. ! 402: ! 403: _buffer->setDirection(kIODirectionIn); // (a read) ! 404: _buffer->setLength(_bufferSize); // (transfer one full block) ! 405: ! 406: if ( media->read( /* client */ this, ! 407: /* byteStart */ labelIncrement * index, ! 408: /* buffer */ _buffer ) == kIOReturnSuccess ) ! 409: { ! 410: // Determine whether this buffer contains a valid NeXT label. We ! 411: // validate the version signature and the label's block position. ! 412: ! 413: disk_label_t * label = (disk_label_t *) _buffer->getBytesNoCopy(); ! 414: ! 415: if ( OSSwapBigToHostInt32(label->dl_version) == DL_V3 || ! 416: OSSwapBigToHostInt32(label->dl_version) == DL_V2 || ! 417: OSSwapBigToHostInt32(label->dl_version) == DL_V1 ) ! 418: { ! 419: if ( OSSwapBigToHostInt32(label->dl_label_blkno) == ! 420: (UInt32) ( (_absoluteBase + labelIncrement * index) / ! 421: media->getPreferredBlockSize() ) ) ! 422: { ! 423: success = true; // (valid version and block position) ! 424: break; ! 425: } ! 426: } ! 427: } ! 428: } ! 429: ! 430: // Close the media object we opened earlier. ! 431: ! 432: media->close(this); ! 433: ! 434: return success; ! 435: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.