1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- gpt.c
- Abstract:
- This module contains GPT support for the partition library.
- Author:
- Evan Green 6-Feb-2014
- Environment:
- Any
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "partlibp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- PartpGptReadEntries (
- PPARTITION_CONTEXT Context,
- PVOID Block,
- PGPT_PARTITION_ENTRY *Entries,
- PVOID *EntriesAllocation,
- PULONG EntryCount,
- PULONG ValidCount
- );
- KSTATUS
- PartpGptWriteBlocks (
- PPARTITION_CONTEXT Context,
- ULONGLONG BlockAddress,
- ULONG BlockCount,
- PVOID Buffer
- );
- KSTATUS
- PartpGptConvertPartitionTypeToGuid (
- PARTITION_TYPE PartitionType,
- UCHAR TypeGuid[GPT_GUID_SIZE]
- );
- BOOL
- PartpGptIsGuidEmpty (
- UCHAR Guid[GPT_GUID_SIZE]
- );
- BOOL
- PartpGptAreGuidsEqual (
- UCHAR FirstGuid[GPT_GUID_SIZE],
- UCHAR SecondGuid[GPT_GUID_SIZE]
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define the mapping of known partition types. The first entry here is
- // assumed to be the empty GUID.
- //
- PARTITION_TYPE_GUID_MAPPING PartTypeGuidToPartitionTypeTable[] = {
- {GPT_PARTITION_TYPE_EMPTY, PartitionTypeEmpty},
- {GPT_PARTITION_TYPE_EFI_SYSTEM, PartitionTypeEfiSystem},
- {GPT_PARTITION_TYPE_MINOCA, PartitionTypeMinoca},
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- BOOL
- PartpGptIsProtectiveMbr (
- PARTITION_TABLE_ENTRY Entry[PARTITION_TABLE_SIZE]
- )
- /*++
- Routine Description:
- This routine determines if the given partition table is a protective MBR
- for a GPT disk.
- Arguments:
- Entry - Supplies the array of MBR partition table entries.
- Return Value:
- TRUE if this is a GPT disk.
- FALSE if this is not a GPT disk.
- --*/
- {
- BOOL FoundEfiEntry;
- ULONG Index;
- FoundEfiEntry = FALSE;
- for (Index = 0; Index < PARTITION_TABLE_SIZE; Index += 1) {
- if (Entry->SystemId == PARTITION_ID_EMPTY) {
- continue;
- }
- if ((Entry->SystemId == PARTITION_ID_EFI_GPT) &&
- (Entry->StartingLba == 1)) {
- FoundEfiEntry = TRUE;
- //
- // Anything other than empty, GPT, or EFI system partitions mean it's
- // not a GPT disk.
- //
- } else {
- return FALSE;
- }
- }
- return FoundEfiEntry;
- }
- KSTATUS
- PartpGptEnumeratePartitions (
- PPARTITION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine is called to read the partition information from the
- GPT-formatted disk and enumerate the list of partitions.
- Arguments:
- Context - Supplies a pointer to the initialized context.
- Return Value:
- STATUS_SUCCESS if the partition information could be determined. There
- could still be zero partitions in this case.
- STATUS_NO_ELIGIBLE_DEVICES if the partition table is invalid.
- Error codes on device read or allocation failure.
- --*/
- {
- ULONG AllocationSize;
- PVOID Block;
- PVOID BlockAllocation;
- ULONG BlockSize;
- ULONG EntryCount;
- ULONG EntryIndex;
- PGPT_PARTITION_ENTRY GptEntry;
- ULONGLONG GptHeaderLba;
- PGPT_HEADER Header;
- PPARTITION_INFORMATION Information;
- ULONG InformationIndex;
- PPARTITION_INFORMATION Partition;
- PGPT_PARTITION_ENTRY PartitionEntries;
- PVOID PartitionEntriesAllocation;
- KSTATUS Status;
- ULONG ValidCount;
- BlockSize = Context->BlockSize;
- Information = NULL;
- PartitionEntriesAllocation = NULL;
- BlockAllocation = PartpAllocateIo(Context, BlockSize, &Block);
- if (BlockAllocation == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GptEnumeratePartitionsEnd;
- }
- //
- // Read LBA 1 to get the GPT header.
- //
- GptHeaderLba = 1;
- Status = Context->ReadFunction(Context, GptHeaderLba, Block);
- if (!KSUCCESS(Status)) {
- goto GptEnumeratePartitionsEnd;
- }
- //
- // Validate the header here. If it wasn't valid, try the header that's at
- // the last sector of the disk.
- //
- Status = PartpGptReadEntries(Context,
- Block,
- &PartitionEntries,
- &PartitionEntriesAllocation,
- &EntryCount,
- &ValidCount);
- if ((!KSUCCESS(Status)) && (Context->BlockCount != 0)) {
- GptHeaderLba = Context->BlockCount - 1;
- Status = Context->ReadFunction(Context, GptHeaderLba, Block);
- if (!KSUCCESS(Status)) {
- goto GptEnumeratePartitionsEnd;
- }
- Status = PartpGptReadEntries(Context,
- Block,
- &PartitionEntries,
- &PartitionEntriesAllocation,
- &EntryCount,
- &ValidCount);
- }
- //
- // If neither header is valid, abort.
- //
- if (!KSUCCESS(Status)) {
- goto GptEnumeratePartitionsEnd;
- }
- Header = (PGPT_HEADER)Block;
- ASSERT(sizeof(Context->DiskIdentifier) >= sizeof(Header->DiskGuid));
- RtlCopyMemory(Context->DiskIdentifier,
- Header->DiskGuid,
- sizeof(Context->DiskIdentifier));
- if (ValidCount == 0) {
- Status = STATUS_SUCCESS;
- goto GptEnumeratePartitionsEnd;
- }
- //
- // Allocate space for the partition information structures.
- //
- AllocationSize = sizeof(PARTITION_INFORMATION) * ValidCount;
- Information = Context->AllocateFunction(AllocationSize);
- if (Information == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GptEnumeratePartitionsEnd;
- }
- RtlZeroMemory(Information, AllocationSize);
- //
- // Loop through and convert all the GPT entries to partition information
- // structures.
- //
- InformationIndex = 0;
- for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex += 1) {
- GptEntry = &(PartitionEntries[EntryIndex]);
- if ((GptEntry->FirstLba == 0) ||
- (GptEntry->LastLba == 0)) {
- continue;
- }
- if (PartpGptIsGuidEmpty(GptEntry->TypeGuid) != FALSE) {
- continue;
- }
- ASSERT(InformationIndex < ValidCount);
- Partition = &(Information[InformationIndex]);
- Partition->StartOffset = GptEntry->FirstLba;
- Partition->EndOffset = GptEntry->LastLba + 1;
- Partition->Number = EntryIndex + 1;
- ASSERT(PARTITION_IDENTIFIER_SIZE >= GPT_GUID_SIZE);
- RtlCopyMemory(Partition->TypeIdentifier,
- GptEntry->TypeGuid,
- sizeof(Partition->TypeIdentifier));
- RtlCopyMemory(Partition->Identifier,
- GptEntry->Guid,
- sizeof(Partition->TypeIdentifier));
- Partition->PartitionType =
- PartpGptConvertTypeGuidToPartitionType(GptEntry->TypeGuid);
- InformationIndex += 1;
- }
- ASSERT(InformationIndex == ValidCount);
- Context->Partitions = Information;
- Context->PartitionCount = InformationIndex;
- Information = NULL;
- Status = STATUS_SUCCESS;
- GptEnumeratePartitionsEnd:
- if (PartitionEntriesAllocation != NULL) {
- Context->FreeFunction(PartitionEntriesAllocation);
- }
- if (Information != NULL) {
- Context->FreeFunction(Information);
- }
- if (BlockAllocation != NULL) {
- Context->FreeFunction(BlockAllocation);
- }
- return Status;
- }
- KSTATUS
- PartpGptWritePartitionLayout (
- PPARTITION_CONTEXT Context,
- PPARTITION_INFORMATION Partitions,
- ULONG PartitionCount,
- BOOL CleanMbr
- )
- /*++
- Routine Description:
- This routine writes a GPT partition layout to the disk. This usually wipes
- out all data on the disk.
- Arguments:
- Context - Supplies a pointer to the partition context.
- Partitions - Supplies a pointer to the new partition layout.
- PartitionCount - Supplies the number of partitions in the new layout.
- CleanMbr - Supplies a boolean indicating if only the partition entries of
- the MBR should be modified (FALSE) or if the whole MBR should be
- zeroed before being written (TRUE).
- Return Value:
- Status code.
- --*/
- {
- ULONG BlockSize;
- ULONG EntriesBlockCount;
- ULONG EntriesSize;
- ULONG EntryCount;
- ULONGLONG FirstUsableBlock;
- PGPT_PARTITION_ENTRY GptEntries;
- PGPT_PARTITION_ENTRY GptEntry;
- PGPT_HEADER Header;
- ULONGLONG LastUsableBlock;
- PPARTITION_TABLE_ENTRY MbrEntry;
- PPARTITION_INFORMATION Partition;
- ULONG PartitionIndex;
- PUSHORT Pointer16;
- KSTATUS Status;
- PVOID Table;
- PVOID TableAllocation;
- TableAllocation = NULL;
- if (Context->BlockCount < 12) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GptWritePartitionLayoutEnd;
- }
- if (Context->FillRandomFunction == NULL) {
- Status = STATUS_NOT_INITIALIZED;
- goto GptWritePartitionLayoutEnd;
- }
- BlockSize = Context->BlockSize;
- ASSERT(POWER_OF_2(BlockSize));
- EntriesSize = PartitionCount * sizeof(GPT_PARTITION_ENTRY);
- if (EntriesSize < GPT_MINIMUM_PARTITION_ENTRIES_SIZE) {
- EntriesSize = GPT_MINIMUM_PARTITION_ENTRIES_SIZE;
- }
- EntriesSize = ALIGN_RANGE_UP(EntriesSize, BlockSize);
- EntriesBlockCount = (EntriesSize / BlockSize);
- EntryCount = EntriesSize / sizeof(GPT_PARTITION_ENTRY);
- //
- // Make sure the first usable block is aligned to 4KB so that disks that
- // internally use 4KB sectors but report 512 byte sectors don't have
- // performance issues doing read/modify/writes all the time within the
- // partition. Remember that the first two blocks are reserved for the
- // protective MBR and the GPT header.
- //
- FirstUsableBlock = 2 + EntriesBlockCount;
- FirstUsableBlock = ALIGN_RANGE_UP(FirstUsableBlock * BlockSize,
- GPT_PARTITION_ALIGNMENT);
- FirstUsableBlock /= BlockSize;
- //
- // Allocate space for the entire table.
- //
- TableAllocation = PartpAllocateIo(Context,
- FirstUsableBlock * BlockSize,
- &Table);
- if (TableAllocation == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GptWritePartitionLayoutEnd;
- }
- RtlZeroMemory(Table, FirstUsableBlock * BlockSize);
- Header = (PGPT_HEADER)(Table + BlockSize);
- LastUsableBlock = (Context->BlockCount - 1) - (EntriesBlockCount + 1);
- //
- // First fill out the partition entries array.
- //
- GptEntries = (PGPT_PARTITION_ENTRY)(Table + (2 * BlockSize));
- for (PartitionIndex = 0;
- PartitionIndex < PartitionCount;
- PartitionIndex += 1) {
- GptEntry = &(GptEntries[PartitionIndex]);
- Partition = &(Partitions[PartitionIndex]);
- //
- // Convert the type enum if it's set, otherwise, just copy the type
- // identifier GUID.
- //
- if ((Partition->PartitionType != PartitionTypeInvalid) &&
- (Partition->PartitionType != PartitionTypeUnknown)) {
- Status = PartpGptConvertPartitionTypeToGuid(
- Partition->PartitionType,
- GptEntry->TypeGuid);
- if (!KSUCCESS(Status)) {
- goto GptWritePartitionLayoutEnd;
- }
- } else {
- ASSERT(sizeof(GptEntry->TypeGuid) <=
- sizeof(Partition->TypeIdentifier));
- RtlCopyMemory(GptEntry->TypeGuid,
- Partition->TypeIdentifier,
- sizeof(GptEntry->TypeGuid));
- }
- //
- // Copy the GUID if it's not the empty one. If it is, create a random
- // one.
- //
- if (PartpGptIsGuidEmpty(Partition->Identifier) != FALSE) {
- Context->FillRandomFunction(Context,
- GptEntry->Guid,
- sizeof(GptEntry->Guid));
- } else {
- ASSERT(sizeof(GptEntry->Guid) <= sizeof(Partition->Identifier));
- RtlCopyMemory(GptEntry->Guid,
- Partition->Identifier,
- sizeof(GptEntry->Guid));
- }
- GptEntry->Attributes = Partition->Attributes;
- GptEntry->FirstLba = Partition->StartOffset;
- if (Partition->EndOffset != 0) {
- GptEntry->LastLba = Partition->EndOffset - 1;
- }
- if ((GptEntry->FirstLba != GptEntry->LastLba) &&
- ((GptEntry->FirstLba < FirstUsableBlock) ||
- (GptEntry->FirstLba > LastUsableBlock) ||
- (GptEntry->LastLba < FirstUsableBlock) ||
- (GptEntry->LastLba > LastUsableBlock))) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GptWritePartitionLayoutEnd;
- }
- }
- //
- // Create the backup copy first as requested by the specification.
- //
- Header->Signature = GPT_HEADER_SIGNATURE;
- Header->Revision = GPT_HEADER_REVISION_1;
- Header->HeaderSize = sizeof(GPT_HEADER);
- Header->CurrentLba = Context->BlockCount - 1;
- Header->BackupLba = 1;
- Header->FirstUsableLba = FirstUsableBlock;
- Header->LastUsableLba = LastUsableBlock;
- if (PartpGptIsGuidEmpty(Context->DiskIdentifier) != FALSE) {
- Context->FillRandomFunction(Context,
- Header->DiskGuid,
- sizeof(Header->DiskGuid));
- } else {
- RtlCopyMemory(Header->DiskGuid,
- Context->DiskIdentifier,
- sizeof(Header->DiskGuid));
- }
- Header->PartitionEntriesLba = Header->CurrentLba - EntriesBlockCount;
- Header->PartitionEntryCount = EntryCount;
- Header->PartitionEntrySize = sizeof(GPT_PARTITION_ENTRY);
- Header->PartitionArrayCrc32 = RtlComputeCrc32(
- 0,
- GptEntries,
- EntryCount * sizeof(GPT_PARTITION_ENTRY));
- Header->HeaderCrc32 = RtlComputeCrc32(0, Header, Header->HeaderSize);
- //
- // Write out the header, then the partition entries array.
- //
- Status = PartpGptWriteBlocks(Context, Header->CurrentLba, 1, Header);
- if (!KSUCCESS(Status)) {
- goto GptWritePartitionLayoutEnd;
- }
- Status = PartpGptWriteBlocks(Context,
- Header->PartitionEntriesLba,
- EntriesBlockCount,
- GptEntries);
- if (!KSUCCESS(Status)) {
- goto GptWritePartitionLayoutEnd;
- }
- //
- // Create the protective MBR.
- //
- Pointer16 = (PUSHORT)(Table + PARTITION_SIGNATURE_OFFSET);
- *Pointer16 = PARTITION_SIGNATURE;
- MbrEntry = (PPARTITION_TABLE_ENTRY)(Table + PARTITION_TABLE_OFFSET);
- MbrEntry->StartingSector = 1;
- MbrEntry->SystemId = PARTITION_ID_EFI_GPT;
- MbrEntry->EndingHead = 0xFE;
- MbrEntry->EndingSector = 0xFF;
- MbrEntry->EndingCylinder = 0xFF;
- MbrEntry->StartingLba = 1;
- if (Context->BlockCount - 1 > MAX_ULONG) {
- MbrEntry->SectorCount = MAX_ULONG;
- } else {
- MbrEntry->SectorCount = Context->BlockCount - 1;
- }
- //
- // Fix up the GPT header for the beginning of the disk.
- //
- Header->HeaderCrc32 = 0;
- Header->BackupLba = Header->CurrentLba;
- Header->CurrentLba = 1;
- Header->PartitionEntriesLba = 2;
- Header->HeaderCrc32 = RtlComputeCrc32(0, Header, Header->HeaderSize);
- //
- // Finally, write out the MBR, GPT header, and entries all at once.
- //
- Status = PartpGptWriteBlocks(Context, 0, FirstUsableBlock, Table);
- if (!KSUCCESS(Status)) {
- goto GptWritePartitionLayoutEnd;
- }
- GptWritePartitionLayoutEnd:
- if (TableAllocation != NULL) {
- Context->FreeFunction(TableAllocation);
- }
- return Status;
- }
- PARTITION_TYPE
- PartpGptConvertTypeGuidToPartitionType (
- UCHAR TypeGuid[GPT_GUID_SIZE]
- )
- /*++
- Routine Description:
- This routine converts a partition type GUID into a partition type to the
- best of its abilities.
- Arguments:
- TypeGuid - Supplies a pointer to the partition type GUID.
- Return Value:
- Returns a partition type for this type GUID.
- --*/
- {
- ULONG EntryCount;
- ULONG EntryIndex;
- BOOL Match;
- EntryCount = sizeof(PartTypeGuidToPartitionTypeTable) /
- sizeof(PartTypeGuidToPartitionTypeTable[0]);
- for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex += 1) {
- Match = PartpGptAreGuidsEqual(
- PartTypeGuidToPartitionTypeTable[EntryIndex].TypeGuid,
- TypeGuid);
- if (Match != FALSE) {
- return PartTypeGuidToPartitionTypeTable[EntryIndex].PartitionType;
- }
- }
- return PartitionTypeUnknown;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- PartpGptReadEntries (
- PPARTITION_CONTEXT Context,
- PVOID Block,
- PGPT_PARTITION_ENTRY *Entries,
- PVOID *EntriesAllocation,
- PULONG EntryCount,
- PULONG ValidCount
- )
- /*++
- Routine Description:
- This routine determines if the GPT header is valid, and reads the
- partition entries if so.
- Arguments:
- Context - Supplies a pointer to the initialized context.
- Block - Supplies a pointer to the block containing the GPT header.
- Entries - Supplies a pointer where a pointer will be returned to the
- GPT partition entries on success.
- EntriesAllocation - Supplies a pointer where a pointer to the actual
- entries allocation will be returned. This is what should be passed to
- the free function.
- EntryCount - Supplies a pointer where the number of GPT entries in the
- array will be returned.
- ValidCount - Supplies a pointer where the number of non-empty partitions
- will be returned on success.
- Return Value:
- STATUS_SUCCESS if the partition information could be determined. There
- could still be zero partitions in this case.
- STATUS_NO_ELIGIBLE_DEVICES if the header is invalid.
- Other errors on read or allocation failures.
- --*/
- {
- ULONG AllocationSize;
- ULONG BlockCount;
- ULONG BlockIndex;
- ULONG BlockSize;
- ULONG ComputedCrc;
- PGPT_PARTITION_ENTRY Entry;
- ULONG EntryIndex;
- PGPT_HEADER Header;
- ULONG HeaderCrc;
- PGPT_PARTITION_ENTRY PartitionEntries;
- PVOID PartitionEntriesAllocation;
- ULONG PartitionEntryCount;
- KSTATUS Status;
- ULONG ValidPartitionCount;
- Status = STATUS_NO_ELIGIBLE_DEVICES;
- BlockSize = Context->BlockSize;
- Header = (PGPT_HEADER)Block;
- PartitionEntriesAllocation = NULL;
- PartitionEntryCount = 0;
- ValidPartitionCount = 0;
- if (Header->Signature != GPT_HEADER_SIGNATURE) {
- goto GptValidateHeaderEnd;
- }
- if (Header->Revision < GPT_HEADER_REVISION_1) {
- goto GptValidateHeaderEnd;
- }
- //
- // Validate that the reported sizes of the header and partition entry are
- // reasonable.
- //
- if ((Header->HeaderSize < sizeof(GPT_HEADER)) ||
- (Header->HeaderSize > Context->BlockSize)) {
- goto GptValidateHeaderEnd;
- }
- if ((Header->PartitionEntrySize < sizeof(GPT_PARTITION_ENTRY)) ||
- (Header->PartitionEntrySize > Context->BlockSize)) {
- goto GptValidateHeaderEnd;
- }
- //
- // Validate that the partition entries live outside the usable data.
- //
- if ((Header->PartitionEntriesLba >= Header->FirstUsableLba) &&
- (Header->PartitionEntriesLba <= Header->LastUsableLba)) {
- goto GptValidateHeaderEnd;
- }
- HeaderCrc = Header->HeaderCrc32;
- Header->HeaderCrc32 = 0;
- ComputedCrc = RtlComputeCrc32(0, Header, Header->HeaderSize);
- Header->HeaderCrc32 = HeaderCrc;
- if (ComputedCrc != HeaderCrc) {
- goto GptValidateHeaderEnd;
- }
- //
- // Allocate space for the partition entries.
- //
- PartitionEntryCount = Header->PartitionEntryCount;
- AllocationSize = PartitionEntryCount * Header->PartitionEntrySize;
- if (AllocationSize == 0) {
- Status = STATUS_SUCCESS;
- goto GptValidateHeaderEnd;
- }
- AllocationSize = ALIGN_RANGE_UP(AllocationSize, BlockSize);
- PartitionEntriesAllocation = PartpAllocateIo(Context,
- AllocationSize,
- (PVOID *)&PartitionEntries);
- if (PartitionEntriesAllocation == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GptValidateHeaderEnd;
- }
- BlockCount = AllocationSize / BlockSize;
- for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
- Status = Context->ReadFunction(
- Context,
- Header->PartitionEntriesLba + BlockIndex,
- (PUCHAR)PartitionEntries + (BlockIndex * BlockSize));
- if (!KSUCCESS(Status)) {
- goto GptValidateHeaderEnd;
- }
- }
- //
- // Validate the CRC for the partition entries.
- //
- ComputedCrc = RtlComputeCrc32(
- 0,
- PartitionEntries,
- Header->PartitionEntryCount * Header->PartitionEntrySize);
- if (ComputedCrc != Header->PartitionArrayCrc32) {
- Status = STATUS_NO_ELIGIBLE_DEVICES;
- goto GptValidateHeaderEnd;
- }
- //
- // Loop through and count the valid entries.
- //
- for (EntryIndex = 0; EntryIndex < PartitionEntryCount; EntryIndex += 1) {
- Entry = &(PartitionEntries[EntryIndex]);
- if ((Entry->FirstLba == 0) || (Entry->LastLba == 0)) {
- continue;
- }
- if (PartpGptIsGuidEmpty(Entry->TypeGuid) != FALSE) {
- continue;
- }
- ValidPartitionCount += 1;
- }
- Status = STATUS_SUCCESS;
- GptValidateHeaderEnd:
- if (!KSUCCESS(Status)) {
- if (PartitionEntriesAllocation != NULL) {
- Context->FreeFunction(PartitionEntriesAllocation);
- PartitionEntries = NULL;
- PartitionEntriesAllocation = NULL;
- }
- PartitionEntryCount = 0;
- ValidPartitionCount = 0;
- }
- *Entries = PartitionEntries;
- *EntriesAllocation = PartitionEntriesAllocation;
- *EntryCount = PartitionEntryCount;
- *ValidCount = ValidPartitionCount;
- return Status;
- }
- KSTATUS
- PartpGptWriteBlocks (
- PPARTITION_CONTEXT Context,
- ULONGLONG BlockAddress,
- ULONG BlockCount,
- PVOID Buffer
- )
- /*++
- Routine Description:
- This routine writes multiple blocks to the disk.
- Arguments:
- Context - Supplies a pointer to the partition context.
- BlockAddress - Supplies the block address to write to.
- BlockCount - Supplies the number of blocks to write.
- Buffer - Supplies a pointer to the buffer containing the data to write.
- Return Value:
- Status code.
- --*/
- {
- ULONG BlockIndex;
- KSTATUS Status;
- Status = STATUS_SUCCESS;
- for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
- Status = Context->WriteFunction(Context, BlockAddress, Buffer);
- if (!KSUCCESS(Status)) {
- goto GptWriteBlocksEnd;
- }
- Buffer += Context->BlockSize;
- BlockAddress += 1;
- }
- GptWriteBlocksEnd:
- return Status;
- }
- KSTATUS
- PartpGptConvertPartitionTypeToGuid (
- PARTITION_TYPE PartitionType,
- UCHAR TypeGuid[GPT_GUID_SIZE]
- )
- /*++
- Routine Description:
- This routine converts a partition type enum into its corresponding GPT GUID.
- Arguments:
- PartitionType - Supplies the partition type.
- TypeGuid - Supplies a pointer where the GUID will be returned.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if the partition type could not be converted.
- --*/
- {
- ULONG EntryCount;
- ULONG EntryIndex;
- EntryCount = sizeof(PartTypeGuidToPartitionTypeTable) /
- sizeof(PartTypeGuidToPartitionTypeTable[0]);
- for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex += 1) {
- if (PartTypeGuidToPartitionTypeTable[EntryIndex].PartitionType ==
- PartitionType) {
- RtlCopyMemory(TypeGuid,
- PartTypeGuidToPartitionTypeTable[EntryIndex].TypeGuid,
- GPT_GUID_SIZE);
- return STATUS_SUCCESS;
- }
- }
- return STATUS_INVALID_PARAMETER;
- }
- BOOL
- PartpGptIsGuidEmpty (
- UCHAR Guid[GPT_GUID_SIZE]
- )
- /*++
- Routine Description:
- This routine determines if the given GUID is all zero.
- Arguments:
- Guid - Supplies the guid to compare.
- Return Value:
- TRUE if the GUID is all zero.
- FALSE if the GUID has something in there.
- --*/
- {
- BOOL Match;
- //
- // The first entry is known to be the empty entry.
- //
- Match = PartpGptAreGuidsEqual(Guid,
- PartTypeGuidToPartitionTypeTable[0].TypeGuid);
- return Match;
- }
- BOOL
- PartpGptAreGuidsEqual (
- UCHAR FirstGuid[GPT_GUID_SIZE],
- UCHAR SecondGuid[GPT_GUID_SIZE]
- )
- /*++
- Routine Description:
- This routine compares two GPT GUIDs.
- Arguments:
- FirstGuid - Supplies the first GUID to compare.
- SecondGuid - Supplies the second GUID to compare.
- Return Value:
- TRUE if the GUIDs are equal.
- FALSE if the GUIDs are not equal.
- --*/
- {
- ULONG Index;
- for (Index = 0; Index < GPT_GUID_SIZE; Index += 1) {
- if (FirstGuid[Index] != SecondGuid[Index]) {
- return FALSE;
- }
- }
- return TRUE;
- }
|