IOAppleLabelScheme.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOLib.h>
#include <IOKit/storage/IOAppleLabelScheme.h>
#include <libkern/OSByteOrder.h>
#define super IOFilterScheme
OSDefineMetaClassAndStructors(IOAppleLabelScheme, IOFilterScheme);
#define kIOMediaBaseKey "Base"
bool IOAppleLabelScheme::init(OSDictionary * properties)
{
assert(sizeof(applelabel) == 512);
if (super::init(properties) == false) return false;
_content = 0;
return true;
}
void IOAppleLabelScheme::free()
{
if ( _content ) _content->release();
super::free();
}
IOService * IOAppleLabelScheme::probe(IOService * provider, SInt32 * score)
{
assert(OSDynamicCast(IOMedia, provider));
if (super::probe(provider, score) == 0) return 0;
_content = scan(score);
return ( _content ) ? this : 0;
}
bool IOAppleLabelScheme::start(IOService * provider)
{
assert(_content);
if ( super::start(provider) == false ) return false;
_content->attach(this);
attachMediaObjectToDeviceTree(_content);
_content->registerService();
return true;
}
void IOAppleLabelScheme::stop(IOService * provider)
{
assert(_content);
detachMediaObjectFromDeviceTree(_content);
super::stop(provider);
}
IOMedia * IOAppleLabelScheme::scan(SInt32 * score)
{
IOBufferMemoryDescriptor * buffer = 0;
UInt64 bufferBase = 0;
UInt32 bufferSize = 0;
applelabel * headerMap = 0;
UInt64 labelBase = 0;
UInt32 labelCheck = 0;
char * labelMap = 0;
UInt32 labelSize = 0;
IOMedia * media = getProvider();
UInt64 mediaBlockSize = media->getPreferredBlockSize();
bool mediaIsOpen = false;
IOMedia * newMedia = 0;
OSDictionary * properties = 0;
IOReturn status = kIOReturnError;
if ( media->isFormatted() == false ) goto scanErr;
if ( (mediaBlockSize % sizeof(applelabel)) ) goto scanErr;
bufferSize = IORound(sizeof(applelabel), mediaBlockSize);
buffer = IOBufferMemoryDescriptor::withCapacity(
bufferSize,
kIODirectionIn );
if ( buffer == 0 ) goto scanErr;
mediaIsOpen = media->open(this, 0, kIOStorageAccessReader);
if ( mediaIsOpen == false ) goto scanErr;
status = media->read(this, 0, buffer);
if ( status != kIOReturnSuccess ) goto scanErr;
headerMap = (applelabel *) buffer->getBytesNoCopy();
if ( OSSwapBigToHostInt16(headerMap->al_magic) != AL_MAGIC )
{
goto scanErr;
}
if ( OSSwapBigToHostInt16(headerMap->al_type) != AL_TYPE_DEFAULT )
{
goto scanErr;
}
labelBase = OSSwapBigToHostInt64(headerMap->al_offset);
labelCheck = OSSwapBigToHostInt32(headerMap->al_checksum);
labelSize = OSSwapBigToHostInt32(headerMap->al_size);
if ( labelSize > 131072 )
{
goto scanErr;
}
buffer->release();
bufferBase = IOTrunc(labelBase, mediaBlockSize);
bufferSize = IORound(labelBase + labelSize, mediaBlockSize) - bufferBase;
buffer = IOBufferMemoryDescriptor::withCapacity(
bufferSize,
kIODirectionIn );
if ( buffer == 0 ) goto scanErr;
if ( bufferBase + bufferSize > media->getSize() ) goto scanErr;
status = media->read(this, bufferBase, buffer);
if ( status != kIOReturnSuccess ) goto scanErr;
labelMap = (char *) buffer->getBytesNoCopy() + (labelBase % mediaBlockSize);
if ( crc32(0, labelMap, labelSize) != labelCheck )
{
goto scanErr;
}
properties = (OSDictionary *) OSUnserializeXML(labelMap, labelSize);
if ( OSDynamicCast(OSDictionary, properties) == 0 )
{
goto scanErr;
}
if ( isContentCorrupt(properties) )
{
goto scanErr;
}
if ( isContentInvalid(properties) )
{
goto scanErr;
}
newMedia = instantiateMediaObject(properties);
if ( newMedia == 0 )
{
goto scanErr;
}
media->close(this);
buffer->release();
properties->release();
return newMedia;
scanErr:
if ( mediaIsOpen ) media->close(this);
if ( buffer ) buffer->release();
if ( properties ) properties->release();
return 0;
}
bool IOAppleLabelScheme::isContentCorrupt(OSDictionary * properties)
{
return false;
}
bool IOAppleLabelScheme::isContentInvalid(OSDictionary * properties)
{
UInt64 contentBase = 0;
UInt64 contentSize = 0;
IOMedia * media = getProvider();
OSObject * object = 0;
object = properties->getObject(kIOMediaBaseKey);
if ( OSDynamicCast(OSNumber, object) )
{
contentBase = ((OSNumber *) object)->unsigned64BitValue();
}
object = properties->getObject(kIOMediaSizeKey);
if ( OSDynamicCast(OSNumber, object) )
{
contentSize = ((OSNumber *) object)->unsigned64BitValue();
}
if ( contentSize == 0 ) return true;
if ( contentBase + contentSize > media->getSize() ) return true;
return false;
}
IOMedia * IOAppleLabelScheme::instantiateMediaObject(OSDictionary * properties)
{
IOMediaAttributeMask contentAttributes = 0;
UInt64 contentBase = 0;
UInt64 contentBlockSize = 0;
const char * contentHint = 0;
bool contentIsWhole = false;
bool contentIsWritable = false;
UInt64 contentSize = 0;
IOMedia * media = getProvider();
IOMedia * newMedia = 0;
OSObject * object = 0;
contentAttributes = media->getAttributes();
contentBlockSize = media->getPreferredBlockSize();
contentIsWhole = media->isWhole();
contentIsWritable = media->isWritable();
contentSize = media->getSize();
properties = OSDictionary::withDictionary(properties);
if ( properties == 0 ) return 0;
object = properties->getObject(kIOMediaBaseKey);
if ( OSDynamicCast(OSNumber, object) )
{
contentBase = ((OSNumber *) object)->unsigned64BitValue();
}
properties->removeObject(kIOMediaBaseKey);
object = properties->getObject(kIOMediaContentKey);
if ( OSDynamicCast(OSString, object) )
{
contentHint = ((OSString *) object)->getCStringNoCopy();
}
properties->removeObject(kIOMediaContentKey);
object = properties->getObject(kIOMediaContentHintKey);
if ( OSDynamicCast(OSString, object) )
{
contentHint = ((OSString *) object)->getCStringNoCopy();
}
properties->removeObject(kIOMediaContentHintKey);
object = properties->getObject(kIOMediaEjectableKey);
if ( OSDynamicCast(OSBoolean, object) )
{
if ( ((OSBoolean *) object)->getValue() )
{
contentAttributes |= kIOMediaAttributeEjectableMask;
}
else
{
contentAttributes &= ~kIOMediaAttributeEjectableMask;
}
}
properties->removeObject(kIOMediaEjectableKey);
object = properties->getObject(kIOMediaPreferredBlockSizeKey);
if ( OSDynamicCast(OSNumber, object) )
{
contentBlockSize = ((OSNumber *) object)->unsigned64BitValue();
}
properties->removeObject(kIOMediaPreferredBlockSizeKey);
object = properties->getObject(kIOMediaRemovableKey);
if ( OSDynamicCast(OSBoolean, object) )
{
if ( ((OSBoolean *) object)->getValue() )
{
contentAttributes |= kIOMediaAttributeRemovableMask;
}
else
{
contentAttributes &= ~kIOMediaAttributeRemovableMask;
}
}
properties->removeObject(kIOMediaRemovableKey);
object = properties->getObject(kIOMediaWholeKey);
if ( OSDynamicCast(OSBoolean, object) )
{
contentIsWhole = ((OSBoolean *) object)->getValue();
}
properties->removeObject(kIOMediaWholeKey);
object = properties->getObject(kIOMediaSizeKey);
if ( OSDynamicCast(OSNumber, object) )
{
contentSize = ((OSNumber *) object)->unsigned64BitValue();
}
properties->removeObject(kIOMediaSizeKey);
object = properties->getObject(kIOMediaWritableKey);
if ( OSDynamicCast(OSBoolean, object) )
{
contentIsWritable = ((OSBoolean *) object)->getValue();
}
properties->removeObject(kIOMediaWritableKey);
newMedia = instantiateDesiredMediaObject(properties);
if ( newMedia )
{
if ( newMedia->init(
contentBase,
contentSize,
contentBlockSize,
contentAttributes,
contentIsWhole,
contentIsWritable,
contentHint ) )
{
newMedia->setLocation("1");
newMedia->getPropertyTable()->merge(properties);
}
else
{
newMedia->release();
newMedia = 0;
}
}
properties->release();
return newMedia;
}
IOMedia * IOAppleLabelScheme::instantiateDesiredMediaObject(
OSDictionary * properties )
{
return new IOMedia;
}
bool IOAppleLabelScheme::attachMediaObjectToDeviceTree( IOMedia * media )
{
IORegistryEntry * child;
if ( (child = getParentEntry(gIOServicePlane)) )
{
IORegistryEntry * parent;
if ( (parent = child->getParentEntry(gIODTPlane)) )
{
const char * location = child->getLocation(gIODTPlane);
const char * name = child->getName(gIODTPlane);
if ( media->attachToParent(parent, gIODTPlane) )
{
media->setLocation(location, gIODTPlane);
media->setName(name, gIODTPlane);
child->detachFromParent(parent, gIODTPlane);
return true;
}
}
}
return false;
}
void IOAppleLabelScheme::detachMediaObjectFromDeviceTree( IOMedia * media )
{
IORegistryEntry * child;
if ( (child = getParentEntry(gIOServicePlane)) )
{
IORegistryEntry * parent;
if ( (parent = media->getParentEntry(gIODTPlane)) )
{
const char * location = media->getLocation(gIODTPlane);
const char * name = media->getName(gIODTPlane);
if ( child->attachToParent(parent, gIODTPlane) )
{
child->setLocation(location, gIODTPlane);
child->setName(name, gIODTPlane);
}
media->detachFromParent(parent, gIODTPlane);
}
}
}
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 0);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 1);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 2);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 3);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 4);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 5);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 6);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 7);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 8);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 9);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 10);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 11);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 12);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 13);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 14);
OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 15);