/*++ 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 // // 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; }