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; }
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 IOGUIDPartitionScheme::start(IOService * provider) { // // Publish the new media objects which represent our partitions. // IOMedia * partition; OSIterator * partitionIterator; // State our assumptions. assert(_partitions); // Ask our superclass' opinion. if ( super::start(provider) == false ) return false; // Attach and register the new media objects representing our partitions. partitionIterator = OSCollectionIterator::withCollection(_partitions); if ( partitionIterator == 0 ) return false; while ( (partition = (IOMedia *) partitionIterator->getNextObject()) ) { if ( partition->attach(this) ) { attachMediaObjectToDeviceTree(partition); partition->registerService(); } } partitionIterator->release(); return true; }
bool AppleFileSystemDriver::mediaNotificationHandler( void * target, void * ref, IOService * service, IONotifier * notifier) { AppleFileSystemDriver * fs; IOMedia * media; IOReturn status = kIOReturnError; OSString * contentHint; const char * contentStr; VolumeUUID volumeUUID; OSString * uuidProperty; uuid_t uuid; bool matched = false; DEBUG_LOG("%s[%p]::%s -> '%s'\n", kClassName, target, __func__, service->getName()); do { fs = OSDynamicCast( AppleFileSystemDriver, (IOService *)target ); if (fs == 0) break; media = OSDynamicCast( IOMedia, service ); if (media == 0) break; // i.e. does it know how big it is / have a block size if ( media->isFormatted() == false ) break; // If the media already has a UUID property, try that first. uuidProperty = OSDynamicCast( OSString, media->getProperty("UUID") ); if (uuidProperty != NULL) { if (fs->_uuidString && uuidProperty->isEqualTo(fs->_uuidString)) { VERBOSE_LOG("existing UUID property matched\n"); matched = true; break; } } // only IOMedia's with content hints are interesting contentHint = OSDynamicCast( OSString, media->getProperty(kIOMediaContentHintKey) ); if (contentHint == NULL) break; contentStr = contentHint->getCStringNoCopy(); if (contentStr == NULL) break; // probe based on content hint if ( strcmp(contentStr, "Apple_HFS" ) == 0 || strcmp(contentStr, "Apple_HFSX" ) == 0 || strcmp(contentStr, "Apple_Boot" ) == 0 || strcmp(contentStr, "Apple_Recovery" ) == 0 || strcmp(contentStr, "48465300-0000-11AA-AA11-00306543ECAC" ) == 0 || /* APPLE_HFS_UUID */ strcmp(contentStr, "426F6F74-0000-11AA-AA11-00306543ECAC" ) == 0 || /* APPLE_BOOT_UUID */ strcmp(contentStr, "5265636F-7665-11AA-AA11-00306543ECAC" ) == 0 ) { /* APPLE_RECOVERY_UUID */ status = readHFSUUID( media, (void **)&volumeUUID ); } else { DEBUG_LOG("contentStr %s\n", contentStr); break; } if (status != kIOReturnSuccess) { break; } if (createUUIDFromName( kFSUUIDNamespaceSHA1, volumeUUID.bytes, kVolumeUUIDValueLength, uuid ) != kIOReturnSuccess) { break; } #if VERBOSE OSString *str = createStringFromUUID(uuid); OSString *bsdn = OSDynamicCast(OSString,media->getProperty("BSD Name")); if (str) { IOLog(" UUID %s found on volume '%s' (%s)\n", str->getCStringNoCopy(), media->getName(), bsdn ? bsdn->getCStringNoCopy():""); str->release(); } #endif if (fs->_uuid) { if ( uuid_compare(uuid, fs->_uuid) == 0 ) { VERBOSE_LOG(" UUID matched on volume %s\n", media->getName()); matched = true; } } } while (false); if (matched) { // prevent more notifications, if notifier is available if (fs->_notifier != NULL) { fs->_notifier->remove(); fs->_notifier = NULL; } DEBUG_LOG("%s::%s publishing boot-uuid-media '%s'\n", kClassName, __func__, media->getName()); IOService::publishResource( kBootUUIDMediaKey, media ); // Now that our job is done, get rid of the matching property // and kill the driver. fs->getResourceService()->removeProperty( kBootUUIDKey ); fs->terminate( kIOServiceRequired ); // Drop the retain for asynchronous notification fs->release( ); VERBOSE_LOG("%s[%p]::%s returning TRUE\n", kClassName, target, __func__); return true; } DEBUG_LOG("%s[%p]::%s returning false\n", kClassName, target, __func__); #if DEBUG //IOSleep(5000); #endif return false; }
IOMedia * IODVDBlockStorageDriver::instantiateMediaObject(UInt64 base,UInt64 byteSize, UInt32 blockSize,char *mediaName) { IOMedia *media = NULL; if (getMediaType() < kDVDMediaTypeMin || getMediaType() > kDVDMediaTypeMax) { return super::instantiateMediaObject(base,byteSize,blockSize,mediaName); } media = IOBlockStorageDriver::instantiateMediaObject( base,byteSize,blockSize,mediaName); if (media) { const char *description = NULL; const char *picture = NULL; switch (getMediaType()) { case kDVDMediaTypeROM: description = kIODVDMediaTypeROM; picture = "DVD.icns"; break; case kDVDMediaTypeRAM: description = kIODVDMediaTypeRAM; picture = "DVD-RAM.icns"; break; case kDVDMediaTypeR: description = kIODVDMediaTypeR; picture = "DVD-R.icns"; break; case kDVDMediaTypeRW: description = kIODVDMediaTypeRW; picture = "DVD-RW.icns"; break; case kDVDMediaTypePlusR: description = kIODVDMediaTypePlusR; picture = "DVD+R.icns"; break; case kDVDMediaTypePlusRW: description = kIODVDMediaTypePlusRW; picture = "DVD+RW.icns"; break; case kDVDMediaTypeHDROM: description = kIODVDMediaTypeHDROM; picture = "DVD.icns"; break; case kDVDMediaTypeHDRAM: description = kIODVDMediaTypeHDRAM; picture = "DVD-RAM.icns"; break; case kDVDMediaTypeHDR: description = kIODVDMediaTypeHDR; picture = "DVD-R.icns"; break; case kDVDMediaTypeHDRW: description = kIODVDMediaTypeHDRW; picture = "DVD-RW.icns"; break; } if (description) { media->setProperty(kIODVDMediaTypeKey, description); } if (picture) { OSDictionary *dictionary = OSDictionary::withCapacity(2); OSString *identifier = OSString::withCString("com.apple.iokit.IODVDStorageFamily"); OSString *resourceFile = OSString::withCString(picture); if (dictionary && identifier && resourceFile) { dictionary->setObject("CFBundleIdentifier", identifier); dictionary->setObject("IOBundleResourceFile", resourceFile); } media->setProperty(kIOMediaIconKey, dictionary); if (resourceFile) { resourceFile->release(); } if (identifier) { identifier->release(); } if (dictionary) { dictionary->release(); } } } return media; }
IOMedia * IOGUIDPartitionScheme::instantiateMediaObject( gpt_ent * partition, UInt32 partitionID ) { // // Instantiate a new media object to represent the given partition. // IOMedia * media = getProvider(); UInt64 mediaBlockSize = media->getPreferredBlockSize(); UInt64 partitionBase = 0; uuid_string_t partitionHint; char partitionName[36 * 3 + 1]; UInt64 partitionSize = 0; ucs2_to_utf8( partition->ent_name, sizeof(partition->ent_name), partitionName, sizeof(partitionName), UCS_LITTLE_ENDIAN ); uuid_unparse( partition->ent_type, partitionHint ); // 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; partitionSize -= partitionBase - mediaBlockSize; // Create the new media object. IOMedia * newMedia = instantiateDesiredMediaObject( /* partition */ partition, /* partitionID */ partitionID ); 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(partitionName[0] ? partitionName : 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 "Base" key for this partition. newMedia->setProperty(kIOMediaBaseKey, partitionBase, 64); // Set the "Partition ID" key for this partition. newMedia->setProperty(kIOMediaPartitionIDKey, partitionID, 32); // Set the "Universal Unique ID" key for this partition. uuid_string_t uuid; uuid_unparse(partition->ent_uuid, uuid); newMedia->setProperty(kIOMediaUUIDKey, uuid); } else { newMedia->release(); newMedia = 0; } } return newMedia; }
OSSet * IOGUIDPartitionScheme::scan(SInt32 * score) { // // Scan the provider media for a GUID 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; IOByteCount bufferSize = 0; UInt32 fdiskID = 0; disk_blk0 * fdiskMap = 0; UInt64 gptBlock = 0; UInt32 gptCheck = 0; UInt32 gptCount = 0; UInt32 gptID = 0; gpt_ent * gptMap = 0; UInt32 gptSize = 0; UInt32 headerCheck = 0; gpt_hdr * headerMap = 0; UInt32 headerSize = 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(8); if ( partitions == 0 ) goto scanErr; // Open the media with read access. mediaIsOpen = open(this, 0, kIOStorageAccessReader); if ( mediaIsOpen == false ) goto scanErr; // Read the protective map into our buffer. status = media->read(this, 0, buffer); if ( status != kIOReturnSuccess ) goto scanErr; fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy(); // Determine whether the protective map signature is present. if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE ) { goto scanErr; } // Scan for valid partition entries in the protective map. for ( unsigned index = 0; index < DISK_NPART; index++ ) { if ( fdiskMap->parts[index].systid ) { if ( fdiskMap->parts[index].systid == 0xEE ) { if ( fdiskID ) goto scanErr; fdiskID = index + 1; } } } if ( fdiskID == 0 ) goto scanErr; // Read the partition header into our buffer. status = media->read(this, mediaBlockSize, buffer); if ( status != kIOReturnSuccess ) goto scanErr; headerMap = (gpt_hdr *) buffer->getBytesNoCopy(); // Determine whether the partition header signature is present. if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) ) { goto scanErr; } // Determine whether the partition header size is valid. headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self); headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size); if ( headerSize < offsetof(gpt_hdr, padding) ) { goto scanErr; } if ( headerSize > mediaBlockSize ) { goto scanErr; } // Determine whether the partition header checksum is valid. headerMap->hdr_crc_self = 0; if ( crc32(0, headerMap, headerSize) != headerCheck ) { goto scanErr; } // Determine whether the partition entry size is valid. gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table); gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz); if ( gptSize < sizeof(gpt_ent) ) { goto scanErr; } if ( gptSize > UINT16_MAX ) { goto scanErr; } // Determine whether the partition entry count is valid. gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table); gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries); if ( gptCount > UINT16_MAX ) { goto scanErr; } // Allocate a buffer large enough to hold one map, rounded to a media block. buffer->release(); bufferSize = IORound(gptCount * gptSize, mediaBlockSize); buffer = IOBufferMemoryDescriptor::withCapacity( /* capacity */ bufferSize, /* withDirection */ kIODirectionIn ); if ( buffer == 0 ) goto scanErr; // Read the partition header into our buffer. status = media->read(this, gptBlock * mediaBlockSize, buffer); if ( status != kIOReturnSuccess ) goto scanErr; gptMap = (gpt_ent *) buffer->getBytesNoCopy(); // Determine whether the partition entry checksum is valid. if ( crc32(0, gptMap, gptCount * gptSize) != gptCheck ) { goto scanErr; } // Scan for valid partition entries in the partition map. for ( gptID = 1; gptID <= gptCount; gptID++ ) { gptMap = (gpt_ent *) ( ((UInt8 *) buffer->getBytesNoCopy()) + (gptID * gptSize) - gptSize ); uuid_unswap( gptMap->ent_type ); uuid_unswap( gptMap->ent_uuid ); if ( isPartitionUsed( gptMap ) ) { // Determine whether the partition is corrupt (fatal). if ( isPartitionCorrupt( gptMap, gptID ) ) { goto scanErr; } // Determine whether the partition is invalid (skipped). if ( isPartitionInvalid( gptMap, gptID ) ) { continue; } // Create a media object to represent this partition. IOMedia * newMedia = instantiateMediaObject( gptMap, gptID ); if ( newMedia ) { partitions->setObject(newMedia); newMedia->release(); } } } // 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; }
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; }
OSSet * IOPartitionScheme::juxtaposeMediaObjects(OSSet * partitionsOld, OSSet * partitionsNew) { // // Updates a set of existing partitions, represented by partitionsOld, // with possible updates from a rescan of the disk, represented by // partitionsNew. It returns a new set of partitions with the results, // removing partitions from partitionsOld where applicable, adding // partitions from partitionsNew where applicable, and folding in property // changes to partitions from partitionsNew into partitionsOld where // applicable. // OSIterator * iterator = 0; OSIterator * iterator1 = 0; OSIterator * iterator2 = 0; OSSymbol * key; OSSet * keys = 0; IOMedia * partition; IOMedia * partition1; IOMedia * partition2; OSSet * partitions = 0; OSOrderedSet * partitions1 = 0; OSOrderedSet * partitions2 = 0; UInt32 partitionID = 0; OSDictionary * properties; // Allocate a set to hold the set of media objects representing partitions. partitions = OSSet::withCapacity( partitionsNew->getCapacity( ) ); if ( partitions == 0 ) goto juxtaposeErr; // Prepare the reference set of partitions. partitions1 = OSOrderedSet::withCapacity( partitionsOld->getCapacity( ), partitionComparison, 0 ); if ( partitions1 == 0 ) goto juxtaposeErr; iterator1 = OSCollectionIterator::withCollection( partitionsOld ); if ( iterator1 == 0 ) goto juxtaposeErr; while ( ( partition1 = ( IOMedia * ) iterator1->getNextObject( ) ) ) { partitionID = max( partitionID, strtoul( partition1->getLocation( ), NULL, 10 ) ); partitions1->setObject( partition1 ); } iterator1->release( ); iterator1 = 0; // Prepare the comparison set of partitions. partitions2 = OSOrderedSet::withCapacity( partitionsNew->getCapacity( ), partitionComparison, 0 ); if ( partitions2 == 0 ) goto juxtaposeErr; iterator2 = OSCollectionIterator::withCollection( partitionsNew ); if ( iterator2 == 0 ) goto juxtaposeErr; while ( ( partition2 = ( IOMedia * ) iterator2->getNextObject( ) ) ) { partitionID = max( partitionID, strtoul( partition2->getLocation( ), NULL, 10 ) ); partitions2->setObject( partition2 ); } iterator2->release( ); iterator2 = 0; // Juxtapose the partitions. iterator1 = OSCollectionIterator::withCollection( partitions1 ); if ( iterator1 == 0 ) goto juxtaposeErr; iterator2 = OSCollectionIterator::withCollection( partitions2 ); if ( iterator2 == 0 ) goto juxtaposeErr; partition1 = ( IOMedia * ) iterator1->getNextObject( ); partition2 = ( IOMedia * ) iterator2->getNextObject( ); while ( partition1 || partition2 ) { UInt64 base1; UInt64 base2; base1 = partition1 ? partition1->getBase( ) : UINT64_MAX; base2 = partition2 ? partition2->getBase( ) : UINT64_MAX; #if TARGET_OS_EMBEDDED if ( partition1 && partition2 ) { OSString * uuid1; OSString * uuid2; uuid1 = OSDynamicCast( OSString, partition1->getProperty( kIOMediaUUIDKey ) ); uuid2 = OSDynamicCast( OSString, partition2->getProperty( kIOMediaUUIDKey ) ); if ( uuid1 || uuid2 ) { if ( uuid1 == 0 ) { base1 = UINT64_MAX; } else if ( uuid2 == 0 ) { base2 = UINT64_MAX; } else { int compare; compare = strcmp( uuid1->getCStringNoCopy( ), uuid2->getCStringNoCopy( ) ); if ( compare > 0 ) { base1 = UINT64_MAX; } else if ( compare < 0 ) { base2 = UINT64_MAX; } else { base1 = base2; } } } } #endif /* TARGET_OS_EMBEDDED */ if ( base1 > base2 ) { // A partition was added. partition2->setProperty( kIOMediaLiveKey, true ); iterator = OSCollectionIterator::withCollection( partitions1 ); if ( iterator == 0 ) goto juxtaposeErr; while ( ( partition = ( IOMedia * ) iterator->getNextObject( ) ) ) { if ( strcmp( partition->getLocation( ), partition2->getLocation( ) ) == 0 ) { // Set a location value for this partition. char location[ 12 ]; partitionID++; snprintf( location, sizeof( location ), "%d", ( int ) partitionID ); partition2->setLocation( location ); partition2->setProperty( kIOMediaLiveKey, false ); break; } } iterator->release( ); iterator = 0; if ( partition2->attach( this ) ) { attachMediaObjectToDeviceTree( partition2 ); partition2->registerService( kIOServiceAsynchronous ); } partitions->setObject( partition2 ); partition2 = ( IOMedia * ) iterator2->getNextObject( ); } else if ( base1 < base2 ) { // A partition was removed. partition1->setProperty( kIOMediaLiveKey, false ); if ( handleIsOpen( partition1 ) == false ) { partition1->terminate( kIOServiceSynchronous ); detachMediaObjectFromDeviceTree( partition1 ); } else { partition1->removeProperty( kIOMediaPartitionIDKey ); partitions->setObject( partition1 ); } partition1 = ( IOMedia * ) iterator1->getNextObject( ); } else { // A partition was matched. bool edit; bool move; edit = false; move = false; keys = OSSet::withCapacity( 1 ); if ( keys == 0 ) goto juxtaposeErr; properties = partition2->getPropertyTable( ); // Determine which properties were updated. if ( partition1->getBase( ) != partition2->getBase( ) || partition1->getSize( ) != partition2->getSize( ) || partition1->getPreferredBlockSize( ) != partition2->getPreferredBlockSize( ) || partition1->getAttributes( ) != partition2->getAttributes( ) || partition1->isWhole( ) != partition2->isWhole( ) || partition1->isWritable( ) != partition2->isWritable( ) || strcmp( partition1->getContentHint( ), partition2->getContentHint( ) ) ) { edit = true; } if ( strcmp( partition1->getName( ), partition2->getName( ) ) || strcmp( partition1->getLocation( ), partition2->getLocation( ) ) ) { move = true; } iterator = OSCollectionIterator::withCollection( properties ); if ( iterator == 0 ) goto juxtaposeErr; while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) ) { OSObject * value1; OSObject * value2; if ( key->isEqualTo( kIOMediaContentHintKey ) || key->isEqualTo( kIOMediaEjectableKey ) || key->isEqualTo( kIOMediaPreferredBlockSizeKey ) || key->isEqualTo( kIOMediaRemovableKey ) || key->isEqualTo( kIOMediaSizeKey ) || key->isEqualTo( kIOMediaWholeKey ) || key->isEqualTo( kIOMediaWritableKey ) ) { continue; } if ( key->isEqualTo( kIOMediaContentKey ) || key->isEqualTo( kIOMediaLeafKey ) || key->isEqualTo( kIOMediaLiveKey ) || key->isEqualTo( kIOMediaOpenKey ) ) { continue; } value1 = partition1->getProperty( key ); value2 = partition2->getProperty( key ); if ( value1 == 0 || value1->isEqualTo( value2 ) == false ) { keys->setObject( key ); } } iterator->release( ); iterator = 0; // A partition was updated. partition1->setProperty( kIOMediaLiveKey, ( move == false ) ); if ( edit ) { partition1->init( partition2->getBase( ), partition2->getSize( ), partition2->getPreferredBlockSize( ), partition2->getAttributes( ), partition2->isWhole( ), partition2->isWritable( ), partition2->getContentHint( ) ); } if ( keys->getCount( ) ) { iterator = OSCollectionIterator::withCollection( keys ); if ( iterator == 0 ) goto juxtaposeErr; while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) ) { partition1->setProperty( key, partition2->getProperty( key ) ); } iterator->release( ); iterator = 0; } if ( edit || keys->getCount( ) ) { partition1->messageClients( kIOMessageServicePropertyChange ); partition1->registerService( kIOServiceAsynchronous ); } keys->release( ); keys = 0; partitions->setObject( partition1 ); partition1 = ( IOMedia * ) iterator1->getNextObject( ); partition2 = ( IOMedia * ) iterator2->getNextObject( ); } } // Release our resources. iterator1->release( ); iterator2->release( ); partitions1->release( ); partitions2->release( ); return partitions; juxtaposeErr: // Release our resources. if ( iterator ) iterator->release( ); if ( iterator1 ) iterator1->release( ); if ( iterator2 ) iterator2->release( ); if ( keys ) keys->release( ); if ( partitions ) partitions->release( ); if ( partitions1 ) partitions1->release( ); if ( partitions2 ) partitions2->release( ); return 0; }