Annotation of XNU/iokit/Families/IOStorage/IOApplePartitionScheme.cpp, revision 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.