bool IOGUIDPartitionScheme::isPartitionInvalid( gpt_ent * partition, UInt32 partitionID ) { // // Ask whether the given partition appears to be invalid. A partition that // is invalid will cause it to be skipped in the scan, but will not cause a // failure of the GUID partition map recognition. // IOMedia * media = getProvider(); UInt64 mediaBlockSize = media->getPreferredBlockSize(); UInt64 partitionBase = 0; UInt64 partitionSize = 0; // Compute the relative byte position and size of the new partition. partitionBase = OSSwapLittleToHostInt64(partition->ent_lba_start); partitionSize = OSSwapLittleToHostInt64(partition->ent_lba_end); partitionBase *= mediaBlockSize; partitionSize *= mediaBlockSize; // Determine whether the partition is a placeholder. if ( partitionBase == partitionSize ) return true; // Compute the relative byte position and size of the new partition. partitionSize -= partitionBase - mediaBlockSize; // Determine whether the new partition leaves the confines of the container. if ( partitionBase + partitionSize > media->getSize() ) return true; return false; }
bool IOFDiskPartitionScheme::isPartitionInvalid( fdisk_part * partition, UInt32 partitionID, UInt32 fdiskBlock ) { // // Ask whether the given partition appears to be invalid. A partition that // is invalid will cause it to be skipped in the scan, but will not cause a // failure of the FDisk partition map recognition. // IOMedia * media = getProvider(); UInt64 mediaBlockSize = media->getPreferredBlockSize(); UInt64 partitionBase = 0; UInt64 partitionSize = 0; // Compute the relative byte position and size of the new partition. partitionBase = OSSwapLittleToHostInt32(partition->relsect) + fdiskBlock; partitionSize = OSSwapLittleToHostInt32(partition->numsect); partitionBase *= mediaBlockSize; partitionSize *= mediaBlockSize; // Determine whether the partition shares space with the partition map. if ( partitionBase == fdiskBlock * mediaBlockSize ) return true; // Determine whether the partition starts at (or past) the end-of-media. if ( partitionBase >= media->getSize() ) return true; return false; }
IOMedia * IOFDiskPartitionScheme::instantiateMediaObject( fdisk_part * partition, UInt32 partitionID, UInt32 fdiskBlock ) { // // Instantiate a new media object to represent the given partition. // IOMedia * media = getProvider(); UInt64 mediaBlockSize = media->getPreferredBlockSize(); UInt64 partitionBase = 0; char * partitionHint = 0; UInt64 partitionSize = 0; // Compute the relative byte position and size of the new partition. partitionBase = OSSwapLittleToHostInt32(partition->relsect) + fdiskBlock; partitionSize = OSSwapLittleToHostInt32(partition->numsect); partitionBase *= mediaBlockSize; partitionSize *= mediaBlockSize; // Clip the size of the new partition if it extends past the end-of-media. if ( partitionBase + partitionSize > media->getSize() ) { partitionSize = media->getSize() - partitionBase; } // Look up a type for the new partition. char hintIndex[5]; snprintf(hintIndex, sizeof(hintIndex), "0x%02X", partition->systid & 0xFF); partitionHint = hintIndex; OSDictionary * hintTable = OSDynamicCast( /* type */ OSDictionary, /* instance */ getProperty(kIOFDiskPartitionSchemeContentTable) ); if ( hintTable ) { OSString * hintValue; hintValue = OSDynamicCast(OSString, hintTable->getObject(hintIndex)); if ( hintValue ) partitionHint = (char *) hintValue->getCStringNoCopy(); } // Create the new media object. IOMedia * newMedia = instantiateDesiredMediaObject( /* partition */ partition, /* partitionID */ partitionID, /* fdiskBlock */ fdiskBlock ); if ( newMedia ) { if ( newMedia->init( /* base */ partitionBase, /* size */ partitionSize, /* preferredBlockSize */ mediaBlockSize, /* attributes */ media->getAttributes(), /* isWhole */ false, /* isWritable */ media->isWritable(), /* contentHint */ partitionHint ) ) { // Set a name for this partition. char name[24]; snprintf(name, sizeof(name), "Untitled %d", (int) partitionID); newMedia->setName(name); // Set a location value (the partition number) for this partition. char location[12]; snprintf(location, sizeof(location), "%d", (int) partitionID); newMedia->setLocation(location); // Set the "Partition ID" key for this partition. newMedia->setProperty(kIOMediaPartitionIDKey, partitionID, 32); } else { newMedia->release(); newMedia = 0; } } return newMedia; }
OSSet * IOFDiskPartitionScheme::scan(SInt32 * score) { // // Scan the provider media for an FDisk partition map. Returns the set // of media objects representing each of the partitions (the retain for // the set is passed to the caller), or null should no partition map be // found. The default probe score can be adjusted up or down, based on // the confidence of the scan. // IOBufferMemoryDescriptor * buffer = 0; UInt32 bufferSize = 0; UInt32 fdiskBlock = 0; UInt32 fdiskBlockExtn = 0; UInt32 fdiskBlockNext = 0; UInt32 fdiskID = 0; disk_blk0 * fdiskMap = 0; IOMedia * media = getProvider(); UInt64 mediaBlockSize = media->getPreferredBlockSize(); bool mediaIsOpen = false; OSSet * partitions = 0; IOReturn status = kIOReturnError; // Determine whether this media is formatted. if ( media->isFormatted() == false ) goto scanErr; // Determine whether this media has an appropriate block size. if ( (mediaBlockSize % sizeof(disk_blk0)) ) goto scanErr; // Allocate a buffer large enough to hold one map, rounded to a media block. bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize); buffer = IOBufferMemoryDescriptor::withCapacity( /* capacity */ bufferSize, /* withDirection */ kIODirectionIn ); if ( buffer == 0 ) goto scanErr; // Allocate a set to hold the set of media objects representing partitions. partitions = OSSet::withCapacity(4); if ( partitions == 0 ) goto scanErr; // Open the media with read access. mediaIsOpen = open(this, 0, kIOStorageAccessReader); if ( mediaIsOpen == false ) goto scanErr; // Scan the media for FDisk partition map(s). do { // Read the next FDisk map into our buffer. status = media->read(this, fdiskBlock * mediaBlockSize, buffer); if ( status != kIOReturnSuccess ) goto scanErr; fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy(); // Determine whether the partition map signature is present. if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE ) { goto scanErr; } // Scan for valid partition entries in the partition map. fdiskBlockNext = 0; for ( unsigned index = 0; index < DISK_NPART; index++ ) { // Determine whether this is an extended (vs. data) partition. if ( isPartitionExtended(fdiskMap->parts + index) ) // (extended) { // If peer extended partitions exist, we accept only the first. if ( fdiskBlockNext == 0 ) // (no peer extended partition) { fdiskBlockNext = fdiskBlockExtn + OSSwapLittleToHostInt32( /* data */ fdiskMap->parts[index].relsect ); if ( fdiskBlockNext * mediaBlockSize >= media->getSize() ) { fdiskBlockNext = 0; // (exceeds confines of media) } } } else if ( isPartitionUsed(fdiskMap->parts + index) ) // (data) { // Prepare this partition's ID. fdiskID = ( fdiskBlock == 0 ) ? (index + 1) : (fdiskID + 1); // Determine whether the partition is corrupt (fatal). if ( isPartitionCorrupt( /* partition */ fdiskMap->parts + index, /* partitionID */ fdiskID, /* fdiskBlock */ fdiskBlock ) ) { goto scanErr; } // Determine whether the partition is invalid (skipped). if ( isPartitionInvalid( /* partition */ fdiskMap->parts + index, /* partitionID */ fdiskID, /* fdiskBlock */ fdiskBlock ) ) { continue; } // Create a media object to represent this partition. IOMedia * newMedia = instantiateMediaObject( /* partition */ fdiskMap->parts + index, /* partitionID */ fdiskID, /* fdiskBlock */ fdiskBlock ); if ( newMedia ) { partitions->setObject(newMedia); newMedia->release(); } } } // Prepare for first extended partition, if any. if ( fdiskBlock == 0 ) { fdiskID = DISK_NPART; fdiskBlockExtn = fdiskBlockNext; } } while ( (fdiskBlock = fdiskBlockNext) ); // Release our resources. close(this); buffer->release(); return partitions; scanErr: // Release our resources. if ( mediaIsOpen ) close(this); if ( partitions ) partitions->release(); if ( buffer ) buffer->release(); return 0; }