IOPartitionScheme.cpp [plain text]
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOMessage.h>
#include <IOKit/storage/IOPartitionScheme.h>
#define super IOStorage
OSDefineMetaClassAndStructors(IOPartitionScheme, IOStorage)
#ifndef __LP64__
extern IOStorageAttributes gIOStorageAttributesUnsupported;
#endif
static SInt32 partitionComparison( const OSMetaClassBase * object1,
const OSMetaClassBase * object2,
void * context )
{
UInt64 base1 = ( ( IOMedia * ) object1 )->getBase( );
UInt64 base2 = ( ( IOMedia * ) object2 )->getBase( );
if ( base1 < base2 ) return 1;
if ( base1 > base2 ) return -1;
return 0;
}
IOMedia * IOPartitionScheme::getProvider() const
{
return (IOMedia *) IOService::getProvider();
}
bool IOPartitionScheme::init(OSDictionary * properties)
{
if (super::init(properties) == false) return false;
_openLevel = kIOStorageAccessNone;
_openReaders = OSSet::withCapacity(16);
_openReaderWriters = OSSet::withCapacity(16);
if (_openReaders == 0 || _openReaderWriters == 0) return false;
return true;
}
void IOPartitionScheme::free()
{
if (_openReaders) _openReaders->release();
if (_openReaderWriters) _openReaderWriters->release();
super::free();
}
bool IOPartitionScheme::handleOpen(IOService * client,
IOOptionBits options,
void * argument)
{
IOStorageAccess access = (uintptr_t) argument;
IOStorageAccess level;
assert(client);
assert( access == kIOStorageAccessReader ||
access == kIOStorageAccessReaderWriter );
unsigned writers = _openReaderWriters->getCount();
if (_openReaderWriters->containsObject(client)) writers--;
if (access == kIOStorageAccessReaderWriter) writers++;
level = (writers) ? kIOStorageAccessReaderWriter : kIOStorageAccessReader;
if ( _openLevel != level )
{
IOStorage * provider;
provider = OSDynamicCast( IOStorage, getProvider( ) );
if ( provider )
{
bool success;
level = ( level | kIOStorageAccessSharedLock );
success = provider->open( this, options, level );
level = ( level & kIOStorageAccessReaderWriter );
if ( success == false )
{
return false;
}
}
}
if (access == kIOStorageAccessReader)
{
_openReaders->setObject(client);
_openReaderWriters->removeObject(client); }
else {
_openReaderWriters->setObject(client);
_openReaders->removeObject(client); }
_openLevel = level;
return true;
}
bool IOPartitionScheme::handleIsOpen(const IOService * client) const
{
if (client == 0) return (_openLevel != kIOStorageAccessNone);
return ( _openReaderWriters->containsObject(client) ||
_openReaders->containsObject(client) );
}
void IOPartitionScheme::handleClose(IOService * client, IOOptionBits options)
{
assert(client);
if (_openReaderWriters->containsObject(client)) {
_openReaderWriters->removeObject(client);
}
else if (_openReaders->containsObject(client)) {
_openReaders->removeObject(client);
}
else {
assert(0);
return;
}
IOStorageAccess level;
if (_openReaderWriters->getCount()) level = kIOStorageAccessReaderWriter;
else if (_openReaders->getCount()) level = kIOStorageAccessReader;
else level = kIOStorageAccessNone;
if ( _openLevel != level )
{
IOStorage * provider;
provider = OSDynamicCast( IOStorage, getProvider( ) );
if ( provider )
{
if ( level == kIOStorageAccessNone )
{
provider->close( this, options );
}
else
{
bool success;
level = ( level | kIOStorageAccessSharedLock );
success = provider->open( this, 0, level );
level = ( level & kIOStorageAccessReaderWriter );
assert( success );
}
}
_openLevel = level;
}
}
void IOPartitionScheme::read(IOService * client,
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageAttributes * attributes,
IOStorageCompletion * completion)
{
#ifndef __LP64__
if ( IOStorage::_expansionData )
{
if ( attributes == &gIOStorageAttributesUnsupported )
{
attributes = NULL;
}
else
{
IOStorage::read( client, byteStart, buffer, attributes, completion );
return;
}
}
#endif
getProvider( )->read( this, byteStart, buffer, attributes, completion );
}
void IOPartitionScheme::write(IOService * client,
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageAttributes * attributes,
IOStorageCompletion * completion)
{
#ifndef __LP64__
if ( IOStorage::_expansionData )
{
if ( attributes == &gIOStorageAttributesUnsupported )
{
attributes = NULL;
}
else
{
IOStorage::write( client, byteStart, buffer, attributes, completion );
return;
}
}
#endif
getProvider( )->write( this, byteStart, buffer, attributes, completion );
}
IOReturn IOPartitionScheme::synchronizeCache(IOService * client)
{
return getProvider()->synchronizeCache(this);
}
IOReturn IOPartitionScheme::discard(IOService * client,
UInt64 byteStart,
UInt64 byteCount)
{
return getProvider( )->discard( this, byteStart, byteCount );
}
#ifdef __LP64__
bool IOPartitionScheme::attachMediaObjectToDeviceTree(IOMedia * media)
#else
bool IOPartitionScheme::attachMediaObjectToDeviceTree(IOMedia * media,
IOOptionBits options)
#endif
{
IORegistryEntry * parent = this;
while ( (parent = parent->getParentEntry(gIOServicePlane)) )
{
if ( parent->inPlane(gIODTPlane) )
{
char location[ 32 ];
const char * locationOfParent = parent->getLocation(gIODTPlane);
const char * nameOfParent = parent->getName(gIODTPlane);
if ( locationOfParent == 0 ) break;
if ( OSDynamicCast(IOMedia, parent) == 0 ) break;
parent = parent->getParentEntry(gIODTPlane);
if ( parent == 0 ) break;
if ( media->attachToParent(parent, gIODTPlane) == false ) break;
strlcpy(location, locationOfParent, sizeof(location));
if ( strchr(location, ':') ) *(strchr(location, ':') + 1) = 0;
strlcat(location, media->getLocation(), sizeof(location) - strlen(location));
media->setLocation(location, gIODTPlane);
media->setName(nameOfParent, gIODTPlane);
return true;
}
}
return false;
}
#ifdef __LP64__
void IOPartitionScheme::detachMediaObjectFromDeviceTree(IOMedia * media)
#else
void IOPartitionScheme::detachMediaObjectFromDeviceTree(IOMedia * media,
IOOptionBits options)
#endif
{
IORegistryEntry * parent;
if ( (parent = media->getParentEntry(gIODTPlane)) )
{
media->detachFromParent(parent, gIODTPlane);
}
}
OSSet * IOPartitionScheme::juxtaposeMediaObjects(OSSet * partitionsOld,
OSSet * partitionsNew)
{
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;
partitions = OSSet::withCapacity( partitionsNew->getCapacity( ) );
if ( partitions == 0 ) goto juxtaposeErr;
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;
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;
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 ( base1 > base2 )
{
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 )
{
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 )
{
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
{
bool edit;
bool move;
edit = false;
move = false;
keys = OSSet::withCapacity( 1 );
if ( keys == 0 ) goto juxtaposeErr;
properties = partition2->getPropertyTable( );
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;
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( );
}
}
iterator1->release( );
iterator2->release( );
partitions1->release( );
partitions2->release( );
return partitions;
juxtaposeErr:
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;
}
#ifdef __LP64__
OSMetaClassDefineReservedUnused(IOPartitionScheme, 0);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 1);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 2);
#else
OSMetaClassDefineReservedUsed(IOPartitionScheme, 0);
OSMetaClassDefineReservedUsed(IOPartitionScheme, 1);
OSMetaClassDefineReservedUsed(IOPartitionScheme, 2);
#endif
OSMetaClassDefineReservedUnused(IOPartitionScheme, 3);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 4);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 5);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 6);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 7);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 8);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 9);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 10);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 11);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 12);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 13);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 14);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 15);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 16);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 17);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 18);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 19);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 20);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 21);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 22);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 23);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 24);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 25);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 26);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 27);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 28);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 29);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 30);
OSMetaClassDefineReservedUnused(IOPartitionScheme, 31);
#ifndef __LP64__
extern "C" void _ZN17IOPartitionScheme4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOPartitionScheme * scheme, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion )
{
scheme->read( client, byteStart, buffer, NULL, &completion );
}
extern "C" void _ZN17IOPartitionScheme5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOPartitionScheme * scheme, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion )
{
scheme->write( client, byteStart, buffer, NULL, &completion );
}
#endif