Annotation of XNU/iokit/Families/IOStorage/IOApplePartitionScheme.cpp, revision 1.1.1.1

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 dpme structure is packed for PowerPC and has big endian fields
                     27: //
                     28: // o the dpme_pblock_start block value is relative to the containing media's
                     29: //   boundary, and the implicit block size is hardcoded to 512 bytes
                     30: //
                     31: // o the dpme_pblocks block value's implicit block size is 512 bytes
                     32: //
                     33: // Policies:
                     34: // --------
                     35: // o the apple partition scheme accepts probes only on "whole" media objects --
                     36: //   this is done in the spirit of minimizing reads, since in general practice,
                     37: //   subpartitions of the apple type do not exist
                     38: //
                     39: // o the default probe score of the apple partition scheme is 1200
                     40: //
                     41: // o the "Apple_partition_map" partition is always published as a non-writable
                     42: //   media -- this is because its contents are nobody's business but ours
                     43: //
                     44: // o the "Apple_Free" partition is always skipped -- this is because it would
                     45: //   never be used by a serious user application, and it cries out to harbour
                     46: //   viruses;  the partition also often exceeds the confines of the media for
                     47: //   CDs, which would arguably require ugly truncation logic to be consistent
                     48: //
                     49: // o the checksum for each partition entry is not validated -- this is done in
                     50: //   the spirit of non-necessity and perhaps a bit of laziness
                     51: //
                     52: 
                     53: #include <IOKit/assert.h>
                     54: #include <IOKit/IOLib.h>
                     55: #include <IOKit/storage/IOApplePartitionScheme.h>
                     56: #include <libkern/OSByteOrder.h>
                     57: 
                     58: #define super IOPartitionScheme
                     59: OSDefineMetaClassAndStructors(IOApplePartitionScheme, IOPartitionScheme);
                     60: 
                     61: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     62: 
                     63: bool IOApplePartitionScheme::init(OSDictionary * properties = 0)
                     64: {
                     65:     //
                     66:     // Initialize this object's minimal state.
                     67:     //
                     68: 
                     69:     if (super::init(properties) == false)  return false;
                     70: 
                     71:     _buffer        = 0;
                     72:     _bufferSize    = 0;
                     73:     _masteredAt512 = false;
                     74: 
                     75:     // Validate the compiled size of our important fixed-size structures.
                     76: 
                     77:     assert(sizeof(dpme)   == 512);
                     78:     assert(sizeof(DDMap)  ==   8);
                     79:     assert(sizeof(Block0) == 512);
                     80: 
                     81:     return true;
                     82: }
                     83: 
                     84: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     85: 
                     86: void IOApplePartitionScheme::free()
                     87: {
                     88:     //
                     89:     // Free all of this object's outstanding resources.
                     90:     //
                     91: 
                     92:     if (_buffer)  _buffer->release();
                     93: 
                     94:     super::free();
                     95: }
                     96: 
                     97: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     98: 
                     99: IOService * IOApplePartitionScheme::probe(IOService * provider, SInt32 * score)
                    100: {
                    101:     //
                    102:     // Determine whether the provider media contains an apple partition map.  If
                    103:     // it does, we return "this" to indicate success, otherwise we return zero.
                    104:     //
                    105: 
                    106:     IOMedia * media = (IOMedia *) provider;
                    107: 
                    108:     // State our assumptions.
                    109: 
                    110:     assert(OSDynamicCast(IOMedia, provider));
                    111: 
                    112:     // Ask superclass' opinion about this probe.
                    113: 
                    114:     if (super::probe(provider, score) == 0)  return 0;
                    115: 
                    116:     // Determine whether this media object is unformatted.
                    117: 
                    118:     if (media->isFormatted() == false)  return 0;
                    119: 
                    120:     // Determine whether this media's block size is below our assumed minimum.
                    121: 
                    122:     if (media->getPreferredBlockSize() < sizeof(dpme))  return 0;
                    123: 
                    124:     // Determine whether we can rule out the media object as an apple partition
                    125:     // map container without reading actual data from the media.    We rule out
                    126:     // all non-whole media objects.
                    127: 
                    128:     if (media->isWhole() == false)  return 0;
                    129: 
                    130:     // Allocate a buffer large enough to hold one media block.
                    131: 
                    132:     _bufferSize = media->getPreferredBlockSize();
                    133:     _buffer     = IOBufferMemoryDescriptor::withCapacity(_bufferSize,
                    134:                                                          kIODirectionIn);
                    135: 
                    136:     if (_buffer == 0)  return 0;
                    137: 
                    138:     // Search for a valid apple partition on the provider media.
                    139: 
                    140:     return identify(media) ? this : 0;
                    141: }
                    142: 
                    143: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    144: 
                    145: bool IOApplePartitionScheme::start(IOService * provider)
                    146: {
                    147:     //
                    148:     // This method is called once we have been attached to the media object.  We
                    149:     // generate the new media objects that will represent our partitions here.
                    150:     //
                    151: 
                    152:     UInt64    block;    
                    153:     UInt32    entriesCount;
                    154:     IOMedia * media = (IOMedia *) provider;
                    155:     dpme *    partition;
                    156:     UInt32    partitionsPerBlock;
                    157:     UInt32    partitionsLeftOnThisBlock;
                    158:     bool      success = false;
                    159: 
                    160:     // State our assumptions.
                    161: 
                    162:     assert(_buffer);
                    163: 
                    164:     // Ask our superclass' opinion.
                    165: 
                    166:     if ( !super::start(provider) )  return false;
                    167: 
                    168:     // Open the media object for access.
                    169: 
                    170:     if ( media->open(this, 0, kAccessReader) == false )  return false;
                    171: 
                    172:     // Set up our iteration variables, based on whether the media was mastered
                    173:     // on a 512-byte-block medium or at the media's preferred block size.
                    174: 
                    175:     if ( _masteredAt512 )
                    176:     {
                    177:         block = 0;
                    178:         partition = (dpme*)((UInt8*)_buffer->getBytesNoCopy() + sizeof(Block0));
                    179:         partitionsPerBlock = _bufferSize / sizeof(dpme);
                    180:         partitionsLeftOnThisBlock = partitionsPerBlock - 1;
                    181:     }
                    182:     else
                    183:     {
                    184:         block = 1;
                    185:         partition = (dpme *) _buffer->getBytesNoCopy();
                    186:         partitionsPerBlock = 1;
                    187:         partitionsLeftOnThisBlock = 1;
                    188:     }
                    189: 
                    190:     // Scan through all the partition entries.
                    191: 
                    192:     entriesCount = OSSwapBigToHostInt32(partition->dpme_map_entries);
                    193: 
                    194:     for ( unsigned index = 0; index < entriesCount; index++, partition += 1 )
                    195:     {
                    196:         // Determine whether we've exhausted the current buffer of partitions.
                    197: 
                    198:         if ( partitionsLeftOnThisBlock == 0 )
                    199:         {
                    200:             // Read the next block into our buffer.
                    201: 
                    202:             block++;
                    203:             _buffer->setDirection(kIODirectionIn); // (a read)
                    204:             _buffer->setLength(_bufferSize);       // (transfer one full block)
                    205: 
                    206:             if ( media->read( /* client    */ this,
                    207:                               /* byteStart */ block * _bufferSize,
                    208:                               /* buffer    */ _buffer ) != kIOReturnSuccess )
                    209:             {
                    210:                 IOLog("%s: %s: Unable to read block %d.\n", 
                    211:                       getName(), media->getName(), (int) block);
                    212:                 break; // (failure)
                    213:             }
                    214: 
                    215:             partition = (dpme *) _buffer->getBytesNoCopy();
                    216:             partitionsLeftOnThisBlock = partitionsPerBlock;
                    217:         }
                    218: 
                    219:         partitionsLeftOnThisBlock--;
                    220: 
                    221:         // Determine whether this partition has a valid 'PM' signature.
                    222: 
                    223:         if ( OSSwapBigToHostInt16(partition->dpme_signature) != DPME_SIGNATURE )
                    224:         {
                    225:             IOLog("%s on %s: Partition %d has an invalid signature.\n",
                    226:                   getName(), media->getName(), index + 1);
                    227:             continue; // (skip)
                    228:         }
                    229: 
                    230:         // Determine whether this partition's type is 'Apple_Free'.
                    231: 
                    232:         if ( !strcmp(partition->dpme_type, "Apple_Free") )
                    233:             continue; // (skip)
                    234: 
                    235:         // Determine whether this partition's type is 'Apple_partition_map'.
                    236: 
                    237:         bool isWritable = media->isWritable();
                    238: 
                    239:         if ( !strcmp(partition->dpme_type, "Apple_partition_map") )
                    240:             isWritable = false;
                    241: 
                    242:         // Compute the relative position and size of the new partition.  The
                    243:         // block values are always in terms of 512-byte blocks.
                    244: 
                    245:         UInt64 base = OSSwapBigToHostInt32(partition->dpme_pblock_start)*512ULL;
                    246:         UInt64 size = OSSwapBigToHostInt32(partition->dpme_pblocks) * 512ULL;
                    247: 
                    248:         if ( base == 0 || size == 0 )
                    249:             continue; // (skip)
                    250: 
                    251:         // Look up a name and a type for this partition.
                    252: 
                    253:         const char * aName = partition->dpme_name;
                    254:         const char * aHint = partition->dpme_type;
                    255: 
                    256:         // Ensure the partition definition does not leave the confines of the
                    257:         // containing media.  Note the "Apple_Free" partition often leaves its
                    258:         // confines on CD media, however it is our policy to ignore Apple_Free
                    259:         // partitions anyway.
                    260: 
                    261:         if ( base + size > media->getSize() )
                    262:         {
                    263:             IOLog("%s on %s: \"%s\" (partition %d) exceeds confines of "
                    264:                   "containing media.\n",
                    265:                   getName(), media->getName(), aName, index+1);
                    266:             continue; // (skip)
                    267:         }
                    268: 
                    269:         // The partition base may be unaligned with respect the parent media's
                    270:         // block boundaries.   We warn the user in this event since every read
                    271:         // or write is going to cause deblocking.  We presume, of course, that
                    272:         // the parent media's base is aligned in making this determination.
                    273: 
                    274:         if ( base % media->getPreferredBlockSize() )
                    275:         {
                    276:             IOLog("%s on %s: Access to \"%s\" (partition %d) may be slow due "
                    277:                   "to a misaligned block boundary.\n",
                    278:                   getName(), media->getName(), aName, index + 1);
                    279:         }        
                    280: 
                    281:         // Create the new media object.
                    282: 
                    283:         IOMedia * newMedia = new IOMedia;
                    284: 
                    285:         if ( !newMedia ||
                    286:              !newMedia->init( // base (bytes; relative to provider media)
                    287:                               base,
                    288:                               // size (bytes)
                    289:                               size,
                    290:                               // natural block size (bytes)
                    291: ///m:2361246:workaround:added:start
                    292:                               (!strcmp(aHint, "Apple_HFS")) ? (512) : 
                    293: ///m:2361246:workaround:added:stop
                    294:                               media->getPreferredBlockSize(),
                    295:                               // is ejectable
                    296:                               media->isEjectable(),
                    297:                               // is whole
                    298:                               false,
                    299:                               // is writable
                    300:                               isWritable,
                    301:                               // content hint
                    302:                               aHint ) ||
                    303:              !newMedia->attach(this) )
                    304:         {
                    305:             IOLog("%s on %s: Unable to create media object for \"%s\" "
                    306:                   "(partition %d).\n",
                    307:                   getName(), media->getName(), aName, index + 1);
                    308: 
                    309:             if ( newMedia )  newMedia->release();
                    310:             continue; // (skip)
                    311:         }
                    312: 
                    313:         newMedia->setName(aName);
                    314: 
                    315:         // Set a location value (the partition number) for this partition.
                    316: 
                    317:         char location[12];
                    318:         sprintf(location, "%d", index + 1);
                    319:         newMedia->setLocation(location);
                    320: 
                    321:         // Create the "Partition ID" key.
                    322: 
                    323:         newMedia->setProperty(kIOMediaPartitionID, index + 1, 32);
                    324: 
                    325:         // Release our retain on the new media object (in registry).
                    326: 
                    327:         newMedia->release();
                    328: 
                    329:         // We don't register the new media object with the matching system
                    330:         // until we've closed our open on the media object below us.
                    331: 
                    332:         success = true;
                    333:     } // (for all partition entries)
                    334: 
                    335:     // Release our buffer now that we no longer need it.
                    336: 
                    337:     _buffer->release();
                    338: 
                    339:     _buffer     = 0;
                    340:     _bufferSize = 0;
                    341: 
                    342:     // Close the media object we opened earlier.
                    343: 
                    344:     media->close(this);
                    345: 
                    346:     // We now register the new media objects with the matching system, now
                    347:     // that we've closed our open on the media object below us.
                    348: 
                    349:     if ( success )
                    350:     {
                    351:         OSIterator * clients = getClientIterator();
                    352: 
                    353:         if (clients)
                    354:         {
                    355:             IOService * client;
                    356:             while ( (client = (IOService *) clients->getNextObject()) )
                    357:                 client->registerService();
                    358:             clients->release();
                    359:         }
                    360:     }
                    361: 
                    362:     // Return success if we found at least one partition.
                    363: 
                    364:     return success;
                    365: }
                    366: 
                    367: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    368: 
                    369: bool IOApplePartitionScheme::identify(IOMedia * media)
                    370: {
                    371:     //
                    372:     // Searches for the existence of an apple partition map on the given media.
                    373:     //
                    374: 
                    375:     bool success = false;
                    376: 
                    377:     // State our assumptions.
                    378: 
                    379:     assert(_buffer);
                    380: 
                    381:     // Open the media object for access.
                    382: 
                    383:     if ( media->open(this, 0, kAccessReader) == false )  return false;
                    384: 
                    385:     // Determine whether this is a larger-than-512-byte-block media that was
                    386:     // mastered from a 512-byte-block media  --  the mastering of 2048-byte-
                    387:     // block CDs is the prime example, from a 512-byte-block hard drive.
                    388: 
                    389:     if ( _bufferSize > sizeof(Block0) )
                    390:     {
                    391:         // State our assumptions.
                    392: 
                    393:         assert(_bufferSize >= sizeof(Block0) + sizeof(dpme));
                    394: 
                    395:         // Read the first block into our buffer.
                    396: 
                    397:         _buffer->setDirection(kIODirectionIn);   // (a read)
                    398:         _buffer->setLength(_bufferSize);         // (transfer one full block)
                    399: 
                    400:         if ( media->read(this, 0, _buffer) != kIOReturnSuccess )
                    401:         {
                    402:             media->close(this);
                    403:             return false; // (failure)
                    404:         }
                    405: 
                    406:         // Determine whether the partition signature 'PM' is present at a 512
                    407:         // byte offset into the block.
                    408: 
                    409:         dpme * partition;
                    410:         partition = (dpme*)((UInt8*)_buffer->getBytesNoCopy() + sizeof(Block0));
                    411: 
                    412:         if ( OSSwapBigToHostInt16(partition->dpme_signature) == DPME_SIGNATURE )
                    413:         {
                    414:             _masteredAt512 = true;
                    415:             success        = true;
                    416:         }
                    417:     }
                    418: 
                    419:     // Determine whether there is a valid apple partition map on the media;
                    420:     // note if the masteredAt512 flag is set, we already confirmed it does.
                    421: 
                    422:     if ( _masteredAt512 == false )
                    423:     {
                    424:         // Read the second block into our buffer.
                    425: 
                    426:         _buffer->setDirection(kIODirectionIn);   // (a read)
                    427:         _buffer->setLength(_bufferSize);         // (transfer one full block)
                    428: 
                    429:         if ( media->read(this, _bufferSize, _buffer) == kIOReturnSuccess )
                    430:         {
                    431:             // Determine whether the partition map signature 'PM' is present.
                    432: 
                    433:             dpme * partition = (dpme *) _buffer->getBytesNoCopy();
                    434: 
                    435:             if (OSSwapBigToHostInt16(partition->dpme_signature)==DPME_SIGNATURE)
                    436:                 success = true;
                    437:         }
                    438:     }
                    439: 
                    440:     // Close the media object we opened earlier.
                    441: 
                    442:     media->close(this);
                    443: 
                    444:     return success;
                    445: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.