windows-nt/Source/XPSP1/NT/base/ntsetup/textmode/kernel/spptwrt.c
2020-09-26 16:20:57 +08:00

4087 lines
120 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
spptwrt.c
Abstract:
Creates, Deletes and Commits the partitions
to the disk.
Author:
Vijay Jayaseelan (vijayj)
Revision History:
None
--*/
#include "spprecmp.h"
#pragma hdrstop
#include "sppart3.h"
#include <oemtypes.h>
//
// If we are testing commit then we don't commit on
// disk zero (i.e. primary disk) where we have our
// NT and recovery console installation
//
//#define TESTING_COMMIT 1
#if 0
//
// To test GPT partitions using existing loader
//
//#define STAMP_MBR_ON_GPT_DISK 1
#endif
//
// Variable to selectively trun on/off commits to
// the disk
//
BOOLEAN DoActualCommit = TRUE;
ULONG
SpPtnGetContainerPartitionCount(
IN ULONG DiskId
)
/*++
Routine Description:
Counts the number of container partitions in the region
list for the given disk
Arguments:
DiskId : Disk ID
Return Value:
Count of the container partitions for the disk
--*/
{
ULONG Count = 0;
if (SPPT_IS_MBR_DISK(DiskId)) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_CONTAINER_PARTITION(Region))
Count++;
Region = Region->Next;
}
}
return Count;
}
ULONG
SpPtnGetLogicalDriveCount(
IN ULONG DiskId
)
/*++
Routine Description:
Counts the number of logical drives in the regions list
for the given disk
Arguments:
DiskId : Disk ID
Return Value:
Count of the logical drives for the disk
--*/
{
ULONG Count = 0;
if (SPPT_IS_MBR_DISK(DiskId)) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_LOGICAL_DRIVE(Region))
Count++;
Region = Region->Next;
}
}
return Count;
}
ULONG
SpPtnGetPartitionCountDisk(
IN ULONG DiskId
)
/*++
Routine Description:
Counts the number of partitions for the given
disk.
Arguments:
DiskId : Disk ID
Return Value:
Count of number of partitions for the disk
--*/
{
ULONG PartCount = 0;
if (DiskId < HardDiskCount) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_PARTITIONED(Region))
PartCount++;
Region = Region->Next;
}
Region = SPPT_GET_EXTENDED_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_PARTITIONED(Region))
PartCount++;
Region = Region->Next;
}
}
return PartCount;
}
ULONG
SpPtnGetDirtyPartitionCountDisk(
IN ULONG DiskId
)
/*++
Routine Description:
Counts the number of dirty partitions for the given
disk.
NB: A partition is dirty if it needs to be commit
to the disk with some new information
Arguments:
DiskId : Disk ID
Return Value:
Count of the number of dirty partitions for the given
disk
--*/
{
ULONG PartCount = 0;
if (DiskId < HardDiskCount) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_DIRTY(Region))
PartCount++;
Region = Region->Next;
}
Region = SPPT_GET_EXTENDED_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_DIRTY(Region))
PartCount++;
Region = Region->Next;
}
}
return PartCount;
}
VOID
SpPtnGetPartitionTypeCounts(
IN ULONG DiskId,
IN BOOLEAN SkipDeleted,
IN PULONG PrimaryPartitions, OPTIONAL
IN PULONG ContainerPartitions, OPTIONAL
IN PULONG LogicalDrives, OPTIONAL
IN PULONG KnownPrimaryCount, OPTIONAL
IN PULONG KnownLogicalCount OPTIONAL
)
/*++
Routine Description:
Counts various partition types for the given disk.
Arguments:
DiskId : Disk ID
SkipDeleted : Whether to skip the partitions marked
deleted or not
PrimaryPartitions : Place holder for primary partition count
ContainerPartitions : Place holder for container partition count
LogicalDrives : Place holder for logical drives count
Return Value:
None
--*/
{
if (SPPT_IS_MBR_DISK(DiskId) &&
(ARGUMENT_PRESENT(PrimaryPartitions) ||
ARGUMENT_PRESENT(ContainerPartitions) ||
ARGUMENT_PRESENT(LogicalDrives))) {
ULONG Primary = 0, Container = 0, Logical = 0;
ULONG ValidPrimary = 0, ValidLogical = 0;
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (Region) {
if (!(SkipDeleted && SPPT_IS_REGION_MARKED_DELETE(Region))) {
if (SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
Container++;
ASSERT(SPPT_IS_REGION_LOGICAL_DRIVE(Region) == FALSE);
ASSERT(SPPT_IS_REGION_PRIMARY_PARTITION(Region) == FALSE);
} else if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
UCHAR SystemId = SPPT_GET_PARTITION_TYPE(Region);
Logical++;
if(SPPT_IS_VALID_PRIMARY_PARTITION_TYPE(SystemId)) {
ValidLogical++;
}
ASSERT(SPPT_IS_REGION_CONTAINER_PARTITION(Region) == FALSE);
ASSERT(SPPT_IS_REGION_PRIMARY_PARTITION(Region) == FALSE);
} else if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
UCHAR SystemId = SPPT_GET_PARTITION_TYPE(Region);
Primary++;
if(SPPT_IS_VALID_PRIMARY_PARTITION_TYPE(SystemId)) {
ValidPrimary++;
}
ASSERT(SPPT_IS_REGION_CONTAINER_PARTITION(Region) == FALSE);
ASSERT(SPPT_IS_REGION_LOGICAL_DRIVE(Region) == FALSE);
}
}
Region = Region->Next;
}
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnGetPartitionTypeCounts(%d):P:%d,C:%d,L:%d,VP:%d,VL:%d\n",
DiskId,
Primary,
Container,
Logical,
ValidPrimary,
ValidLogical));
ASSERT((Logical <= Container) && (Primary < PTABLE_DIMENSION));
if (ARGUMENT_PRESENT(PrimaryPartitions))
*PrimaryPartitions = Primary;
if (ARGUMENT_PRESENT(ContainerPartitions))
*ContainerPartitions = Container;
if (ARGUMENT_PRESENT(LogicalDrives))
*LogicalDrives = Logical;
if (ARGUMENT_PRESENT(KnownPrimaryCount))
*KnownPrimaryCount = ValidPrimary;
if (ARGUMENT_PRESENT(KnownLogicalCount))
*KnownLogicalCount = ValidLogical;
}
}
VOID
SpPtnFreeDiskRegions(
IN ULONG DiskId
)
/*++
Routine Description:
Free the disk region linked list. Its assumed that
this list has all the regions allocated in heap
Arguments:
DiskId : Disk ID
Return Value:
None
--*/
{
NTSTATUS Status;
PPARTITIONED_DISK Disk = SPPT_GET_PARTITIONED_DISK(DiskId);
PDISK_REGION Region = Disk->PrimaryDiskRegions;
PDISK_REGION Temp;
while (Region) {
Temp = Region;
Region = Region->Next;
SpMemFree(Temp);
}
Disk->PrimaryDiskRegions = NULL;
//
// Mark the disk blank since we don't have any regions
// for the disk currently
//
SPPT_SET_DISK_BLANK(DiskId, TRUE);
}
NTSTATUS
SpPtnZapSectors(
IN HANDLE DiskHandle,
IN ULONG BytesPerSector,
IN ULONGLONG StartSector,
IN ULONG SectorCount
)
/*++
Routine Description:
Zaps (zeros) the requested sector(s).
Arguments:
DiskHandle : Open Handle to disk with R/W permissions
StartSector : Starting sector to Zap
Sector Count: Number of sectors to Zap
(includes starting sector also)
Return Value:
Appropriate status code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (SectorCount) {
ULONG BufferSize = (BytesPerSector * 2);
PVOID UBuffer = SpMemAlloc(BufferSize);
ULONGLONG SectorIdx = StartSector;
if (UBuffer) {
PVOID Buffer = UBuffer;
RtlZeroMemory(UBuffer, BufferSize);
Buffer = ALIGN(Buffer, BytesPerSector);
Status = STATUS_SUCCESS;
while (NT_SUCCESS(Status) && SectorCount) {
Status = SpReadWriteDiskSectors(DiskHandle,
SectorIdx,
1,
BytesPerSector,
Buffer,
TRUE);
SectorIdx++;
SectorCount--;
}
SpMemFree(UBuffer);
} else {
Status = STATUS_NO_MEMORY;
}
}
return Status;
}
NTSTATUS
SpPtnZapRegionBootSector(
IN HANDLE DiskHandle,
IN PDISK_REGION Region
)
/*++
Routine Description:
Zaps (zeros) the starting sector for the given
region. Generally used to zap the boot sector after
creating a new partition
Currently skips the zapping for Container partitions
Arguments:
DiskHandle : Open Handle to disk with R/W permissions
Region : The region, whose boot sector (starting sector)
needs to be zapped
Return Value:
Appropriate status code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (Region) {
if (!SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
Status = SpPtnZapSectors(DiskHandle,
SPPT_DISK_SECTOR_SIZE(Region->DiskNumber),
Region->StartSector,
1);
} else {
Status = STATUS_SUCCESS;
}
}
return Status;
}
#if 0
NTSTATUS
SpPtnStampMBROnGptDisk(
IN HANDLE DiskHandle,
IN ULONG DiskId,
IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
)
/*++
Routine Description:
Stamps the first 3 partitions as primary partitions in the
MBR of the GPT disk (for testing)
Arguments:
DiskHandle : Open Handle to disk with R/W permissions
DiskId : The disk which we are operating on.
LayoutInfo : The partition information for the disk
Return Value:
Appropriate status code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if ((DiskId < HardDiskCount) && LayoutInfo && SPPT_IS_GPT_DISK(DiskId)) {
PPARTITION_INFORMATION_EX PartInfo;
ON_DISK_PTE PartEntries[4];
BOOLEAN WriteMBR = FALSE;
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskId);
ULONG BytesPerSector = Disk->Geometry.BytesPerSector;
ULONG Index;
RtlZeroMemory(PartEntries, sizeof(ON_DISK_PTE) * 4);
//
// Go through the partitions and pick up the partitions
// whose number are less than 4 (and not zero)
//
for (Index = 0; Index < LayoutInfo->PartitionCount; Index++) {
ULONG PartIndex = 0;
PartInfo = LayoutInfo->PartitionEntry + Index;
PartIndex = PartInfo->PartitionNumber;
if ((PartIndex > 0) && (PartIndex < 4)) {
ULONGLONG SectorStart = (PartInfo->StartingOffset.QuadPart /
BytesPerSector);
ULONGLONG SectorCount = (PartInfo->PartitionLength.QuadPart /
BytesPerSector);
ULONGLONG SectorEnd = SectorStart + SectorCount;
WriteMBR = TRUE; // need to write MBR
SpPtInitializeCHSFields(Disk,
SectorStart,
SectorEnd,
PartEntries + PartIndex);
U_ULONG(&(PartEntries[PartIndex].RelativeSectors)) = (ULONG)SectorStart;
U_ULONG(&(PartEntries[PartIndex].SectorCount)) = (ULONG)SectorCount;
PartEntries[PartIndex].SystemId = PARTITION_HUGE;
}
}
if (WriteMBR) {
PUCHAR UBuffer;
PUCHAR Buffer;
PON_DISK_MBR DummyMbr;
UBuffer = SpMemAlloc(BytesPerSector * 2);
if (UBuffer) {
RtlZeroMemory(UBuffer, BytesPerSector * 2);
//
// align the buffer on sector boundary
//
Buffer = ALIGN(UBuffer, BytesPerSector);
//
// Read sector 0 (for existing boot code)
//
Status = SpReadWriteDiskSectors(
DiskHandle,
(Disk->Int13Hooker == HookerEZDrive) ? 1 : 0,
1,
BytesPerSector,
Buffer,
FALSE
);
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnStampMBROnGptDisk():Read MBR on an GPT Disk for testing (%lx)\n",
Status));
if (NT_SUCCESS(Status)) {
ASSERT(512 == BytesPerSector);
DummyMbr = (PON_DISK_MBR)Buffer;
//
// copy the 3 entries in partition table (which we created eariler)
//
RtlCopyMemory(DummyMbr->PartitionTable + 1, PartEntries + 1,
sizeof(PartEntries) - sizeof(ON_DISK_PTE));
//
// Write the sector(s).
//
Status = SpReadWriteDiskSectors(
DiskHandle,
(Disk->Int13Hooker == HookerEZDrive) ? 1 : 0,
1,
BytesPerSector,
Buffer,
TRUE
);
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnStampMBROnGtpDisk():Wrote MBR on an GPT Disk for testing (%lx)\n",
Status));
}
SpMemFree(UBuffer);
} else {
Status = STATUS_NO_MEMORY;
}
} else {
Status = STATUS_SUCCESS;
}
}
return Status;
}
#endif // 0, comment out
NTSTATUS
SpPtnAssignPartitionNumbers(
IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
)
/*++
Routine Description:
Given a drive layout structure with number of partitions,
walks through each partitions assigning a partition number
if one is not already assigned.
Does not assign partition number to container partitions
Arguments:
LayoutEx - Contains all the partitions some of which needs
partition numbers
Return Value:
Appropriate error code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (LayoutEx && LayoutEx->PartitionCount) {
ULONG Index;
PBOOLEAN UsedArray;
ULONG PartCount = LayoutEx->PartitionCount;
ULONG Size = PartCount;
ULONG MaxPartAssigned;
PPARTITION_INFORMATION_EX PartInfo = LayoutEx->PartitionEntry;
//
// Find out the space needed for boolean array
//
for (Index = 0, MaxPartAssigned = 0; Index < PartCount; Index++) {
if (PartInfo[Index].PartitionNumber > MaxPartAssigned)
MaxPartAssigned = PartInfo[Index].PartitionNumber;
}
Size = max(MaxPartAssigned, PartCount);
Size++;
UsedArray = (PBOOLEAN)SpMemAlloc(sizeof(BOOLEAN) * Size);
if (UsedArray) {
BOOLEAN Assign = FALSE;
RtlZeroMemory(UsedArray, (sizeof(BOOLEAN) * Size));
UsedArray[0] = TRUE; // don't assign '0' to any partition
//
// Mark the already assigned partition numbers
//
for (Index = 0; Index < PartCount; Index++) {
if (PartInfo[Index].PartitionNumber != 0)
UsedArray[PartInfo[Index].PartitionNumber] = TRUE;
else
Assign = TRUE;
}
if (Assign) {
ULONG NextFreeEntry;
//
// Find the next available partition number for assignment
//
for (Index = 1, NextFreeEntry = 0; Index < Size; Index++) {
if (!UsedArray[Index]) {
NextFreeEntry = Index;
break;
}
}
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAssignPartitionNumber : NextFreeEntry = %d\n",
NextFreeEntry));
//
// Assign the partition numbers for the needed partitions
//
for (Index = 0; (Index < PartCount); Index++) {
if (SPPT_PARTITION_NEEDS_NUMBER(PartInfo + Index)) {
PartInfo[Index].PartitionNumber = NextFreeEntry;
UsedArray[NextFreeEntry] = TRUE;
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAssignPartitionNumber : Assigning = %d to %d\n",
NextFreeEntry, Index));
while ((NextFreeEntry < Size) && UsedArray[NextFreeEntry])
NextFreeEntry++;
}
}
}
Status = STATUS_SUCCESS;
SpMemFree(UsedArray);
} else {
Status = STATUS_NO_MEMORY;
}
}
return Status;
}
NTSTATUS
SpPtnInitializeDiskStyle(
IN ULONG DiskId,
IN PARTITION_STYLE Style,
IN PCREATE_DISK DiskInfo OPTIONAL
)
/*++
Routine Description:
Given the disk, changes the disk style (MBR/GPT) as
requested.
For RAW disks, uses the default partition type style
which can differ from platform to platform.
Arguments:
DiskId : Disk ID
Style : Partition Style
DiskInfo : Disk information which needs to be used,
while initializing the disk
Return Value:
Appropriate error code
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
#ifdef COMMIT_TESTING
if (!DiskId)
return STATUS_SUCCESS;
#endif
if (SPPT_IS_BLANK_DISK(DiskId) &&
((Style == PARTITION_STYLE_GPT) || (Style == PARTITION_STYLE_MBR))) {
WCHAR DiskPath[MAX_PATH];
HANDLE DiskHandle;
//
// form the name
//
swprintf(DiskPath, L"\\Device\\Harddisk%u", DiskId);
//
// Open partition 0 on this disk..
//
Status = SpOpenPartition0(DiskPath, &DiskHandle, TRUE);
if (NT_SUCCESS(Status)) {
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS InitStatus;
if (Style == PARTITION_STYLE_GPT) {
CREATE_DISK CreateInfo;
RtlZeroMemory(&CreateInfo, sizeof(CREATE_DISK));
if (DiskInfo) {
CreateInfo = *DiskInfo;
CreateInfo.PartitionStyle = Style;
} else {
CreateInfo.PartitionStyle = Style;
SpCreateNewGuid(&(CreateInfo.Gpt.DiskId));
CreateInfo.Gpt.MaxPartitionCount = 0; // will be 128 actually
}
Status = ZwDeviceIoControlFile( DiskHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_CREATE_DISK,
&CreateInfo,
sizeof(CREATE_DISK),
NULL,
0);
} else {
//
// Note : This is needed since CREATE_DISK doesn't work for
// MBR disks :(
//
ULONG LayoutSize;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
PHARD_DISK Disk;
Disk = SPPT_GET_HARDDISK(DiskId);
LayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
(3 * sizeof(PARTITION_INFORMATION_EX));
DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)SpMemAlloc(LayoutSize);
if (DriveLayout) {
RtlZeroMemory(DriveLayout, LayoutSize);
DriveLayout->PartitionStyle = PARTITION_STYLE_MBR;
DriveLayout->PartitionCount = 4;
if (DiskInfo) {
Disk->Signature = DriveLayout->Mbr.Signature =
DiskInfo->Mbr.Signature;
} else {
Disk->Signature = DriveLayout->Mbr.Signature =
SPPT_GET_NEW_DISK_SIGNATURE();
}
DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
DriveLayout->PartitionEntry[1].RewritePartition = TRUE;
DriveLayout->PartitionEntry[2].RewritePartition = TRUE;
DriveLayout->PartitionEntry[3].RewritePartition = TRUE;
Status = ZwDeviceIoControlFile( DiskHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
DriveLayout,
LayoutSize,
NULL,
0);
if (NT_SUCCESS(Status)) {
ULONG Signature = 0;
//
// Zero out sector 1 & 2 also since it might contain
// stale GPT information
//
if (!SPPT_IS_REMOVABLE_DISK(DiskId)) {
SpPtnZapSectors(DiskHandle,
SPPT_DISK_SECTOR_SIZE(DiskId),
1,
2);
}
Status = SpMasterBootCode(DiskId, DiskHandle, &Signature);
}
SpMemFree(DriveLayout);
} else {
Status = STATUS_NO_MEMORY;
}
}
ZwClose(DiskHandle);
}
}
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnInitializeDiskStyle (%d, %d) failed with (%lx)\n",
DiskId, Style, Status));
}
SpAppendDiskTag(SPPT_GET_HARDDISK(DiskId));
return Status;
}
BOOLEAN
SpPtnRegionToPartitionInfoEx(
IN PDISK_REGION Region,
OUT PPARTITION_INFORMATION_EX PartInfo
)
/*++
Routine Description:
Fills in the PartInfo structure from the given region.
NB. If the region is not dirty uses the cached partition
information to fill the structure.
Arguments:
Region - Which has the details to be filled
into PartInfo
PartInfo - The structure which needs to filled
Return Value:
TRUE if successful, otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
if (Region && PartInfo &&
(SPPT_IS_REGION_CONTAINER_PARTITION(Region) || SPPT_IS_REGION_PARTITIONED(Region))) {
if (SPPT_IS_REGION_DIRTY(Region)) {
PHARD_DISK Disk = SPPT_GET_HARDDISK(Region->DiskNumber);
PartInfo->StartingOffset.QuadPart = Region->StartSector *
Disk->Geometry.BytesPerSector;
PartInfo->PartitionLength.QuadPart = Region->SectorCount *
Disk->Geometry.BytesPerSector;
PartInfo->PartitionNumber = Region->PartitionNumber;
PartInfo->RewritePartition = TRUE;
if (SPPT_IS_GPT_DISK(Region->DiskNumber)) {
PPARTITION_INFORMATION_GPT GptInfo;
PartInfo->PartitionStyle = PARTITION_STYLE_GPT;
GptInfo = &(PartInfo->Gpt);
if (Region->PartInfoDirty) {
//
// User specified partition attributes
//
*GptInfo = Region->PartInfo.Gpt;
} else {
GptInfo->Attributes = 0;
if (SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
GptInfo->PartitionType = PARTITION_SYSTEM_GUID;
} else {
GptInfo->PartitionType = PARTITION_BASIC_DATA_GUID;
}
SpCreateNewGuid(&(GptInfo->PartitionId));
}
SpPtnGetPartitionNameFromGUID(&(GptInfo->PartitionType),
GptInfo->Name);
} else {
PPARTITION_INFORMATION_MBR MbrInfo;
PartInfo->PartitionStyle = PARTITION_STYLE_MBR;
MbrInfo = &(PartInfo->Mbr);
MbrInfo->PartitionType = SPPT_GET_PARTITION_TYPE(Region);
if (!MbrInfo->PartitionType)
MbrInfo->PartitionType = PARTITION_IFS;
MbrInfo->BootIndicator = SPPT_IS_REGION_ACTIVE_PARTITION(Region);
//
// System partition must be active partition for MBR disks
// on Non-ARC machines
//
if (SPPT_IS_REGION_SYSTEMPARTITION(Region) && !SpIsArc() ) {
ASSERT(MbrInfo->BootIndicator);
}
MbrInfo->RecognizedPartition =
IsRecognizedPartition(MbrInfo->PartitionType);
MbrInfo->HiddenSectors = 0;
}
} else {
*PartInfo = Region->PartInfo;
}
Result = TRUE;
}
return Result;
}
BOOLEAN
SpPtnInitDiskInfo(
IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
OUT PCREATE_DISK CreateInfo
)
/*++
Routine Description:
Fills the information needed for creating a disk,
form the given drive layout structure
NB. If the LayoutInfo is marked as RAW disk style
then used the default partition style for the disk.
This default style can vary from platform to platform
Arguments:
LayoutInfo - The drive layout information to use
CreateInfo - The disk information to be filled in
Return Value:
TRUE if successful otherwise FALSE.1
--*/
{
BOOLEAN Result = FALSE;
if (LayoutInfo && CreateInfo) {
RtlZeroMemory(CreateInfo, sizeof(CREATE_DISK));
CreateInfo->PartitionStyle = LayoutInfo->PartitionStyle;
switch (CreateInfo->PartitionStyle) {
case PARTITION_STYLE_MBR:
CreateInfo->Mbr.Signature = LayoutInfo->Mbr.Signature;
Result = TRUE;
break;
case PARTITION_STYLE_GPT:
CreateInfo->Gpt.DiskId = LayoutInfo->Gpt.DiskId;
CreateInfo->Gpt.MaxPartitionCount =
LayoutInfo->Gpt.MaxPartitionCount;
Result = TRUE;
break;
case PARTITION_STYLE_RAW:
CreateInfo->PartitionStyle = SPPT_DEFAULT_PARTITION_STYLE;
if (CreateInfo->PartitionStyle == PARTITION_STYLE_GPT) {
SpCreateNewGuid(&(CreateInfo->Gpt.DiskId));
} else {
CreateInfo->Mbr.Signature = SPPT_GET_NEW_DISK_SIGNATURE();
}
Result = TRUE;
break;
default:
break;
}
}
return Result;
}
NTSTATUS
SpPtnCommitChanges(
IN ULONG DiskNumber,
OUT PBOOLEAN AnyChanges
)
/*++
Routine Description:
Given the disk, commits the in memory disk region structures
to the disk as partitions.
The commit happens only if atlease a single disk region for the
given disk is dirty.
Arguments:
DiskNumber : Disk to commit for.
AnyChanges : Place holder, indicating if any thing was committed
or not.
Return Value:
Appropriate error code.
--*/
{
NTSTATUS Status;
ULONG LayoutSize;
HANDLE Handle = NULL;
ULONG Index;
ULONG PartitionCount;
ULONG DirtyCount;
WCHAR DevicePath[MAX_PATH];
BOOLEAN ProcessExtended;
PHARD_DISK Disk;
PDISK_REGION Region;
IO_STATUS_BLOCK IoStatusBlock;
PPARTITION_INFORMATION_EX PartInfo;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx;
//
// For the time being lets not commit the primary disk
// where we have our OS/RC installed
//
#ifdef TESTING_COMMIT
if (!DiskNumber)
return STATUS_SUCCESS;
#endif
if (DiskNumber >= HardDiskCount)
return STATUS_INVALID_PARAMETER;
*AnyChanges = FALSE;
SpPtDumpDiskRegionInformation(DiskNumber, TRUE);
//
// Check to see if we need to commit
//
DirtyCount = SpPtnGetDirtyPartitionCountDisk(DiskNumber);
if (DoActualCommit && !DirtyCount)
return STATUS_SUCCESS;
*AnyChanges = TRUE;
if (!SpPtnGetContainerPartitionCount(DiskNumber)) {
//
// Recreate the DRIVE_LAYOUT_INFORMATION_EX structure
//
PartitionCount = SpPtnGetPartitionCountDisk(DiskNumber);
LayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
if (PartitionCount == 0) {
CREATE_DISK DiskInfo;
SpPtnInitDiskInfo(&(SPPT_GET_HARDDISK(DiskNumber)->DriveLayout),
&DiskInfo);
SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
Status = SpPtnInitializeDiskStyle(DiskNumber,
DiskInfo.PartitionStyle, &DiskInfo);
SpPtnFreeDiskRegions(DiskNumber);
//
// Update the boot entries to point to null regions
// (if any)
//
SpUpdateRegionForBootEntries();
return Status;
}
if (PartitionCount > 1) {
LayoutSize += ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX));
}
if (PartitionCount < 4) {
LayoutSize += ((4 - PartitionCount) * sizeof(PARTITION_INFORMATION_EX));
}
DriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)SpMemAlloc(LayoutSize);
if (!DriveLayoutEx)
return STATUS_NO_MEMORY;
RtlZeroMemory(DriveLayoutEx, LayoutSize);
RtlCopyMemory(DriveLayoutEx, &(HardDisks[DiskNumber].DriveLayout),
FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry));
DriveLayoutEx->PartitionCount = PartitionCount;
PartInfo = DriveLayoutEx->PartitionEntry;
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
ProcessExtended = TRUE;
//
// Initialize stray partitions
//
if (SPPT_IS_MBR_DISK(DiskNumber) && (PartitionCount < 4)) {
ULONG Index = PartitionCount;
DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
DriveLayoutEx->PartitionCount = 4;
while (Index < 4) {
DriveLayoutEx->PartitionEntry[Index].PartitionStyle = PARTITION_STYLE_MBR;
DriveLayoutEx->PartitionEntry[Index].RewritePartition = TRUE;
Index++;
}
}
//
// Make PARTITION_INFORMATION_EXs from DISK_REGIONs for all non deleted
// partitions
//
for (Index=0; (Region && (Index < PartitionCount));) {
if (SPPT_IS_REGION_PARTITIONED(Region) &&
(!SPPT_IS_REGION_MARKED_DELETE(Region))) {
Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
ASSERT(NT_SUCCESS(Status));
Index++;
}
Region = Region->Next;
}
} else {
//
// The disk has container partitions and possibly logical
// drives
//
ULONG PrimaryCount = 0, ContainerCount = 0, LogicalCount = 0;
ULONG TotalPartitions;
//SpPtDumpDiskRegionInformation(DiskNumber, TRUE);
SpPtnGetPartitionTypeCounts(DiskNumber,
TRUE,
&PrimaryCount,
&ContainerCount,
&LogicalCount,
NULL,
NULL);
TotalPartitions = PrimaryCount + ContainerCount + LogicalCount;
if (TotalPartitions == 0) {
CREATE_DISK DiskInfo;
SpPtnInitDiskInfo(&(SPPT_GET_HARDDISK(DiskNumber)->DriveLayout),
&DiskInfo);
SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
Status = SpPtnInitializeDiskStyle(DiskNumber,
DiskInfo.PartitionStyle, &DiskInfo);
SpPtnFreeDiskRegions(DiskNumber);
//
// Update the boot entries to point to null regions
// (if any)
//
SpUpdateRegionForBootEntries();
return Status;
} else {
BOOLEAN FirstContainer = FALSE;
//
// allocate adequate space for the drive layout information
//
PartitionCount = (4 * (ContainerCount + 1));
LayoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
(PartitionCount * sizeof(PARTITION_INFORMATION_EX));
DriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)SpMemAlloc(LayoutSize);
if (!DriveLayoutEx)
return STATUS_NO_MEMORY;
//
// initialize the drive layout information
//
RtlZeroMemory(DriveLayoutEx, LayoutSize);
RtlCopyMemory(DriveLayoutEx, &(HardDisks[DiskNumber].DriveLayout),
FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry));
DriveLayoutEx->PartitionCount = PartitionCount;
PartInfo = DriveLayoutEx->PartitionEntry;
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
//SpPtDumpDiskRegionInformation(DiskNumber, TRUE);
//
// first pickup the primary partitions and the first
// container partition and put them in the drive layout
// information
//
for (Index=0; (Region && (Index < 4)); ) {
if (!SPPT_IS_REGION_MARKED_DELETE(Region)){
if (!FirstContainer &&
SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
FirstContainer = TRUE;
Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
ASSERT(NT_SUCCESS(Status));
Index++;
} else if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
ASSERT(NT_SUCCESS(Status));
Index++;
}
}
Region = Region->Next;
}
//SpPtDumpDriveLayoutInformation(NULL, DriveLayoutEx);
//
// further container and logical drives need to start at
// multiple of 4 index, in drive layout
//
if (Index)
Index = 4;
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
//
// pickup the remaining valid container and logical drives
// and put them in the drive layout information except
// for the first container partition, which we have
// already processed
//
while (Region && (Index < PartitionCount)) {
if ((!SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(Region)) &&
(!SPPT_IS_REGION_MARKED_DELETE(Region)) &&
(!SPPT_IS_REGION_PRIMARY_PARTITION(Region)) &&
(SPPT_IS_REGION_PARTITIONED(Region) ||
SPPT_IS_REGION_CONTAINER_PARTITION(Region))) {
Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
ASSERT(NT_SUCCESS(Status));
if (SPPT_IS_REGION_CONTAINER_PARTITION(Region) &&
(Region->Next) &&
SPPT_IS_REGION_LOGICAL_DRIVE(Region->Next)) {
//
// think about this ;)
//
if (Index % 4)
Index += 3;
else
Index += 4;
} else {
Index++;
}
}
Region = Region->Next;
}
}
}
//
// Assign proper partition numbers
//
// TBD : Needed ?
// Status = SpPtnAssignPartitionNumbers(DriveLayoutEx);
//
Status = STATUS_SUCCESS;
if (NT_SUCCESS(Status)) {
//
// Need to rewrite all the partitions
//
for (Index = 0; Index < DriveLayoutEx->PartitionCount; Index++)
PartInfo[Index].RewritePartition = TRUE;
//
// Commit the Partition changes
//
//
// Create a device path (NT style!) that will describe this disk. This
// will be of the form: \Device\Harddisk0
//
swprintf(DevicePath, L"\\Device\\Harddisk%u", DiskNumber);
//SpPtDumpDriveLayoutInformation(DevicePath, DriveLayoutEx);
//
// Open partition 0 on this disk..
//
Status = SpOpenPartition0(DevicePath, &Handle, TRUE);
if(NT_SUCCESS(Status)){
if (DoActualCommit) {
// write the drive layout information
Status = ZwDeviceIoControlFile( Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
DriveLayoutEx,
LayoutSize,
NULL,
0);
if(NT_SUCCESS(Status)) {
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnCommitChanges : Commited partitions "
"successfully on %ws (%lx)\n",
DevicePath));
if (NT_SUCCESS(Status)) {
ULONG Signature = 0;
ULONG Count = 0;
if (SPPT_IS_MBR_DISK(DiskNumber)) {
Status = SpMasterBootCode(DiskNumber,
Handle,
&Signature);
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnCommitChanges : Unable to write "
"master boot code (%lx)\n",
Status));
}
}
while (Region && NT_SUCCESS(Status)) {
if (Region->Filesystem == FilesystemNewlyCreated) {
Status = SpPtnZapRegionBootSector(Handle, Region);
Count++;
}
Region = Region->Next;
}
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCommitChanges : Error in Zapping\n"));
//SpPtDumpDiskRegion(Region);
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnCommitChanges : Zapped %d sectors :)\n",
Count));
#ifdef STAMP_MBR_ON_GPT_DISK
Status = ZwDeviceIoControlFile( Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
NULL,
0,
DriveLayoutEx,
LayoutSize);
if (NT_SUCCESS(Status)) {
Status = SpPtnStampMBROnGptDisk(Handle,
DiskNumber,
DriveLayoutEx);
}
#endif
}
}
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCommitChanges : unable to do "
"IOCTL_DISK_SET_DRIVE_LAYOUT_EX on device %ws (%lx)\n",
DevicePath,
Status));
}
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCommitChanges : Skipping acutal commit to disk "
"for %ws\n",
DevicePath));
}
ZwClose(Handle);
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCommitChanges : unable to open "
"partition0 on device %ws (%lx)\n",
DevicePath,
Status ));
}
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCommitChanges : unable to assign "
"partition numbers for %ws (%lx)\n",
DevicePath,
Status ));
}
SpMemFree(DriveLayoutEx);
return Status;
}
NTSTATUS
SpPtnRemoveLogicalDrive(
IN PDISK_REGION LogicalDrive
)
/*++
Routine Description:
Manipulates the in memory region data structure
so as to mark the logical drive as deleted.
NB. When a logical drive gets deleted, the container
partition needs to be deleted based on some
conditions.
Arguments:
LogicalDrive : The region representing the logical
drive which needs to be deleted.
Return Value:
Approprate error code
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (SPPT_IS_REGION_LOGICAL_DRIVE(LogicalDrive) &&
(LogicalDrive->Container)){
PDISK_REGION ContainerRegion = LogicalDrive->Container;
BOOLEAN LastLogicalDrive =
(SpPtnGetLogicalDriveCount(LogicalDrive->DiskNumber) == 1);
SPPT_SET_REGION_DELETED(LogicalDrive, TRUE);
SPPT_SET_REGION_DIRTY(LogicalDrive, TRUE);
SPPT_SET_REGION_PARTITIONED(LogicalDrive, FALSE);
if (LastLogicalDrive) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnRemoveLogicalDrive(%p) is the last"
" logical drive\n", LogicalDrive));
}
if (ContainerRegion->Container) {
PDISK_REGION Region = NULL;
SPPT_SET_REGION_DELETED(ContainerRegion, TRUE);
SPPT_SET_REGION_DIRTY(ContainerRegion, TRUE);
SPPT_SET_REGION_PARTITIONED(ContainerRegion, FALSE);
//
// if this was the last logical drive then delete the
// first container region also
//
if (LastLogicalDrive) {
ASSERT(SPPT_IS_REGION_CONTAINER_PARTITION(
ContainerRegion->Container));
SPPT_SET_REGION_DELETED(ContainerRegion->Container, TRUE);
SPPT_SET_REGION_DIRTY(ContainerRegion->Container, TRUE);
SPPT_SET_REGION_PARTITIONED(ContainerRegion->Container, FALSE);
}
} else {
if (LastLogicalDrive) {
//
// No trailing region, so delete the first container region
//
SPPT_SET_REGION_DELETED(ContainerRegion, TRUE);
SPPT_SET_REGION_DIRTY(ContainerRegion, TRUE);
SPPT_SET_REGION_PARTITIONED(ContainerRegion, FALSE);
}
}
Status = STATUS_SUCCESS;
}
return Status;
}
BOOLEAN
SpPtnDelete(
IN ULONG DiskNumber,
IN ULONGLONG StartSector
)
/*++
Routine Description:
Removes the requested partition for the given disk.
Also updates the region structure when returns.
Arguments:
DiskNumber : Disk where the partition needs to be
deleted.
StartSector : Start sector of the partition/region
which needs to be deleted.
Return Value:
TRUE if successful otherwise FALSE.
--*/
{
BOOLEAN Result = FALSE;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PDISK_REGION Region;
PPARTITIONED_DISK PartDisk;
NTSTATUS InitStatus;
#ifdef TESTING_COMMIT
if (DiskNumber == 0)
return TRUE;
#endif
PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
if (Region) {
if (SPPT_IS_REGION_DYNAMIC_VOLUME(Region) || SPPT_IS_REGION_LDM_METADATA(Region)) {
//
// delete all the regions on this disk
//
PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
if (SPPT_IS_MBR_DISK(DiskNumber)) {
//
// Skip OEM partitions on MBR disk since they will always be
// hard partitions
//
// NOTE : Assumes that all the OEM partitions are primary
// partitions (which also indicates they are hard partitions)
//
while (CurrRegion) {
if (!IsOEMPartition(SPPT_GET_PARTITION_TYPE(CurrRegion))) {
SPPT_SET_REGION_PARTITIONED(CurrRegion, FALSE);
SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
}
CurrRegion = CurrRegion->Next;
}
} else {
while (CurrRegion) {
//
// Skip ESP & MSR partitions since they will always be
// hard partitions
//
if (!SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion) &&
!SPPT_IS_REGION_MSFT_RESERVED(CurrRegion)) {
SPPT_SET_REGION_PARTITIONED(CurrRegion, FALSE);
SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
}
CurrRegion = CurrRegion->Next;
}
}
Status = STATUS_SUCCESS;
} else if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
Status = SpPtnRemoveLogicalDrive(Region);
} else {
SPPT_SET_REGION_PARTITIONED(Region, FALSE);
SPPT_SET_REGION_DELETED(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status)) {
Status = SpPtnCommitChanges(DiskNumber, &Result);
if (!(Result && NT_SUCCESS(Status))) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnDelete(%u, %I64u) failed to commit changes (%lx)\n",
DiskNumber, StartSector, Status));
}
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnDelete(%u, %I64u) failed to delete logical drive (%lx)\n",
DiskNumber, StartSector, Status));
}
}
Result = Result && NT_SUCCESS(Status);
//
// Reinitialize regions irrespective of commit's status
//
InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
if (!NT_SUCCESS(InitStatus)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnDelete(%u, %I64u) failed to reinit regions\n",
DiskNumber,
StartSector));
Result = FALSE;
}
return Result;
}
ValidationValue
SpPtnGetSizeCB(
IN ULONG Key
)
/*++
Routine Description:
Key stroke filter for getting the partition size
from the user
Arguments:
Key - The key stroke
Return Value:
One of the enumerated types of ValidationValue, indicating
whether to accept / reject / terminate / ignore the key
stroke.
--*/
{
if(Key == ASCI_ESC) {
//
// User wants to bail.
//
return(ValidateTerminate);
}
if(Key & KEY_NON_CHARACTER) {
return(ValidateIgnore);
}
//
// Allow only digits.
//
return(((Key >= L'0') && (Key <= L'9')) ? ValidateAccept : ValidateReject);
}
BOOLEAN
SpPtnGetSizeFromUser(
IN PHARD_DISK Disk,
IN ULONGLONG MinMB,
IN ULONGLONG MaxMB,
OUT PULONGLONG SizeMB
)
/*++
Routine Description:
Gets the size from user, after showing him the minimum
and maximum values
Arguments:
Disk - Disk for which the partition size is being
requested
MinMB - Minimum partition size
MaxMB - Maximim patitions size
SizeMB - Place holder for user entered size
Return Value:
TRUE if the input was valid or FALSE if the user
cancelled the input dialog using ESC.
--*/
{
BOOLEAN Result;
WCHAR Buffer[200];
WCHAR SizeBuffer[32] = {0};
*SizeMB = 0;
//
// Put up a screen displaying min/max size info.
//
SpStartScreen(
SP_SCRN_CONFIRM_CREATE_PARTITION,
3,
CLIENT_TOP + 1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
Disk->Description,
(ULONG)MinMB,
(ULONG)MaxMB
);
//
// Display the staus text.
//
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CREATE,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
//
// Get and display the size prompt.
//
SpFormatMessage(Buffer, sizeof(Buffer), SP_TEXT_SIZE_PROMPT);
SpvidDisplayString(Buffer, DEFAULT_ATTRIBUTE, 3, NextMessageTopLine);
Result = TRUE;
//
// Get the size from the user.
//
do {
swprintf(SizeBuffer,L"%u", (ULONG)MaxMB);
if(!SpGetInput(SpPtnGetSizeCB,
SplangGetColumnCount(Buffer) + 5,
NextMessageTopLine,
8, // at the max 99999999
SizeBuffer,
TRUE)) {
//
// User pressed escape and bailed.
//
Result = FALSE;
break;
}
*SizeMB = SpStringToLong(SizeBuffer, NULL, 10);
}
while(((*SizeMB) < MinMB) || ((*SizeMB) > MaxMB));
return Result;
}
VOID
SpPtnAlignPartitionStartAndEnd(
IN PHARD_DISK Disk,
IN ULONGLONG SizeMB,
IN ULONGLONG StartSector,
IN PDISK_REGION Region,
IN BOOLEAN ForExtended,
OUT PULONGLONG AlignedStartSector,
OUT PULONGLONG AlignedEndSector
)
/*++
Routine Description:
Aligns the partition start and end sector
Arguments:
Disk - Partition's disk for which alignment needs to be
done.
SizeMB - The partition's size
StartSector - The start sector of the partition
Region - The region representing the partition
ForExtended - Whether this partition needs to be aligned
for creating a container partition.
AlignedStartSector - Place holder for the aligned start sector
AlignedEndSector - Place holder fot the aligned end sector
Return Value:
None
--*/
{
ULONGLONG SectorCount;
ULONGLONG LeftOverSectors;
//
// Determine the number of sectors in the size passed in.
//
SectorCount = SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector);
//
// If this is the first free space inside the extended partition
// we need to decrement the StartSector so that while creating
// first logical inside the extended we don't create the
// logical at one cylinder offset
//
if (SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(Region) && StartSector) {
StartSector--;
}
//
// Align the start sector.
//
(*AlignedStartSector) = SpPtAlignStart(Disk, StartSector, ForExtended);
//
// Determine the end sector based on the size passed in.
//
(*AlignedEndSector) = (*AlignedStartSector) + SectorCount;
//
// Align the ending sector to a cylinder boundary. If it is not already
// aligned and is more than half way into the final cylinder, align it up,
// otherwise align it down.
//
LeftOverSectors = (*AlignedEndSector) % Disk->SectorsPerCylinder;
if (LeftOverSectors) {
(*AlignedEndSector) -= LeftOverSectors;
if (LeftOverSectors > (Disk->SectorsPerCylinder / 2)) {
(*AlignedEndSector) += Disk->SectorsPerCylinder;
}
}
//
// If the ending sector is past the end of the free space, shrink it
// so it fits.
//
while((*AlignedEndSector) > StartSector + Region->SectorCount) {
(*AlignedEndSector) -= Disk->SectorsPerCylinder;
}
//
// Find out if last sector is in the last cylinder. If it is then align it down.
// This is necessary so that we reserve a cylinder at the end of the disk, so that users
// can convert the disk to dynamic after the system is installed.
//
// (guhans) Don't align down if this is ASR. ASR already takes this into account.
//
if( !DockableMachine && !SpDrEnabled() &&
((*AlignedEndSector) > ((Disk->CylinderCount - 1) * Disk->SectorsPerCylinder))) {
(*AlignedEndSector) -= Disk->SectorsPerCylinder;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: End of partition was aligned down 1 cylinder \n"));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: AlignedStartSector = %I64x \n", AlignedStartSector));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: AlignedEndSector = %I64x \n", AlignedEndSector));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SectorsPerCylinder = %lx \n", Disk->SectorsPerCylinder));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: CylinderCount = %lx \n", Disk->CylinderCount));
}
ASSERT((*AlignedEndSector) > 0);
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnAlignPartitionStartAndEnd:S/C:%d,Size:%I64d,"
"StartSector:%I64d,RSS:%I64d,FE:%d,AS:%I64d,AE:%I64d\n"
"LeftOverSectors:%I64d\n",
Disk->SectorsPerCylinder,
SizeMB,
StartSector,
Region->StartSector,
ForExtended,
*AlignedStartSector,
*AlignedEndSector,
LeftOverSectors));
}
BOOLEAN
SpPtnCreateLogicalDrive(
IN ULONG DiskNumber,
IN ULONGLONG StartSector,
IN ULONGLONG SizeInSectors, // Used ONLY in the ASR case
IN BOOLEAN ForNT,
IN BOOLEAN AlignToCylinder,
IN ULONGLONG DesiredMB OPTIONAL,
IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
OUT PDISK_REGION *ActualDiskRegion OPTIONAL
)
/*++
Routine Description:
Creates logical drive.
To create a logical drive we need to create the
logical drive's container partition also first.
Algorithm:
if (first logical drive) {
1. create an extended partition encompassing the
whole free space in region
2. create a logical drive at one track offset
from the extened partition of the required size
} else {
1. create an extended partition encompassing the
given space
2. create a logical drive of the maximim size
inside the created extended partition
}
Arguments:
DiskNumber - Disk on which logical drive nedds to be
created.
StartSector - The starting sector for the region, which
will contain the container & logical drive
ForNT - Indicating whether to use the given
Desired Size or not
AlignToCylinder - Indicating whether the partition should
be aligned on a cylinder boundary (Usually set
to TRUE, except in a few specific ASR cases).
PartInfo - Partition Information which needs to be
used while creating the partition (like
Partition Type on MBR disks and GUID
for Partition Id on GPT disks)
ActualDiskRegion - Place holder for returning, the
region which indicates the new
partition in memory
Return Value:
TRUE is successful otherwise FALSE.
--*/
{
BOOLEAN Result = FALSE;
NTSTATUS Status;
NTSTATUS InitStatus;
UCHAR PartitionType = 0;
ULONG Primary = 0, Container = 0, Logical = 0;
BOOLEAN FirstLogical = FALSE;
BOOLEAN ReservedRegion = FALSE;
BOOLEAN CreateContainer = TRUE;
BOOLEAN Beyond1024;
BOOLEAN FreeRegions = FALSE;
ULONGLONG MinMB = 0, MaxMB = 0, SizeMB = 0;
ULONGLONG LogicalSize = 0;
ULONGLONG CylinderMB = 0;
PDISK_REGION Region;
ULONGLONG SectorCount, LeftOverSectors;
ULONGLONG AlignedStartSector, AlignedEndSector;
ULONGLONG LogicalStartSector, LogicalEndSector;
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
PDISK_REGION NewContainer = NULL, NewLogical = NULL;
//
// get hold of the region
//
Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
if (!Region)
return Result;
//
// should be free
//
ASSERT(SPPT_IS_REGION_PARTITIONED(Region) == FALSE);
//
// get the various partition type count on the disk
//
SpPtnGetPartitionTypeCounts(DiskNumber,
TRUE,
&Primary,
&Container,
&Logical,
NULL,
NULL);
//
// first logical indicates, what we will be creating the first
// container partition which will consume the whole free space
// available
//
FirstLogical = !(Logical || Container);
//
// Some times there might be just an extended partition and we
// might be creating the partition in the starting free space inside
// this extended partition. For this case we want to make sure that
// we don't create another container partition
//
if (!FirstLogical && SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(Region)) {
CreateContainer = FALSE;
}
//
// Create an extened partition
//
SpPtQueryMinMaxCreationSizeMB(DiskNumber,
Region->StartSector,
CreateContainer,
!CreateContainer,
&MinMB,
&MaxMB,
&ReservedRegion
);
if (ReservedRegion) {
ULONG ValidKeys[2] = {ASCI_CR , 0};
SpStartScreen(
SP_SCRN_REGION_RESERVED,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
SpWaitValidKey(ValidKeys, NULL, NULL);
return FALSE;
}
if (ForNT) {
//
// If a size was requested then try to use that, otherwise use
// the maximum.
//
if (DesiredMB) {
if (DesiredMB <= MaxMB) {
SizeMB = DesiredMB;
} else {
return FALSE; // don't have the space user requested
}
} else {
SizeMB = MaxMB;
}
} else {
if (SpPtnGetSizeFromUser(Disk, MinMB, MaxMB, &SizeMB)) {
DesiredMB = SizeMB;
} else {
return FALSE; // user didn't want to proceed
}
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_PLEASE_WAIT,
0);
}
//
// get the aligned start and end sector for exteneded/logical partition
//
if (AlignToCylinder) {
SpPtnAlignPartitionStartAndEnd(Disk,
FirstLogical ? MaxMB : SizeMB,
StartSector,
Region,
CreateContainer,
&AlignedStartSector,
&AlignedEndSector);
}
else {
AlignedStartSector = StartSector;
if (SpDrEnabled()) {
AlignedEndSector = StartSector + SizeInSectors;
}
else {
AlignedEndSector = StartSector +
(SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector));
}
}
if (CreateContainer) {
//
// Logical drive start is always at 1 track offset from extended start
//
LogicalStartSector = AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber);
if (FirstLogical) {
ULONGLONG SectorCount = (SizeMB * 1024 * 1024) / SPPT_DISK_SECTOR_SIZE(DiskNumber);
ULONGLONG Remainder = 0;
if (SpDrEnabled()) {
SectorCount = SizeInSectors;
}
LogicalEndSector = LogicalStartSector + SectorCount;
if (AlignToCylinder) {
Remainder = LogicalEndSector % SPPT_DISK_CYLINDER_SIZE(DiskNumber);
LogicalEndSector -= Remainder;
if (Remainder > (SPPT_DISK_CYLINDER_SIZE(DiskNumber) / 2))
LogicalEndSector += SPPT_DISK_CYLINDER_SIZE(DiskNumber);
}
if (LogicalEndSector > AlignedEndSector)
LogicalEndSector = AlignedEndSector;
} else {
LogicalEndSector = AlignedEndSector;
}
} else {
//
// The first free region (inside first extended) is at the offset
// of 1 sector from the previous exteneded region. Since we are not
// using the aligned start sector some times this first logical
// will be greater than the requested size i.e.
// end is aligned but start may not be aligned
//
LogicalStartSector = StartSector - 1 + SPPT_DISK_TRACK_SIZE(DiskNumber);
LogicalEndSector = AlignedEndSector;
}
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnCreateLogicalDrive():"
"CMB:%I64d,CS:%I64d,CE:%I64d,LS:%I64d,LE:%I64d\n",
CylinderMB,
AlignedStartSector,
AlignedEndSector,
LogicalStartSector,
LogicalEndSector));
//
// allocate the new regions
//
if (CreateContainer) {
//
// allocate the container region
//
NewContainer = (PDISK_REGION)SpMemAlloc(sizeof(DISK_REGION));
if (!NewContainer)
return FALSE;
RtlZeroMemory(NewContainer, sizeof(DISK_REGION));
}
//
// allocate the logical drive region
//
NewLogical = (PDISK_REGION)SpMemAlloc(sizeof(DISK_REGION));
if (!NewLogical) {
SpMemFree(NewContainer);
return FALSE;
}
RtlZeroMemory(NewLogical, sizeof(DISK_REGION));
//
// put the new regions in the list
//
if (CreateContainer) {
NewContainer->Next = NewLogical;
NewLogical->Next = Region->Next;
Region->Next = NewContainer;
} else {
//
// This is the first logical inside the
// already existing extended partition
//
ASSERT(Region->Container->Next == Region);
NewLogical->Next = Region->Next;
Region->Container->Next = NewLogical;
}
//
// fill the container disk region.
//
if (CreateContainer) {
ASSERT(AlignedStartSector < AlignedEndSector);
NewContainer->DiskNumber = DiskNumber;
NewContainer->StartSector = AlignedStartSector;
NewContainer->SectorCount = AlignedEndSector - AlignedStartSector;
if (!FirstLogical) {
PDISK_REGION FirstContainer = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
while (FirstContainer && !SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(FirstContainer))
FirstContainer = FirstContainer->Next;
ASSERT(FirstContainer);
NewContainer->Container = FirstContainer;
}
SPPT_SET_REGION_PARTITIONED(NewContainer, FALSE);
SPPT_SET_REGION_DIRTY(NewContainer, TRUE);
SPPT_SET_REGION_EPT(NewContainer, EPTContainerPartition);
NewContainer->FreeSpaceKB = (ULONG)(-1);
NewContainer->AdjustedFreeSpaceKB = (ULONG)(-1);
Beyond1024 = SpIsRegionBeyondCylinder1024(NewContainer);
//
// Only mark the first extended (container) partition as XINT13_EXTENDED
// if beyond 1024 cylinders, for backward compatability with Win9x
//
PartitionType = (Beyond1024 && FirstLogical) ? PARTITION_XINT13_EXTENDED : PARTITION_EXTENDED;
SPPT_SET_PARTITION_TYPE(NewContainer, PartitionType);
}
//
// fill in the logical disk region
//
ASSERT(LogicalStartSector < LogicalEndSector);
if (CreateContainer) {
ASSERT((AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber)) == LogicalStartSector);
if (LogicalStartSector != (AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber))) {
LogicalStartSector = AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber);
}
}
ASSERT(LogicalEndSector <= AlignedEndSector);
if (LogicalEndSector > AlignedEndSector) {
LogicalEndSector = AlignedEndSector;
}
NewLogical->DiskNumber = DiskNumber;
NewLogical->StartSector = LogicalStartSector;
NewLogical->SectorCount = LogicalEndSector - LogicalStartSector;
if (CreateContainer) {
NewLogical->Container = NewContainer; // the new logical drive's container !!!
} else {
ASSERT(Region->Container);
NewLogical->Container = Region->Container;
}
SPPT_SET_REGION_PARTITIONED(NewLogical, TRUE);
SPPT_SET_REGION_DIRTY(NewLogical, TRUE);
SPPT_SET_REGION_EPT(NewLogical, EPTLogicalDrive);
NewLogical->FreeSpaceKB = (ULONG)(-1);
NewLogical->AdjustedFreeSpaceKB = (ULONG)(-1);
Beyond1024 = SpIsRegionBeyondCylinder1024(NewLogical);
PartitionType = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE;
//
// If the argument is specified and is valid partition type
// then use that making the assumption the caller knows exactly
// what he wants
//
if (ARGUMENT_PRESENT(PartInfo) && !IsContainerPartition(PartInfo->Mbr.PartitionType)) {
PartitionType = PartInfo->Mbr.PartitionType;
}
SPPT_SET_PARTITION_TYPE(NewLogical, PartitionType);
NewLogical->Filesystem = FilesystemNewlyCreated; // to zap boot sector
SpFormatMessage(Region->TypeName,
sizeof(Region->TypeName),
SP_TEXT_FS_NAME_BASE + Region->Filesystem);
//
// commit to the disk
//
Status = SpPtnCommitChanges(DiskNumber, &Result);
if (!(NT_SUCCESS(Status) && Result)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnDelete(%u, %I64u) failed to commit changes (%lx)\n",
DiskNumber,
StartSector,
Status));
}
Result = Result && NT_SUCCESS(Status);
//
// Reinitialize irrespective of commit's status
//
InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
if (!NT_SUCCESS(InitStatus)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCreateLogicalDrive(%u, %I64u) failed to reinit regions\n",
DiskNumber,
StartSector));
Result = FALSE;
}
if (Result && ARGUMENT_PRESENT(ActualDiskRegion)) {
*ActualDiskRegion = SpPtLookupRegionByStart(PartDisk,
FALSE,
LogicalStartSector);
//SpPtDumpDiskRegion(*ActualDiskRegion);
}
//
// We don't need to free the regions which we allocated above
// as the above commit and init would have done that already
//
return Result;
}
BOOLEAN
SpPtnCreate(
IN ULONG DiskNumber,
IN ULONGLONG StartSector,
IN ULONGLONG SizeInSectors, // Used ONLY in the ASR case
IN ULONGLONG SizeMB,
IN BOOLEAN InExtended,
IN BOOLEAN AlignToCylinder,
IN PPARTITION_INFORMATION_EX PartInfo,
OUT PDISK_REGION *ActualDiskRegion OPTIONAL
)
/*++
Routine Description:
Creates a primary partition of the requested size on the
given disk (either MBR/GPT).
Arguments:
DiskNumber : Disk on which the partition needs to be
created
StartSector : Start sector of the region, which represents
the free space in which the partition needs
to be created
SizeMB : The size of the partition
InExtended : Whether to create an logical drive
or not (currently NOT USED except in the ASR case)
AlignToCylinder : Indicating whether the partition should
be aligned on a cylinder boundary (Usually set
to TRUE, except in a few specific ASR cases).
PartInfo : Partition attributes to use
ActualDiskRegion : Place holder for the actual disk
region which will represent the created
partition
Return Value:
TRUE if successful, otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
PDISK_REGION Region;
ULONGLONG SectorCount, AlignedStartSector;
ULONGLONG AlignedEndSector, LeftOverSectors;
PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
PDISK_REGION PrevRegion;
PDISK_REGION NewRegion = NULL;
NTSTATUS Status;
NTSTATUS InitStatus;
BOOLEAN FirstLogical = TRUE;
//
// Verify that the optional attributes specified
// are correct
//
if (PartInfo) {
if ((SPPT_IS_MBR_DISK(DiskNumber) &&
(PartInfo->PartitionStyle != PARTITION_STYLE_MBR)) ||
(SPPT_IS_GPT_DISK(DiskNumber) &&
(PartInfo->PartitionStyle != PARTITION_STYLE_GPT))) {
return FALSE;
}
}
Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
if (!Region)
return Result;
ASSERT(SPPT_IS_REGION_PARTITIONED(Region) == FALSE);
SpPtDumpDiskRegion(Region);
//
// Determine the number of sectors in the size passed in.
//
if (SpDrEnabled()) {
SectorCount = SizeInSectors;
}
else {
SectorCount = SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector);
}
//
// Align the start sector.
//
if (AlignToCylinder) {
if (!SpDrEnabled()) {
AlignedStartSector = SpPtAlignStart(Disk, StartSector, FALSE);
}
else {
AlignedStartSector = SpPtAlignStart(Disk, StartSector, InExtended);
}
}
else {
AlignedStartSector = StartSector;
}
//
// Determine the end sector based on the size passed in.
//
AlignedEndSector = AlignedStartSector + SectorCount;
//
// Align the ending sector to a cylinder boundary. If it is not already
// aligned and is more than half way into the final cylinder, align it up,
// otherwise align it down.
//
if (AlignToCylinder) {
LeftOverSectors = AlignedEndSector % Disk->SectorsPerCylinder;
if (LeftOverSectors) {
AlignedEndSector -= LeftOverSectors;
if (LeftOverSectors > (Disk->SectorsPerCylinder / 2)) {
AlignedEndSector += Disk->SectorsPerCylinder;
}
}
}
//
// If the ending sector is past the end of the free space, shrink it
// so it fits.
//
while(AlignedEndSector > Region->StartSector + Region->SectorCount) {
AlignedEndSector -= Disk->SectorsPerCylinder;
}
//
// Find out if last sector is in the last cylinder. If it is then align it down.
// This is necessary so that we reserve a cylinder at the end of the disk, so that users
// can convert the disk to dynamic after the system is installed.
//
// (guhans) Don't align down if this is ASR. ASR already takes this into account.
//
if( !DockableMachine && !SpDrEnabled() && SPPT_IS_MBR_DISK(DiskNumber) &&
(AlignedEndSector > ((Disk->CylinderCount - 1) * Disk->SectorsPerCylinder))) {
AlignedEndSector -= Disk->SectorsPerCylinder;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: End of partition was aligned down 1 cylinder \n"));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: AlignedStartSector = %I64x \n", AlignedStartSector));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: AlignedEndSector = %I64x \n", AlignedEndSector));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SectorsPerCylinder = %lx \n", Disk->SectorsPerCylinder));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: CylinderCount = %lx \n", Disk->CylinderCount));
}
ASSERT(AlignedEndSector > 0);
//
// Find the previous region
//
PrevRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
if(PrevRegion == Region) {
PrevRegion = NULL;
} else {
while (PrevRegion) {
if(PrevRegion->Next == Region) {
break;
}
PrevRegion = PrevRegion->Next;
}
}
//
// Create a new disk region for the new free space at the
// beginning and end of the free space, if any.
//
if(AlignedStartSector - Region->StartSector) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnCreate():Previous:OS:%I64d,AS:%I64d,DIFF:%I64d,S/P:%d\n",
Region->StartSector,
AlignedStartSector,
(ULONGLONG)(AlignedStartSector - Region->StartSector),
Disk->SectorsPerCylinder));
NewRegion = SpPtAllocateDiskRegionStructure(
DiskNumber,
Region->StartSector,
AlignedStartSector - Region->StartSector,
FALSE,
NULL,
0
);
ASSERT(NewRegion);
if(PrevRegion) {
PrevRegion->Next = NewRegion;
} else {
ASSERT(Region == SPPT_GET_PRIMARY_DISK_REGION(DiskNumber));
PartDisk->PrimaryDiskRegions = NewRegion;
}
NewRegion->Next = Region;
}
if(Region->StartSector + Region->SectorCount - AlignedEndSector) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnCreate():Next:OE:%I64d,AE:%I64d,DIFF:%I64d,S/P:%d\n",
(ULONGLONG)(Region->StartSector + Region->SectorCount),
AlignedEndSector,
(ULONGLONG)(Region->StartSector + Region->SectorCount - AlignedEndSector),
Disk->SectorsPerCylinder));
NewRegion = SpPtAllocateDiskRegionStructure(
DiskNumber,
AlignedEndSector,
Region->StartSector + Region->SectorCount -
AlignedEndSector,
FALSE,
NULL,
0
);
NewRegion->Next = Region->Next;
Region->Next = NewRegion;
}
//
// fill the current disk region.
//
Region->DiskNumber = DiskNumber;
Region->StartSector = AlignedStartSector;
Region->SectorCount = AlignedEndSector - AlignedStartSector;
SPPT_SET_REGION_PARTITIONED(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
Region->VolumeLabel[0] = 0;
Region->Filesystem = FilesystemNewlyCreated;
Region->FreeSpaceKB = (ULONG)(-1);
Region->AdjustedFreeSpaceKB = (ULONG)(-1);
//
// Set the passed in partition information
//
if (PartInfo) {
SpPtnSetRegionPartitionInfo(Region, PartInfo);
}
SpFormatMessage(Region->TypeName,
sizeof(Region->TypeName),
SP_TEXT_FS_NAME_BASE + Region->Filesystem);
//
// commit to the disk
//
Status = SpPtnCommitChanges(DiskNumber, &Result);
if (!(Result && NT_SUCCESS(Status))) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCreate(%u, %I64u) failed to commit changes to"
"the drive (%lx)\n",
DiskNumber,
StartSector,
Status));
}
Result = Result && NT_SUCCESS(Status);
//
// Reinitialize irrespective of commit's status
//
InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
if (!NT_SUCCESS(InitStatus)){
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCreate(%u, %I64u) failed to reinitialize regions\n",
DiskNumber,
StartSector));
Result = FALSE;
}
if (Result && ARGUMENT_PRESENT(ActualDiskRegion)) {
*ActualDiskRegion = SpPtLookupRegionByStart(PartDisk,
FALSE,
AlignedStartSector);
}
return Result;
}
BOOLEAN
SpPtnDoCreate(
IN PDISK_REGION Region,
OUT PDISK_REGION *ActualRegion, OPTIONAL
IN BOOLEAN ForNT,
IN ULONGLONG DesiredMB OPTIONAL,
IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
IN BOOLEAN ConfirmIt
)
/*++
Routine Description:
Given the region which was selected by the user,
this routine creates the appropriate partition in
it.
This routine decides whether to create a primary or
container partition on MBR disks.
Algorithm:
if (RemoveableMedia && already partition exists) {
1. put up a warning for the user
2. return with error
}
if ((MBR disk) && ((there is no space for primary partition) ||
(region is in a container space)){
1. create a logical drive using SpPtnCreateLogicalDrive()
} else {
1. align the start sector.
2. create the required GPT/MBR partition.
}
Arguments:
Region - The region representing the free space on disk
where the partition needs to be created.
ActualRegion - Place holder, for the region which will
represent the actual partition after
creating it.
ForNT - Indicates whether to use the given desired size
argument or not.
DesiredSize - The size of the partition to created
PartInfo - The partition attributes to use while creating
the new partition
ConfirmIt - Whether to pop up error dialogs, if something
goes wrong while creating the partition
Return Value:
TRUE if successful otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
ULONG DiskNumber = Region->DiskNumber;
ULONGLONG MinMB = 0, MaxMB = 0;
ULONGLONG SizeMB = 0;
BOOLEAN ReservedRegion = FALSE;
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
if (SPPT_IS_MBR_DISK(DiskNumber)) {
ULONG PrimaryCount = 0;
ULONG ContainerCount = 0;
ULONG LogicalCount = 0;
ULONG ValidPrimaryCount = 0;
BOOLEAN InContainer = FALSE;
BOOLEAN FirstContainer = FALSE;
SpPtnGetPartitionTypeCounts(DiskNumber,
TRUE,
&PrimaryCount,
&ContainerCount,
&LogicalCount,
&ValidPrimaryCount,
NULL);
//
// Create a logical drive if we have a valid primary
// or there is no more space for another primary
//
FirstContainer = (ContainerCount == 0) && (ValidPrimaryCount > 0);
InContainer = (Region->Container != NULL);
//
// We allow only one partition on the removable media (?)
//
if (SPPT_IS_REMOVABLE_DISK(DiskNumber)) {
if (PrimaryCount || ContainerCount || LogicalCount) {
ULONG ValidKeys[2] = { ASCI_CR ,0 };
//
// Disk is already partitioned
//
SpDisplayScreen(SP_SCRN_REMOVABLE_ALREADY_PARTITIONED,
3,
HEADER_HEIGHT + 1);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
SpWaitValidKey(ValidKeys, NULL, NULL);
return FALSE;
}
} else {
if (FirstContainer || InContainer) {
//
// create the logical drive
//
Result = SpPtnCreateLogicalDrive(DiskNumber,
Region->StartSector,
0, // SizeInSectors: used only in the ASR case
ForNT,
TRUE, // AlignToCylinder
DesiredMB,
PartInfo,
ActualRegion);
if (!Result) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCreateLogicalDrive() failed\n"));
}
return Result;
}
//
// check to see if there is no space in the partition table
//
if (PrimaryCount >= (PTABLE_DIMENSION - 1)) {
//
// Let the user know that the partition table is full
//
if (ConfirmIt) {
while (TRUE) {
ULONG Keys[2] = {ASCI_CR, 0};
SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,
3,
CLIENT_TOP + 1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0
);
if (SpWaitValidKey(Keys, NULL, NULL) == ASCI_CR)
return FALSE;
}
} else {
return TRUE;
}
}
}
}
//
// need to create the primary / GPT partition
//
SpPtQueryMinMaxCreationSizeMB(DiskNumber,
Region->StartSector,
FALSE,
TRUE,
&MinMB,
&MaxMB,
&ReservedRegion
);
if (ReservedRegion) {
ULONG ValidKeys[2] = {ASCI_CR , 0};
SpStartScreen(
SP_SCRN_REGION_RESERVED,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
SpWaitValidKey(ValidKeys, NULL, NULL);
return FALSE;
}
if (ForNT) {
//
// If a size was requested then try to use that, otherwise use
// the maximum.
//
if (DesiredMB) {
if (DesiredMB <= MaxMB) {
SizeMB = DesiredMB;
} else {
return FALSE; // don't have the space user requested
}
} else {
SizeMB = MaxMB;
}
} else {
if (!SpPtnGetSizeFromUser(Disk, MinMB, MaxMB, &SizeMB))
return FALSE; // user didn't want to proceed
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_PLEASE_WAIT,
0);
}
//SpPtDumpDiskRegionInformation(DiskNumber, FALSE);
//
// Create the partition.
//
Result = SpPtnCreate(
Region->DiskNumber,
Region->StartSector,
0, // SizeInSectors: used only in the ASR case
SizeMB,
FALSE,
TRUE, // AlignToCylinder
PartInfo,
ActualRegion
);
//SpPtDumpDiskRegionInformation(DiskNumber, FALSE);
if (!Result) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnCreate() failed \n"));
}
return Result;
}
BOOLEAN
SpPtnDoDelete(
IN PDISK_REGION pRegion,
IN PWSTR RegionDescription,
IN BOOLEAN ConfirmIt
)
/*++
Routine Description:
Given the region which was selected by the user,
this routine prompts the user then calls the
actual deletion routine
Argument:
pRegion - Region selected by the user which
needs to be deleted
RegionDescription - Description of the
region
ConfirmIt - Whether the deletion needs to be
confirmed
Return Value:
TRUE if deletion was carried out and was successful.
FALSE if deletion was cancelled or could not be carried
out because of some other error.
++*/
{
ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; // do not change order
ULONG Mnemonics[2] = { MnemonicDeletePartition2, 0 };
PHARD_DISK Disk;
ULONG Key;
BOOLEAN Result = FALSE;
//
// Prompt for MSR deletion
//
if (SPPT_IS_GPT_DISK(pRegion->DiskNumber) &&
SPPT_IS_REGION_MSFT_RESERVED(pRegion) && ConfirmIt) {
SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_MSRPART, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
return Result;
}
}
//
// Special warning if this is a system partition.
//
// Do not check system partition on NEC98.
//
if (!IsNEC_98) { //NEC98
if(ConfirmIt && pRegion->IsSystemPartition) {
SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_SYSPART,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
return Result;
}
}
} //NEC98
if(ConfirmIt && (pRegion->DynamicVolume || SPPT_IS_REGION_LDM_METADATA(pRegion))) {
SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_DYNVOL,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
return Result;
}
}
//
// CR is no longer a valid key.
//
ValidKeys[1] = 0;
//
// Display the staus text.
//
if (ConfirmIt) {
Disk = SPPT_GET_HARDDISK(pRegion->DiskNumber);
SpStartScreen(
SP_SCRN_CONFIRM_REMOVE_PARTITION,
3,
CLIENT_TOP+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
RegionDescription,
Disk->Description
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_L_EQUALS_DELETE,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
Key = SpWaitValidKey(ValidKeys,NULL,Mnemonics);
if(Key == ASCI_ESC) {
return Result;
}
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_PLEASE_WAIT,
0);
}
//
// Delete the bootset, if any, for the region
//
SpPtDeleteBootSetsForRegion(pRegion);
//
// Now go ahead and delete it.
//
Result = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
if (!Result) {
if (ConfirmIt) {
SpDisplayScreen(SP_SCRN_PARTITION_DELETE_FAILED,3,HEADER_HEIGHT+1);
SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
SpInputDrain();
while(SpInputGetKeypress() != ASCI_CR) ;
}
return Result;
}
//
// Delete the drive letters if the necessary. This is to ensure that
// the drive letters assigned to CD-ROM drives will go away,
// when the the disks have no partitioned space.
//
SpPtDeleteDriveLetters();
return Result;
}
VOID
SpPtnMakeRegionActive(
IN PDISK_REGION Region
)
/*++
Routine Description:
Makes the given region active (i.e. converts into system partition).
Is valid only for MBR disks. Makes all the other regions
inactive on the disk
Arguments:
Region - The region (primary partition) which needs to made
active.
Return Value:
None.
--*/
{
static BOOLEAN WarnedOtherOS = FALSE;
if (Region && SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(Region->DiskNumber);
while (CurrRegion) {
if ((Region != CurrRegion) &&
SPPT_IS_REGION_ACTIVE_PARTITION(CurrRegion)) {
//
// Give the warning for the first time
//
if (!WarnedOtherOS && !UnattendedOperation) {
SpDisplayScreen((SPPT_GET_PARTITION_TYPE(CurrRegion) == 10) ?
SP_SCRN_BOOT_MANAGER : SP_SCRN_OTHER_OS_ACTIVE,
3,
HEADER_HEIGHT + 1);
SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,
DEFAULT_STATUS_ATTRIBUTE);
SpInputDrain();
while (SpInputGetKeypress() != ASCI_CR) ;
WarnedOtherOS = TRUE;
}
SPPT_MARK_REGION_AS_ACTIVE(CurrRegion, FALSE);
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
}
CurrRegion = CurrRegion->Next;
}
SPPT_MARK_REGION_AS_ACTIVE(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
}
}
BOOLEAN
SpPtMakeDiskRaw(
IN ULONG DiskNumber
)
/*++
Routine Description:
Converts the given disk to RAW i.e. Zaps couple of first
sectors which have information about the disk format
Arguments:
DiskNumber : Disk Index, to converted into RAW
Return Value:
TRUE, if successful, otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
if (DiskNumber < HardDiskCount) {
HANDLE DiskHandle;
NTSTATUS Status;
WCHAR DiskName[256];
swprintf(DiskName, L"\\Device\\Harddisk%u", DiskNumber);
//
// Open partition 0 on this disk..
//
Status = SpOpenPartition0(DiskName, &DiskHandle, TRUE);
if(NT_SUCCESS(Status)){
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
ULONG BytesPerSector = Disk->Geometry.BytesPerSector;
ULONG BufferSize = (BytesPerSector * 2);
PVOID UBuffer = SpMemAlloc(BufferSize);
if (UBuffer) {
PVOID Buffer = UBuffer;
RtlZeroMemory(UBuffer, BufferSize);
Buffer = ALIGN(Buffer, BytesPerSector);
//
// Wipe out 0'th sector
//
Status = SpReadWriteDiskSectors(DiskHandle,
0,
1,
BytesPerSector,
Buffer,
TRUE);
if (NT_SUCCESS(Status)) {
//
// Wipe out 1st sector
//
Status = SpReadWriteDiskSectors(DiskHandle,
1,
1,
BytesPerSector,
Buffer,
TRUE);
if (NT_SUCCESS(Status)) {
//
// Wipe out 2nd sector
//
Status = SpReadWriteDiskSectors(DiskHandle,
2,
1,
BytesPerSector,
Buffer,
TRUE);
}
}
} else {
Status = STATUS_NO_MEMORY;
}
ZwClose(DiskHandle);
}
Result = NT_SUCCESS(Status);
}
if (Result) {
SpPtnFreeDiskRegions(DiskNumber);
}
return Result;
}
VOID
SpPtnDeletePartitionsForRemoteBoot(
PPARTITIONED_DISK PartDisk,
PDISK_REGION StartRegion,
PDISK_REGION EndRegion,
BOOLEAN Extended
)
/*++
Routine Description:
Deletes the specified start region and end region partitions
and all the partitions in between them.
Arguments:
PartDisk : The partitioned disk
StartRegion : The starting region for deletion
EndRegion : The Ending region for deletion
Extended : Not used (for backward compatability)
Return Value:
None
--*/
{
PDISK_REGION CurrRegion = StartRegion;
BOOLEAN FirstContainerDeleted = FALSE;
ULONG DiskNumber = StartRegion ?
StartRegion->DiskNumber : EndRegion->DiskNumber;
BOOLEAN Changes = FALSE;
NTSTATUS Status;
NTSTATUS InitStatus;
//
// Mark all the regions which need to be deleted
//
while (CurrRegion && (CurrRegion != EndRegion)) {
if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
if (SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(CurrRegion))
FirstContainerDeleted = TRUE;
//
// Remove any boot sets pointing to this region.
//
SpPtDeleteBootSetsForRegion(CurrRegion);
//
// Get rid of the compressed drives, if any
//
if( CurrRegion->NextCompressed != NULL ) {
SpDisposeCompressedDrives( CurrRegion->NextCompressed );
CurrRegion->NextCompressed = NULL;
CurrRegion->MountDrive = 0;
CurrRegion->HostDrive = 0;
}
}
CurrRegion = CurrRegion->Next;
}
if (EndRegion && CurrRegion && (CurrRegion == EndRegion)){
if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
if (SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(CurrRegion))
FirstContainerDeleted = TRUE;
//
// Remove any boot sets pointing to this region.
//
SpPtDeleteBootSetsForRegion(CurrRegion);
//
// Get rid of the compressed drives, if any
//
if( CurrRegion->NextCompressed != NULL ) {
SpDisposeCompressedDrives( CurrRegion->NextCompressed );
CurrRegion->NextCompressed = NULL;
CurrRegion->MountDrive = 0;
CurrRegion->HostDrive = 0;
}
}
}
//
// If the first container partition was deleted then delete
// all the container and logical partitions,
//
if (FirstContainerDeleted) {
CurrRegion = PartDisk->PrimaryDiskRegions;
while (CurrRegion) {
if (SPPT_IS_REGION_CONTAINER_PARTITION(CurrRegion) ||
SPPT_IS_REGION_LOGICAL_DRIVE(CurrRegion)) {
SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
//
// Remove any boot sets pointing to this region.
//
SpPtDeleteBootSetsForRegion(CurrRegion);
//
// Get rid of the compressed drives, if any
//
if( CurrRegion->NextCompressed != NULL ) {
SpDisposeCompressedDrives( CurrRegion->NextCompressed );
CurrRegion->NextCompressed = NULL;
CurrRegion->MountDrive = 0;
CurrRegion->HostDrive = 0;
}
}
CurrRegion = CurrRegion->Next;
}
}
//
// Commit the changes
//
Status = SpPtnCommitChanges(DiskNumber, &Changes);
//
// Initialize region structure for the disk again
//
InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
if (!NT_SUCCESS(Status) || !Changes || !NT_SUCCESS(InitStatus)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnDeletePartitionsForRemoteBoot(%p, %p, %p, %d) failed "
"with %lx status\n",
PartDisk,
StartRegion,
EndRegion,
Extended,
Status));
}
}
NTSTATUS
SpPtnMakeRegionArcSysPart(
IN PDISK_REGION Region
)
/*++
Routine Description:
Makes the given region a system partition on ARC machines
Arguments:
Region - The region which needs to be convered to system
partition
Return Value:
STATUS_SUCCESS if successful, otherwise appropriate error
code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (Region && SpIsArc() && !ValidArcSystemPartition) {
if (SPPT_IS_MBR_DISK(Region->DiskNumber)) {
if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
SpPtnMakeRegionActive(Region);
SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
Status = STATUS_SUCCESS;
}
} else {
WCHAR RegionName[MAX_PATH];
SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
//
// Remove the drive letter also
//
swprintf(RegionName,
L"\\Device\\Harddisk%u\\Partition%u",
Region->DiskNumber,
Region->PartitionNumber);
SpDeleteDriveLetter(RegionName);
Region->DriveLetter = 0;
Status = STATUS_SUCCESS;
}
}
return Status;
}
ULONG
SpPtnCountPartitionsByFSType(
IN ULONG DiskId,
IN FilesystemType FsType
)
/*++
Routine Description:
Counts the partition based on the file system type.
Note : The partitions which are marked
deleted are skipped.
Arguments:
DiskId : The disk on which the partitions need to be
counted
FsType : File system type which needs to present on
the partitions
Return Value:
Number of partitions containing the requested file system
--*/
{
ULONG Count = 0;
if ((FsType < FilesystemMax) && (DiskId < HardDiskCount)) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (Region) {
if (SPPT_IS_REGION_PARTITIONED(Region) &&
!SPPT_IS_REGION_MARKED_DELETE(Region) &&
(Region->Filesystem == FsType)) {
Count++;
}
Region = Region->Next;
}
}
return Count;
}
PDISK_REGION
SpPtnLocateESP(
VOID
)
{
PDISK_REGION EspRegion = NULL;
ULONG Index;
for (Index=0; (Index < HardDiskCount) && (!EspRegion); Index++) {
if (SPPT_IS_GPT_DISK(Index)) {
PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(Index);
while (CurrRegion) {
if (SPPT_IS_REGION_PARTITIONED(CurrRegion) &&
SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
EspRegion = CurrRegion;
break; // found the first ESP
}
CurrRegion = CurrRegion->Next;
}
}
}
return EspRegion;
}
NTSTATUS
SpPtnCreateESPForDisk(
IN ULONG DiskId
)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PDISK_REGION EspCandidateRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
if (EspCandidateRegion && SpPtnIsValidESPRegion(EspCandidateRegion)) {
ULONG DiskId = EspCandidateRegion->DiskNumber;
ULONGLONG SizeMB = SpPtnGetDiskESPSizeMB(DiskId);
PARTITION_INFORMATION_EX PartInfo;
PDISK_REGION EspRegion = NULL;
BOOLEAN CreateResult;
RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
PartInfo.PartitionStyle = PARTITION_STYLE_GPT;
PartInfo.Gpt.Attributes = 1; // required ???
PartInfo.Gpt.PartitionType = PARTITION_SYSTEM_GUID;
SpCreateNewGuid(&(PartInfo.Gpt.PartitionId));
CreateResult = SpPtnCreate(DiskId,
EspCandidateRegion->StartSector,
0, // SizeInSectors: used only in the ASR case
SizeMB,
FALSE,
TRUE,
&PartInfo,
&EspRegion);
if (CreateResult) {
//
// format this region
//
WCHAR RegionDescr[128];
//
// Mark this region as ESP
//
SPPT_MARK_REGION_AS_SYSTEMPARTITION(EspRegion, TRUE);
SPPT_SET_REGION_DIRTY(EspRegion, TRUE);
ValidArcSystemPartition = TRUE;
SpPtRegionDescription(
SPPT_GET_PARTITIONED_DISK(EspRegion->DiskNumber),
EspRegion,
RegionDescr,
sizeof(RegionDescr));
if (!SetupSourceDevicePath || !DirectoryOnSetupSource) {
SpGetWinntParams(&SetupSourceDevicePath, &DirectoryOnSetupSource);
}
Status = SpDoFormat(RegionDescr,
EspRegion,
FilesystemFat,
TRUE,
TRUE,
FALSE,
SifHandle,
0, // default cluster size
SetupSourceDevicePath,
DirectoryOnSetupSource);
if (!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnCreateESP() failed to"
" format ESP partition for %p region (%lx)\n",
EspRegion,
Status));
} else {
BOOLEAN AnyChanges = FALSE;
Status = SpPtnCommitChanges(EspRegion->DiskNumber,
&AnyChanges);
if (!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnCreateESP() failed to"
" commit changes to disk (%lx)\n",
Status));
}
Status = SpPtnInitializeDiskDrive(EspRegion->DiskNumber);
if (!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnCreateESP() failed to"
" reinitialize disk regions (%lx)\n",
Status));
}
}
} else {
Status = STATUS_UNSUCCESSFUL;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnCreateESP() failed to"
" create ESP partition for %p region (%lx)\n",
EspRegion,
Status));
}
}
return Status;
}
NTSTATUS
SpPtnCreateESP(
IN BOOLEAN PromptUser
)
{
NTSTATUS Status = STATUS_CANCELLED;
BOOLEAN Confirmed = FALSE;
if (ValidArcSystemPartition) {
Status = STATUS_SUCCESS;
return Status;
}
if (UnattendedOperation) {
Confirmed = TRUE;
} else {
if (PromptUser) {
//
// Prompt the user for confirmation
//
ULONG ValidKeys[] = { ASCI_CR, ASCI_ESC, 0 };
ULONG UserOption = ASCI_CR;
SpDisplayScreen(SP_AUTOCREATE_ESP, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_ESC_EQUALS_CANCEL,
0);
//
// Wait for user input
//
SpInputDrain();
UserOption = SpWaitValidKey(ValidKeys, NULL, NULL);
if (UserOption == ASCI_CR) {
Confirmed = TRUE;
}
} else {
Confirmed = TRUE;
}
}
if (Confirmed) {
WCHAR ArcDiskName[MAX_PATH];
ULONG DiskNumber;
ULONG ArcDiskNumber;
PDISK_REGION EspCandidateRegion = NULL;
//
// Find the first harddisk (non-removable) media that the
// BIOS enumerated to be used for system partition
//
for (DiskNumber = 0, Status = STATUS_UNSUCCESSFUL;
(!NT_SUCCESS(Status) && (DiskNumber < HardDiskCount));
DiskNumber++) {
swprintf(ArcDiskName, L"multi(0)disk(0)rdisk(%d)", DiskNumber);
ArcDiskNumber = SpArcDevicePathToDiskNumber(ArcDiskName);
//
// Make sure its not removable disk and its reachable by firmware
//
if ((ArcDiskNumber == (ULONG)-1) || SPPT_IS_REMOVABLE_DISK(ArcDiskNumber)) {
continue; // get to the next disk
}
Status = SpPtnCreateESPForDisk(ArcDiskNumber);
}
if (PromptUser && !NT_SUCCESS(Status)) {
ULONG ValidKeys[] = { ASCI_CR, 0 };
ValidArcSystemPartition = FALSE;
SpDisplayScreen(SP_AUTOCREATE_ESP_FAILED, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
//
// Wait for user input
//
SpInputDrain();
SpWaitValidKey(ValidKeys, NULL, NULL);
}
} else {
Status = STATUS_CANCELLED;
}
return Status;
}
NTSTATUS
SpPtnInitializeGPTDisk(
IN ULONG DiskNumber
)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if ((DiskNumber < HardDiskCount) && (SPPT_IS_GPT_DISK(DiskNumber))) {
PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
PDISK_REGION EspRegion = NULL;
PDISK_REGION MsrRegion = NULL;
while (CurrRegion && !EspRegion && !MsrRegion) {
if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
EspRegion = CurrRegion;
} else if (SPPT_IS_REGION_MSFT_RESERVED(CurrRegion)) {
MsrRegion = CurrRegion;
}
CurrRegion = CurrRegion->Next;
}
if (!MsrRegion) {
PDISK_REGION MsrCandidate = NULL;
if (EspRegion) {
MsrCandidate = EspRegion->Next;
} else {
MsrCandidate = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
}
if (MsrCandidate && SpPtnIsValidMSRRegion(MsrCandidate)) {
PARTITION_INFORMATION_EX PartInfo;
PDISK_REGION MsrRegion = NULL;
ULONGLONG SizeMB = SpPtnGetDiskMSRSizeMB(DiskNumber);
BOOLEAN CreateResult;
RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
PartInfo.PartitionStyle = PARTITION_STYLE_GPT;
PartInfo.Gpt.Attributes = 0; // required ???
PartInfo.Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID;
SpCreateNewGuid(&(PartInfo.Gpt.PartitionId));
CreateResult = SpPtnCreate(DiskNumber,
MsrCandidate->StartSector,
0, // SizeInSectors: used only in the ASR case
SizeMB,
FALSE,
TRUE,
&PartInfo,
&MsrRegion);
Status = CreateResult ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
if (!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnInitializeGPTDisk() failed with "
" (%lx)\n",
Status));
}
} else {
Status = STATUS_SUCCESS;
}
} else {
Status = STATUS_SUCCESS;
}
}
return Status;
}
NTSTATUS
SpPtnInitializeGPTDisks(
VOID
)
{
NTSTATUS LastError = STATUS_SUCCESS;
NTSTATUS Status = STATUS_SUCCESS;
ULONG DiskNumber;
for (DiskNumber = 0; (DiskNumber < HardDiskCount); DiskNumber++) {
if (SPPT_IS_GPT_DISK(DiskNumber)) {
Status = SpPtnInitializeGPTDisk(DiskNumber);
if (!NT_SUCCESS(Status)) {
LastError = Status;
}
}
}
return LastError;
}
NTSTATUS
SpPtnRepartitionGPTDisk(
IN ULONG DiskId,
IN ULONG MinimumFreeSpaceKB,
OUT PDISK_REGION *RegionToInstall
)
/*++
Routine Description:
Repartitions a given disk for unattended and remote
boot install case
Arguments:
DiskId : The disk which needs to be repartitioned
MinimumFreeSpace : Minimum space required in KB
RegionToInstall : Place holder for the region which
will be selected for installation.
Return Value:
Appropriate status code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if ((DiskId < HardDiskCount) && !SPPT_IS_REMOVABLE_DISK(DiskId)) {
PDISK_REGION CurrentRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
BOOLEAN Changes = FALSE;
//
// Mark all the existing partitioned space on the disk
// for deletion
//
while (CurrentRegion) {
if (SPPT_IS_REGION_PARTITIONED(CurrentRegion)) {
SPPT_SET_REGION_DELETED(CurrentRegion, TRUE);
SPPT_SET_REGION_DIRTY(CurrentRegion, TRUE);
Changes = TRUE;
}
CurrentRegion = CurrentRegion->Next;
}
//
// Delete all the partitioned space on the disk
//
if (Changes) {
Status = SpPtnCommitChanges(DiskId, &Changes);
} else {
Status = STATUS_SUCCESS;
}
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Update the in memory region structure for the disk
//
Status = SpPtnInitializeDiskDrive(DiskId);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Reinitialize the disk style to GPT to be sure its
// GPT disk
//
SPPT_SET_DISK_BLANK(DiskId, TRUE);
Status = SpPtnInitializeDiskStyle(DiskId,
PARTITION_STYLE_GPT,
NULL);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Update the in memory region structure for the disk
//
Status = SpPtnInitializeDiskDrive(DiskId);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// First create the ESP on the disk
//
Status = SpPtnCreateESPForDisk(DiskId);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Create the MSR partition
//
Status = SpPtnInitializeGPTDisk(DiskId);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Find the first free space region with adequate space
//
CurrentRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
while (CurrentRegion) {
if (SPPT_IS_REGION_FREESPACE(CurrentRegion) &&
(SPPT_REGION_FREESPACE_KB(CurrentRegion) >= MinimumFreeSpaceKB)) {
break;
}
CurrentRegion = CurrentRegion->Next;
}
if (CurrentRegion) {
*RegionToInstall = CurrentRegion;
} else {
Status = STATUS_UNSUCCESSFUL;
}
}
return Status;
}