4087 lines
120 KiB
C
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;
|
|
}
|
|
|