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;
}
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;
}