Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4731 lines
153 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
sppart3.c
Abstract:
Partitioning module for disks in textmode setup.
Contains functions that initialize the in memory data structures,
representing the extents on the disk.
Author:
Matt Holle (matth) 1-December-1999
Revision History:
Vijay Jayaseelan (vijayj) 2-April-2000
- Clean up
- Added lookup and prompting for system partition on
ARC systems
- Added on disk ordinals for MBR disks
--*/
#include "spprecmp.h"
#pragma hdrstop
#include <initguid.h>
#include <devguid.h>
#include <diskguid.h>
#include <oemtypes.h>
#include "sppart3.h"
#define MAX_NTPATH_LENGTH (2048)
#define SUGGESTED_SYSTEMPARTIION_SIZE_MB (100)
#define SUGGESTED_INSTALL_PARTITION_SIZE_MB (4*1024)
extern BOOLEAN ConsoleRunning;
extern BOOLEAN ForceConsole;
//
// Debugging Macros
//
//#define PERF_STATS 1
//#define TESTING_SYSTEM_PARTITION 1
NTSTATUS
SpPtnInitializeDiskDrive(
IN ULONG DiskId
)
/*++
Routine Description:
Initializes the in memory disk region structures for
the given disk number.
Arguments:
DiskId : Disk ID
Return Value:
STATUS_SUCCESS if successful otherwise appropriate
error code
--*/
{
NTSTATUS Status;
#ifdef PERF_STATS
LARGE_INTEGER StartTime, EndTime;
ULONGLONG Diff;
KeQuerySystemTime(&StartTime);
#endif
//
// Send the event
//
SendSetupProgressEvent(PartitioningEvent, ScanDiskEvent, &DiskId);
//
// It would have been better to just have a pointer to a list
// of PDISK_REGIONs off of HARD_DISK, but for some reason, someone
// long ago decided to also maintain a list of PARTITIONED_DISK, which
// *does* contain a list of PDISK_REGIONs. I'm not sure of the use
// of maintaining both HARD_DISKs and PARTITIONED_DISKs, but that's
// the way the data structures are set, so we'll use those.
//
// But it doesn't end there. Rather than assuming that HardDisk[i]
// is describing the same disk as PartitionedDisks[i], we'll
// keep a pointer out of PartitionedDisks[i] that points to the
// corresponding HardDisk entry. Oh well...
//
PartitionedDisks[DiskId].HardDisk = &HardDisks[DiskId];
//
// Initialize structures that are based on the partition tables.
//
Status = SpPtnInitializeDiskAreas(DiskId);
//
// Now we need to fill in additional Region structures
// to represent empty space on the disk. For example, assume
// we have 2 partitions on the disk, but there's empty space
// in between:
// partition1: 0 - 200 sectors
// <empty space>
// partition2: 500 - 1000 sectors
//
// I need to create another Region structure to represent
// this empty space (ensuring that it's marked as unpartitioned.
// This will allow me to present a nice UI to the user when it's
// time to ask for input.
//
//
// Sort the Partitions based on their location on the disk.
//
if( NT_SUCCESS(Status) ) {
Status = SpPtnSortDiskAreas(DiskId);
//
// Create place holders for all empty spaces on the disk.
//
if( NT_SUCCESS(Status) ) {
Status = SpPtnFillDiskFreeSpaceAreas(DiskId);
if (NT_SUCCESS(Status)) {
//
// Mark logical drive's and its container, if any.
//
Status = SpPtnMarkLogicalDrives(DiskId);
}
}
}
#ifdef PERF_STATS
KeQuerySystemTime(&EndTime);
Diff = EndTime.QuadPart - StartTime.QuadPart;
Diff /= 1000000;
KdPrint(("SETUP:SpPtInitializeDiskDrive(%d) took %I64d Secs\n",
DiskId,
Diff));
#endif
SpPtDumpDiskDriveInformation(TRUE);
return Status;
}
NTSTATUS
SpPtnInitializeDiskDrives(
VOID
)
/*++
Routine Description:
Initializes all the disk drive's in memory data structure
representing the disk regions (extents)
Arguments:
None
Return Value:
STATUS_SUCCESS if successful other wise appropriate error
code.
--*/
{
ULONG disk;
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS ErrStatus = STATUS_SUCCESS;
BOOLEAN ValidHardDiskPresent = FALSE;
//
// If there are no hard disks, bail now.
//
if(!HardDiskCount) {
#if defined(REMOTE_BOOT)
//
// If this is a diskless remote boot setup, it's OK for there to be
// no hard disks. Otherwise, this is a fatal error.
//
if (!RemoteBootSetup || RemoteInstallSetup)
#endif // defined(REMOTE_BOOT)
{
SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
SpInputDrain();
while(SpInputGetKeypress() != KEY_F3);
SpDone(0,FALSE,TRUE);
}
return STATUS_SUCCESS;
}
CLEAR_CLIENT_SCREEN();
//
// Initialize all the RAW disks to platform specific
// default disk styles
//
for(disk=0, Status = STATUS_SUCCESS;
(disk < HardDiskCount);
disk++) {
if (SPPT_IS_RAW_DISK(disk) && SPPT_IS_BLANK_DISK(disk)) {
PHARD_DISK HardDisk = SPPT_GET_HARDDISK(disk);
PARTITION_STYLE Style = SPPT_DEFAULT_PARTITION_STYLE;
//
// Removable Media are always MBR (so don't bother)
//
if (HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) {
continue;
}
Status = SpPtnInitializeDiskStyle(disk,
Style,
NULL);
if (!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnInitializeDiskStyle(%d) failed with"
" %lx \n",
disk,
Status));
}
}
}
//
// Allocate an array for the partitioned disk descriptors.
//
PartitionedDisks = SpMemAlloc(HardDiskCount * sizeof(PARTITIONED_DISK));
if(!PartitionedDisks) {
return(STATUS_NO_MEMORY);
}
RtlZeroMemory( PartitionedDisks, HardDiskCount * sizeof(PARTITIONED_DISK) );
//
// Unlock the floppy if we booted off the ls-120 media
//
SpPtnUnlockDevice(L"\\device\\floppy0");
//
// Collect information about each partition.
//
for(disk=0, Status = ErrStatus = STATUS_SUCCESS;
(disk < HardDiskCount);
disk++) {
//
// Initialize the region structure for the given
// disk
//
Status = SpPtnInitializeDiskDrive(disk);
//
// TBD - In remote boot case the disk needs to have
// a valid signature. I am assuming that setupldr
// would have stamped the signature when booting off
// the harddisk
//
//
// Save of the last error
//
if (!NT_SUCCESS(Status)){
ErrStatus = Status;
} else {
ValidHardDiskPresent = TRUE;
}
}
//
// If no valid hard disk is present and this is not a remote boot setup
// then we stop the setup.
//
if (!ValidHardDiskPresent &&
(!RemoteBootSetup || RemoteInstallSetup)){
SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,
3,
HEADER_HEIGHT+1);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
0);
SpInputDrain();
while(SpInputGetKeypress() != KEY_F3);
SpDone(0,FALSE,TRUE);
return ErrStatus;
}
#if defined(_IA64_)
//
// Go and figure out the ESP partitions and
// initialize the MSR partitions on valid GPT
// disks
//
if (SpIsArc() && !SpDrEnabled()) {
if (!ValidArcSystemPartition) {
//
// Create a system partition
//
Status = SpPtnCreateESP(TRUE);
}
//
// Initialize the GPT disks, to have MSR
// partition
//
Status = SpPtnInitializeGPTDisks();
}
#endif
return ErrStatus;
}
NTSTATUS
SpPtnInitializeDiskAreas(
IN ULONG DiskNumber
)
/*++
Routine Description:
Examine the disk for partitioning information and fill in our
partition descriptors.
We'll ask the volume manager for a list of partitions and fill
in our descriptors from the information he provided us.
Arguments:
DiskNumber - supplies the disk number of the disk whose partitions
we want to inspect for determining their types.
Return Value:
NTSTATUS. If all goes well, we should be returing STATUS_SUCCESS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx;
WCHAR DevicePath[(sizeof(DISK_DEVICE_NAME_BASE)+sizeof(L"000"))/sizeof(WCHAR)];
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
PDISK_REGION pDiskRegion = NULL;
PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo = NULL;
PFILE_FS_SIZE_INFORMATION pSizeInfo = NULL;
PFILE_FS_VOLUME_INFORMATION pLabelInfo = NULL;
PWCHAR MyTempBuffer = NULL;
ULONG DriveLayoutSize,
i,
r;
PWSTR LocalSourceFiles[1] = { LocalSourceDirectory };
PHARD_DISK Disk = NULL;
PPARTITIONED_DISK PartDisk = NULL;
ULONGLONG *NewPartitions = NULL;
ULONG NewPartitionCount;
Disk = SPPT_GET_HARDDISK(DiskNumber);
PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
//
// Give the user some indication of what we're doing.
//
SpDisplayStatusText( SP_STAT_EXAMINING_DISK_N,
DEFAULT_STATUS_ATTRIBUTE,
Disk->Description);
//
// If we are updating the local source region disk then
// make sure we invalidate LocalSourceRegion
//
if (LocalSourceRegion && (LocalSourceRegion->DiskNumber == DiskNumber)) {
LocalSourceRegion = NULL;
}
//
// Save off the new partitions created
//
NewPartitionCount = SpPtnCountPartitionsByFSType(DiskNumber,
FilesystemNewlyCreated);
if (NewPartitionCount) {
PDISK_REGION NewRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
ULONG Index;
NewPartitions = (PULONGLONG) SpMemAlloc(sizeof(ULONGLONG) * NewPartitionCount);
if (!NewPartitions) {
return STATUS_NO_MEMORY;
}
RtlZeroMemory(NewPartitions, sizeof(ULONGLONG) * NewPartitionCount);
Index = 0;
while (NewRegion && (Index < NewPartitionCount)) {
if (SPPT_IS_REGION_PARTITIONED(NewRegion) &&
!SPPT_IS_REGION_MARKED_DELETE(NewRegion) &&
(NewRegion->Filesystem == FilesystemNewlyCreated)) {
NewPartitions[Index] = NewRegion->StartSector;
Index++;
}
NewRegion = NewRegion->Next;
}
}
//
// Free the old regions we allocated, if there are any
//
SpPtnFreeDiskRegions(DiskNumber);
//
// ============================
//
// Open a handle to this hard disk
//
// ============================
//
//
// 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 );
//
// Open partition 0 on this disk..
//
Status = SpOpenPartition0( DevicePath,
&Handle,
FALSE );
if(!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: unable to open partition0 on device %ws (%lx)\n",
DevicePath,
Status ));
if (NewPartitions) {
SpMemFree(NewPartitions);
}
return( Status );
}
//
// ============================
//
// Load the drive layout information.
//
// ============================
//
//
// Get the disk's layout information. We aren't
// sure how big of a buffer we need, so brute-force it.
//
DriveLayoutSize = 0;
DriveLayoutEx = NULL;
Status = STATUS_BUFFER_TOO_SMALL;
while ((Status == STATUS_BUFFER_TOO_SMALL) ||
(Status == STATUS_BUFFER_OVERFLOW)) {
if (DriveLayoutEx)
SpMemFree(DriveLayoutEx);
DriveLayoutSize += 1024;
DriveLayoutEx = SpMemAlloc( DriveLayoutSize );
if(!DriveLayoutEx) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
if (NewPartitions) {
SpMemFree(NewPartitions);
}
return (STATUS_NO_MEMORY);
}
RtlZeroMemory( DriveLayoutEx, DriveLayoutSize );
//
// Attempt to get the disk's partition information.
//
Status = ZwDeviceIoControlFile( Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
NULL,
0,
DriveLayoutEx,
DriveLayoutSize );
}
if(!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: unable to query IOCTL_DISK_GET_DRIVE_LAYOUT_EX on device %ws (%lx)\n",
DevicePath,
Status ));
if (NewPartitions) {
SpMemFree(NewPartitions);
}
if (DriveLayoutEx)
SpMemFree(DriveLayoutEx);
if (Handle != INVALID_HANDLE_VALUE)
ZwClose(Handle);
return ( Status );
}
//
// What kind of disk is this?
//
switch (DriveLayoutEx->PartitionStyle) {
case PARTITION_STYLE_GPT:
Disk->FormatType = DISK_FORMAT_TYPE_GPT;
break;
case PARTITION_STYLE_MBR:
Disk->FormatType = DISK_FORMAT_TYPE_PCAT;
Disk->Signature = DriveLayoutEx->Mbr.Signature;
#if defined(_IA64_)
//
// Make sure that this is not a raw disk
// which is being faked as MBR disk
//
if (SpPtnIsRawDiskDriveLayout(DriveLayoutEx)) {
Disk->FormatType = DISK_FORMAT_TYPE_RAW;
SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
}
#endif
break;
case PARTITION_STYLE_RAW:
Disk->FormatType = DISK_FORMAT_TYPE_RAW;
SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
break;
default:
Disk->FormatType = DISK_FORMAT_TYPE_UNKNOWN;
break;
}
SpAppendDiskTag(Disk);
SpPtDumpDriveLayoutInformation(DevicePath, DriveLayoutEx);
//
// Don't need this guy anymore.
//
ZwClose( Handle );
//
// might need this while committing
//
Disk->DriveLayout = *DriveLayoutEx;
Status = STATUS_SUCCESS;
//
// ============================
//
// Initialize partiton descriptors.
//
// ============================
//
if(DriveLayoutEx->PartitionCount) {
BOOLEAN SysPartFound = FALSE;
ULONG PartitionedSpaceCount = 1;
//
// Initialize an area entry for each partition
// on the disk.
//
for( i = 0, pDiskRegion = NULL; i < DriveLayoutEx->PartitionCount; i++ ) {
ULONG Count = 0;
ULONG TypeNameId = SP_TEXT_UNKNOWN;
LARGE_INTEGER DelayTime;
BOOLEAN AssignDriveLetter = TRUE;
PPARTITION_INFORMATION_EX PartInfo = DriveLayoutEx->PartitionEntry + i;
//
// IOCTL_DISK_GET_DRIVE_LAYOUT_EX may return us a list of entries that
// are not used, so ignore these partitions.
//
if (// if its partition 0, which indicates whole disk
(SPPT_IS_GPT_DISK(DiskNumber) && (PartInfo->PartitionNumber == 0)) ||
(PartInfo->PartitionLength.QuadPart == 0) ||
// if MBR entry not used or length is zero
((DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR) &&
(PartInfo->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) &&
(PartInfo->PartitionLength.QuadPart == 0)) ||
// if unknown/unused GPT partition
((DriveLayoutEx->PartitionStyle == PARTITION_STYLE_GPT) &&
(!memcmp(&PartInfo->Gpt.PartitionType,
&PARTITION_ENTRY_UNUSED_GUID, sizeof(GUID))))){
continue;
}
//
// Allocate space for the next region.
//
if(pDiskRegion) {
pDiskRegion->Next = SpMemAlloc( sizeof(DISK_REGION) );
pDiskRegion = pDiskRegion->Next;
} else {
//
// First region allocation for harddisk so initialize
// the region list head for the hardisk
//
ASSERT(PartDisk->PrimaryDiskRegions == NULL);
pDiskRegion = SpMemAlloc(sizeof(DISK_REGION));
PartDisk->PrimaryDiskRegions = pDiskRegion;
SPPT_SET_DISK_BLANK(DiskNumber, FALSE);
}
if(!pDiskRegion) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
Status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory(pDiskRegion, sizeof(DISK_REGION));
//
// Start filling out our Region descriptor...
//
//
// DiskNumber
//
pDiskRegion->DiskNumber = DiskNumber;
//
// Partition information
//
pDiskRegion->PartInfo = *PartInfo;
//
// StartSector
//
pDiskRegion->StartSector = PartInfo->StartingOffset.QuadPart /
Disk->Geometry.BytesPerSector;
//
// SectorCount
//
pDiskRegion->SectorCount = PartInfo->PartitionLength.QuadPart /
Disk->Geometry.BytesPerSector;
//
// PartitionNumber
//
pDiskRegion->PartitionNumber = PartInfo->PartitionNumber;
if (SPPT_IS_MBR_DISK(DiskNumber) && (PartInfo->PartitionNumber == 0)) {
if (IsContainerPartition(PartInfo->Mbr.PartitionType)) {
SPPT_SET_REGION_EPT(pDiskRegion, EPTContainerPartition);
}
//
// nothing after this is really needed for container partition
//
continue;
} else {
//
// PartitionedSpace
//
SPPT_SET_REGION_PARTITIONED(pDiskRegion, TRUE);
}
if (SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
pDiskRegion->TablePosition = PartitionedSpaceCount++;
}
//
// Partition Number should be valid
//
ASSERT(pDiskRegion->PartitionNumber);
//
// IsSystemPartition (is it active)
//
if( DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR ) {
//
// On IA64 systems don't use active MBR partitions as system
// partitions
//
if (!SpIsArc()) {
//
// He's an MBR disk, so we can rely on the BootIndicator field.
//
pDiskRegion->IsSystemPartition = PartInfo->Mbr.BootIndicator;
}
//
// Don't assign drive letters to OEM partitions
//
if (IsOEMPartition(SPPT_GET_PARTITION_TYPE(pDiskRegion))) {
AssignDriveLetter = FALSE;
}
} else {
//
// He's not MBR, look at his PartitionType (which is a GUID).
//
pDiskRegion->IsSystemPartition = FALSE;
if(IsEqualGUID(&(PartInfo->Gpt.PartitionType), &(PARTITION_SYSTEM_GUID))) {
pDiskRegion->IsSystemPartition = TRUE;
AssignDriveLetter = FALSE;
#ifdef _IA64_
//
// We assign a Drive letter for ESP in the Recovery Console
// for IA64
//
if (ForceConsole) {
AssignDriveLetter = TRUE;
}
#endif
}
}
if (SPPT_IS_REGION_SYSTEMPARTITION(pDiskRegion)) {
SysPartFound = TRUE;
}
//
// FtPartition
//
if( DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR ) {
//
// He's an MBR disk, so we can rely on the PartitionType field.
//
pDiskRegion->FtPartition = IsFTPartition(PartInfo->Mbr.PartitionType);
} else {
//
// He's not MBR. Assume he's GPT and look at his PartitionType (which is a GUID).
//
pDiskRegion->FtPartition = FALSE;
}
//
// DynamicVolume
// DynamicVolumeSuitableForOS
//
if( DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR ) {
//
// He's an MBR disk, so we can rely on the PartitionType field.
//
pDiskRegion->DynamicVolume = (PartInfo->Mbr.PartitionType == PARTITION_LDM);
} else {
//
// He's not MBR. Assume he's GPT and look at his PartitionType (which is a GUID).
//
pDiskRegion->DynamicVolume = FALSE;
if( !memcmp(&PartInfo->Gpt.PartitionType,
&PARTITION_LDM_DATA_GUID, sizeof(GUID)) ) {
//
// The GUIDs match.
pDiskRegion->DynamicVolume = TRUE;
}
}
if (pDiskRegion->DynamicVolume) {
TypeNameId = SP_TEXT_PARTITION_NAME_DYNVOL;
}
//
// if MSFT reserved partition (we need to keep track of it but
// not process it)
//
if((DriveLayoutEx->PartitionStyle == PARTITION_STYLE_GPT) &&
(IsEqualGUID(&(PartInfo->Gpt.PartitionType), &PARTITION_MSFT_RESERVED_GUID) ||
IsEqualGUID(&(PartInfo->Gpt.PartitionType), &PARTITION_LDM_METADATA_GUID) ||
IS_OEM_PARTITION_GPT(PartInfo->Gpt.Attributes))) {
pDiskRegion->IsReserved = TRUE;
AssignDriveLetter = FALSE;
//
// Get the type name from the resources.
//
SpFormatMessage(pDiskRegion->TypeName,
sizeof(pDiskRegion->TypeName),
SP_TEXT_PARTNAME_RESERVED);
continue;
}
//
// Assume we can't install on this dynamic volume.
//
pDiskRegion->DynamicVolumeSuitableForOS = FALSE;
//
// For the following entries, we need an Open handle to this partition.
//
//
// If the partition just got created, we may have to wait for
// a few seconds before its actually available
//
// Note : We wait for 20 secs at the max for each partition
//
for (Count = 0; (Count < 10); Count++) {
//
// Open the handle to the required partition
//
Status = SpOpenPartition( DevicePath,
PartInfo->PartitionNumber,
&Handle,
FALSE );
if((Status == STATUS_NO_SUCH_DEVICE) ||
(Status == STATUS_OBJECT_NAME_NOT_FOUND)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: unable to open partition%d on device %ws (%lx)\n",
PartInfo->PartitionNumber,
DevicePath,
Status ));
DelayTime.HighPart = -1; // relative time
DelayTime.LowPart = (ULONG)(-20000000); // 2 secs in 100ns interval
KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
} else {
break;
}
}
//
// Need the partition handle to continue
//
if (!NT_SUCCESS(Status)) {
//
// ignore the error while trying to open dynamic disks
//
if (SPPT_IS_REGION_DYNAMIC_VOLUME(pDiskRegion)) {
Status = STATUS_SUCCESS;
}
//
// Get the type name from the resources.
//
SpFormatMessage(pDiskRegion->TypeName,
sizeof(pDiskRegion->TypeName),
TypeNameId);
continue;
}
//
// Check, if installtion can be done on the dynamic volume
//
if( pDiskRegion->DynamicVolume ) {
//
// Call disk manager to tell me if it's okay to
// install on this dynamic volume. If I get back
// anything but STATUS_SUCCESS, then assume we
// can't install here.
//
Status = ZwDeviceIoControlFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VOLUME_IS_PARTITION,
NULL,
0,
NULL,
0 );
if( NT_SUCCESS(Status) ){
pDiskRegion->DynamicVolumeSuitableForOS = TRUE;
}
}
//
// Filesystem
//
pFSInfo = SpMemAlloc( sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + (MAX_PATH*2) );
if( !pFSInfo ) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
ZwClose( Handle );
Status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory( pFSInfo, sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + (MAX_PATH*2) );
Status = ZwQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
pFSInfo,
sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + (MAX_PATH*2),
FileFsAttributeInformation );
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: Failed to retrieve partition attribute information (%lx)\n",
Status ));
} else {
if (!wcscmp(pFSInfo->FileSystemName, L"NTFS")) {
pDiskRegion->Filesystem = FilesystemNtfs;
TypeNameId = SP_TEXT_FS_NAME_3;
} else if (!wcscmp(pFSInfo->FileSystemName, L"FAT")) {
pDiskRegion->Filesystem = FilesystemFat;
TypeNameId = SP_TEXT_FS_NAME_2;
} else if (!wcscmp(pFSInfo->FileSystemName, L"FAT32")) {
pDiskRegion->Filesystem = FilesystemFat32;
TypeNameId = SP_TEXT_FS_NAME_4;
} else if (TypeNameId == SP_TEXT_UNKNOWN){
ULONG Index;
pDiskRegion->Filesystem = FilesystemUnknown;
//
// Make sure it was not already created new partition
//
for (Index = 0; Index < NewPartitionCount; Index++) {
if (pDiskRegion->StartSector == NewPartitions[Index]) {
pDiskRegion->Filesystem = FilesystemNewlyCreated;
TypeNameId = SP_TEXT_FS_NAME_1;
break;
}
}
}
}
//
// if we cannot determine the partition type, then try
// to use the known name from partition id.
//
if ((TypeNameId == SP_TEXT_UNKNOWN) && SPPT_IS_MBR_DISK(DiskNumber)) {
ULONG PartitionType = SPPT_GET_PARTITION_TYPE(pDiskRegion);
if (PartitionType < 256) {
UCHAR NameId = PartitionNameIds[SPPT_GET_PARTITION_TYPE(pDiskRegion)];
if (NameId != 0xFF) {
TypeNameId = SP_TEXT_PARTITION_NAME_BASE + NameId;
}
}
}
//
// Get the type name from the resources.
//
SpFormatMessage(pDiskRegion->TypeName,
sizeof(pDiskRegion->TypeName),
TypeNameId);
SpMemFree( pFSInfo );
//
// FreeSpaceKB and BytesPerCluster (only if we know what FS it is)
//
if ((pDiskRegion->Filesystem != FilesystemUnknown) &&
(pDiskRegion->Filesystem != FilesystemNewlyCreated)) {
//
// Delete \pagefile.sys if it's there. This makes disk free space
// calculations a little easier.
//
MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
if( !MyTempBuffer ) {
//
// No memory...
//
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
Status = STATUS_NO_MEMORY;
break;
}
SpNtNameFromRegion( pDiskRegion,
MyTempBuffer,
MAX_NTPATH_LENGTH,
PrimaryArcPath );
SpConcatenatePaths( MyTempBuffer, L"" );
SpDeleteFile( MyTempBuffer, L"pagefile.sys", NULL );
SpMemFree( MyTempBuffer );
MyTempBuffer = NULL;
pSizeInfo = SpMemAlloc( sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2) );
if( !pSizeInfo ) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
ZwClose( Handle );
Status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory( pSizeInfo, sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2) );
Status = ZwQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
pSizeInfo,
sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2),
FileFsSizeInformation );
//
// Waiting for another 2 secs for the volume to appear
//
if (Status == STATUS_NO_SUCH_DEVICE) {
//
// Wait for 2 seconds
//
DelayTime.HighPart = -1; // relative time
DelayTime.LowPart = (ULONG)(-20000000); // 2 secs in 100ns interval
KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
RtlZeroMemory( pSizeInfo, sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2) );
Status = ZwQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
pSizeInfo,
sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2),
FileFsSizeInformation );
}
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: Failed to retrieve disk(%d)partition(%d) sizing information (%lx)\n",
DiskNumber,
pDiskRegion->PartitionNumber,
Status ));
} else {
LARGE_INTEGER FreeBytes;
FreeBytes = RtlExtendedIntegerMultiply(
pSizeInfo->AvailableAllocationUnits,
pSizeInfo->SectorsPerAllocationUnit * pSizeInfo->BytesPerSector );
pDiskRegion->FreeSpaceKB = RtlExtendedLargeIntegerDivide( FreeBytes,
1024, &r ).LowPart;
if(r >= 512) {
pDiskRegion->FreeSpaceKB++;
}
//
// Sigh... Legacy stuff. SpPtDeterminePartitionGood() will want this
// field so that he knows what the free-space+space_from_local_source is.
//
pDiskRegion->AdjustedFreeSpaceKB = pDiskRegion->FreeSpaceKB;
pDiskRegion->BytesPerCluster =
pSizeInfo->SectorsPerAllocationUnit * pSizeInfo->BytesPerSector;
}
SpMemFree( pSizeInfo );
//
// VolumeLabel
//
pLabelInfo = SpMemAlloc( sizeof(FILE_FS_VOLUME_INFORMATION) + (MAX_PATH*2) );
if( !pFSInfo ) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
ZwClose( Handle );
Status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory( pLabelInfo, sizeof(FILE_FS_VOLUME_INFORMATION) + (MAX_PATH*2) );
Status = ZwQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
pLabelInfo,
sizeof(FILE_FS_VOLUME_INFORMATION) + (MAX_PATH*2),
FileFsVolumeInformation );
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: Failed to retrieve volume information (%lx)\n", Status));
} else {
ULONG SaveCharCount;
//
// We'll only save away the first <n> characters of
// the volume label.
//
SaveCharCount = min( pLabelInfo->VolumeLabelLength + sizeof(WCHAR),
sizeof(pDiskRegion->VolumeLabel) ) / sizeof(WCHAR);
if(SaveCharCount) {
SaveCharCount--; // allow for terminating NUL.
}
wcsncpy( pDiskRegion->VolumeLabel,
pLabelInfo->VolumeLabel,
SaveCharCount );
pDiskRegion->VolumeLabel[SaveCharCount] = 0;
}
SpMemFree( pLabelInfo );
} else {
//
// Free space is what ever the partition size is
//
pDiskRegion->FreeSpaceKB = (pDiskRegion->SectorCount *
Disk->Geometry.BytesPerSector) / 1024;
pDiskRegion->AdjustedFreeSpaceKB = pDiskRegion->FreeSpaceKB;
}
//
// Assign the drive letter if required
//
if (AssignDriveLetter) {
//
// Retrieve nt pathname for this region.
//
MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
if( !MyTempBuffer ) {
//
// No memory...
//
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
Status = STATUS_NO_MEMORY;
break;
}
SpNtNameFromRegion( pDiskRegion,
MyTempBuffer,
MAX_NTPATH_LENGTH,
PrimaryArcPath );
//
// Assign the drive letter
//
pDiskRegion->DriveLetter = SpGetDriveLetter( MyTempBuffer, NULL );
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtInitializeDiskAreas: Partition = %ls, DriveLetter = %wc: \n",
MyTempBuffer, pDiskRegion->DriveLetter));
SpMemFree( MyTempBuffer );
MyTempBuffer = NULL;
}
//
// See if this guy has the local source.
//
//
MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
if( !MyTempBuffer ) {
//
// No memory...
//
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
Status = STATUS_NO_MEMORY;
break;
}
SpNtNameFromRegion( pDiskRegion,
MyTempBuffer,
MAX_NTPATH_LENGTH,
PrimaryArcPath );
SpConcatenatePaths( MyTempBuffer, L"" );
//
// Don't need this guy anymore.
//
ZwClose( Handle );
if( WinntSetup && !WinntFromCd && !LocalSourceRegion &&
SpNFilesExist(MyTempBuffer, LocalSourceFiles, ELEMENT_COUNT(LocalSourceFiles), TRUE) ) {
LocalSourceRegion = pDiskRegion;
pDiskRegion->IsLocalSource = TRUE;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: %ws is the local source partition.\n", MyTempBuffer));
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: %ws is not the local source partition.\n", MyTempBuffer));
}
SpMemFree( MyTempBuffer );
MyTempBuffer = NULL;
Status = STATUS_SUCCESS;
}
//
// Go ahead and locate the system partitions on this disk
//
if (SpIsArc()) {
if (!SysPartFound) {
SpPtnLocateDiskSystemPartitions(DiskNumber);
} else {
ValidArcSystemPartition = TRUE;
}
}
}
//
// Update the boot entries to reflect the
// new region pointers
//
SpUpdateRegionForBootEntries();
if (NewPartitions) {
SpMemFree(NewPartitions);
}
SpMemFree( DriveLayoutEx );
return Status;
}
NTSTATUS
SpPtnSortDiskAreas(
IN ULONG DiskNumber
)
/*++
Routine Description:
Examine the partitions defined on this disk and sort them
according to their location on the disk.
Arguments:
DiskNumber - supplies the disk number of the disk whose partitions
we want to inspect.
Return Value:
NTSTATUS. If all goes well, we should be returing STATUS_SUCCESS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PDISK_REGION pTempDiskRegion = NULL;
PDISK_REGION pCurrentDiskRegion = NULL;
PDISK_REGION pPreviousDiskRegion = NULL;
//
// Get a pointer to the list of regions.
//
pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
if( !pCurrentDiskRegion ) {
//
// Odd. Either something is very wrong, or
// this disk simply has no partitions, which is
// certainly possible. Assume the best.
//
return STATUS_SUCCESS;
}
//
// We got something. Go sort the list. There
// can't be very many partitions, so just bubble-sort.
//
while( pCurrentDiskRegion->Next ) {
//
// There's another partition ahead of
// us. See if we need to switch places.
//
if( pCurrentDiskRegion->StartSector > pCurrentDiskRegion->Next->StartSector ) {
//
// Yes, we need to swap these 2 entries.
// Fixup the pointers.
//
if( pPreviousDiskRegion ) {
//
// 1. Set the previous disk region to point to
// the region after us.
//
pPreviousDiskRegion->Next = pCurrentDiskRegion->Next;
} else {
//
// We're at the very beginning of the linked
// list.
//
//
// 1. Set the disk's region pointer to point to
// the region after us.
//
PartitionedDisks[DiskNumber].PrimaryDiskRegions = pCurrentDiskRegion->Next;
}
//
// 2. Set our our next region's Next pointer to
// come back to us.
//
pTempDiskRegion = pCurrentDiskRegion->Next->Next;
pCurrentDiskRegion->Next->Next = pCurrentDiskRegion;
//
// 3. Set our own pointer to a couple of regions ahead.
//
pCurrentDiskRegion->Next = pTempDiskRegion;
//
// Now reset so we start the sort over again.
//
pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
pPreviousDiskRegion = NULL;
} else {
//
// No need to swap these two regions in our list. Increment
// our pointers and continue.
//
pPreviousDiskRegion = pCurrentDiskRegion;
pCurrentDiskRegion = pCurrentDiskRegion->Next;
}
}
return Status;
}
NTSTATUS
SpPtnInitRegionFromDisk(
IN ULONG DiskNumber,
OUT PDISK_REGION Region
)
/*++
Routine Description:
Given the disk id, creates a disk region representing
the whole disk
Arguments:
DiskNumber : Disk Id
Region : Region which gets initialized on return
Return Value:
STATUS_SUCCESS if successful, otherwise STATUS_INVALID_PARAMETER
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (Region) {
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
RtlZeroMemory(Region, sizeof(DISK_REGION));
//
// Note : Most of the fields below don't need to be initialized
// because of the memset above, but its done for sake of
// clarity
//
Region->DiskNumber = DiskNumber;
Region->StartSector = Disk->Geometry.SectorsPerTrack;
Region->SectorCount = Disk->DiskSizeSectors - Region->StartSector;
SPPT_SET_REGION_PARTITIONED(Region, FALSE);
Region->PartitionNumber = 0;
Region->MbrInfo = NULL;
Region->TablePosition = 0;
Region->IsSystemPartition = FALSE;
Region->IsLocalSource = FALSE;
Region->Filesystem = FilesystemUnknown;
Region->FreeSpaceKB = Disk->DiskSizeMB * 1024;
Region->BytesPerCluster = -1;
Region->AdjustedFreeSpaceKB = Region->FreeSpaceKB;
Region->DriveLetter = 0;
Region->FtPartition = FALSE;
Region->DynamicVolume = FALSE;
Region->DynamicVolumeSuitableForOS = FALSE;
Status = STATUS_SUCCESS;
}
return Status;
}
NTSTATUS
SpPtnFillDiskFreeSpaceAreas(
IN ULONG DiskNumber
)
/*++
Routine Description:
This function will go peruse all partitions on the disk. If there are
any free regions on the disk, we'll create a region entry and
mark it as unformatted.
Arguments:
DiskNumber - supplies the disk number of the disk whose partitions
we want to inspect.
Return Value:
NTSTATUS. If all goes well, we should be returing STATUS_SUCCESS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PDISK_REGION pTempDiskRegion;
PDISK_REGION pCurrentDiskRegion = NULL;
ULONGLONG NextStart;
ULONGLONG NextSize;
PDISK_REGION FirstContainer = NULL;
//
// Get a pointer to the list of regions.
//
pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
if( !pCurrentDiskRegion ) {
//
// Odd. Either something is very wrong, or
// this disk simply has no partitions, which is
// certainly possible. Assume the best and
// create one region entry that encompasses all
// space on the disk, but is unpartitioned.
//
pCurrentDiskRegion = SpMemAlloc(sizeof(DISK_REGION));
if (pCurrentDiskRegion) {
Status = SpPtnInitRegionFromDisk(DiskNumber, pCurrentDiskRegion);
} else {
Status = STATUS_NO_MEMORY;
}
if (NT_SUCCESS(Status)) {
ASSERT(!PartitionedDisks[DiskNumber].PrimaryDiskRegions);
PartitionedDisks[DiskNumber].PrimaryDiskRegions =
pCurrentDiskRegion;
SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
}
return Status;
}
//
// The regions are already sorted according to their relative
// position on the disk, so before we go through them, let's
// see if there's any empty space on the disk occurring *before*
// the first partition.
//
if( pCurrentDiskRegion->StartSector > SPPT_DISK_TRACK_SIZE(DiskNumber) ) {
//
// Yep. Make a region descriptor for this guy (if he is more than
// one cylinder in size)
//
NextStart = SPPT_DISK_TRACK_SIZE(DiskNumber);
NextSize = pCurrentDiskRegion->StartSector - NextStart;
//
// The first partition can start at first track offset. So this need not always
// be of minimum cylinder size
//
if (NextSize >= (SPPT_DISK_CYLINDER_SIZE(DiskNumber) - SPPT_DISK_TRACK_SIZE(DiskNumber))) {
pTempDiskRegion = SpMemAlloc( sizeof(DISK_REGION) );
if(!pTempDiskRegion) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
return STATUS_NO_MEMORY;
}
RtlZeroMemory( pTempDiskRegion, sizeof(DISK_REGION) );
pTempDiskRegion->DiskNumber = DiskNumber;
pTempDiskRegion->StartSector = NextStart;
pTempDiskRegion->SectorCount = NextSize;
//
// Put this region before the current region
//
pTempDiskRegion->Next = pCurrentDiskRegion;
PartitionedDisks[DiskNumber].PrimaryDiskRegions = pTempDiskRegion;
}
}
//
// Now go through the regions, inserting regions to account for any
// empty space between the partitions.
//
while( pCurrentDiskRegion ) {
if( !pCurrentDiskRegion->Next ) {
NextStart = 0;
//
// if this is container partition then all the space in this
// container is free space
//
if (SPPT_IS_MBR_DISK(DiskNumber) &&
IsContainerPartition(SPPT_GET_PARTITION_TYPE(pCurrentDiskRegion))) {
PDISK_REGION ExtFree = NULL;
ASSERT(FirstContainer == NULL);
//
// We add one here because we should be able to differentiate the starting
// free region inside the extended partition from the extended partition
// itself.
//
NextStart = pCurrentDiskRegion->StartSector + 1;
NextSize = pCurrentDiskRegion->SectorCount;
if (NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) {
PDISK_REGION ExtFree = SpMemAlloc(sizeof(DISK_REGION));
if (!ExtFree) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
return STATUS_NO_MEMORY;
}
RtlZeroMemory(ExtFree, sizeof(DISK_REGION));
ExtFree->DiskNumber = DiskNumber;
ExtFree->StartSector = NextStart;
ExtFree->SectorCount = NextSize;
pCurrentDiskRegion->Next = ExtFree;
//
// make the new region current region !!!
//
pCurrentDiskRegion = ExtFree;
NextStart = NextStart + NextSize - 1;
} else {
//
// Make sure that the free space after the extended
// partition is accounted for
//
NextStart = 0;
}
}
//
// There's nothing behind of us. See if there's any
// empty space back there that's unaccounted for.
//
if (!NextStart) {
NextStart = pCurrentDiskRegion->StartSector +
pCurrentDiskRegion->SectorCount;
}
if (PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors > NextStart) {
NextSize = PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors -
NextStart;
} else {
NextSize = 0;
}
//
// For ASR, allow partition size on GPT disks to be >= 1 sector.
// In all other cases, partition size must be >= 1 cylinder.
//
if ((NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) ||
(SpDrEnabled() && SPPT_IS_GPT_DISK(DiskNumber) && (NextSize >= 1))
) {
//
// Yes there is. We need to make a region behind us that's
// marked as unpartitioned.
//
if (FirstContainer) {
//
// there could be free space at the end of the
// extended partition. Mark is separately from
// the free space after the extended partition
//
ULONGLONG ExtEnd = FirstContainer->StartSector +
FirstContainer->SectorCount;
ULONGLONG ExtFreeStart = NextStart;
ULONGLONG ExtFreeSize = (ExtEnd > ExtFreeStart) ?
ExtEnd - ExtFreeStart : 0;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnFillDiskFreeSpaces():EFS:%I64d,EFSize:%I64d,EE:%I64d\n",
ExtFreeStart,
ExtFreeSize,
ExtEnd));
if (ExtFreeSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) {
PDISK_REGION ExtFree = SpMemAlloc(sizeof(DISK_REGION));
if (!ExtFree) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
return STATUS_NO_MEMORY;
}
RtlZeroMemory(ExtFree, sizeof(DISK_REGION));
ExtFree->DiskNumber = DiskNumber;
ExtFree->StartSector = ExtFreeStart;
ExtFree->SectorCount = ExtFreeSize;
pCurrentDiskRegion->Next = ExtFree;
pCurrentDiskRegion = ExtFree;
NextStart = ExtEnd;
NextSize = 0;
if (PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors > NextStart) {
NextSize = PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors -
NextStart;
}
} else {
//
// Get rid of any free space at the end which is lesser than a
// cylinder partition inside the exteneded partition before
// we try to see if there is adequate space at the end of extended
// partition
//
NextStart += ExtFreeSize;
NextSize -= ExtFreeSize;
}
}
//
// For ASR, allow partition size on GPT disks to be >= 1 sector.
// In all other cases, partition size must be >= 1 cylinder.
//
if ((NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) ||
(SpDrEnabled() && SPPT_IS_GPT_DISK(DiskNumber) && (NextSize >= 1))
) {
pTempDiskRegion = SpMemAlloc( sizeof(DISK_REGION) );
if(!pTempDiskRegion) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
return(STATUS_NO_MEMORY);
}
RtlZeroMemory( pTempDiskRegion, sizeof(DISK_REGION) );
pTempDiskRegion->DiskNumber = DiskNumber;
pTempDiskRegion->StartSector = NextStart;
pTempDiskRegion->SectorCount = NextSize;
pCurrentDiskRegion->Next = pTempDiskRegion;
}
}
//
// We just processed the last region. If there was any free space
// behind that partition, we just accounted for it, in which case
// we're done with this disk. If there wasn't any free space behind
// that partition, then we're also done.
//
return( Status );
} else {
//
// There's another partition ahead of us.
// See if there's free space between them.
//
NextStart = pCurrentDiskRegion->StartSector +
pCurrentDiskRegion->SectorCount;
if (pCurrentDiskRegion->Next->StartSector > NextStart) {
NextSize = pCurrentDiskRegion->Next->StartSector - NextStart;
//
// Check to see if its a container partition
//
if (!FirstContainer && SPPT_IS_MBR_DISK(DiskNumber) &&
IsContainerPartition(SPPT_GET_PARTITION_TYPE(pCurrentDiskRegion))) {
FirstContainer = pCurrentDiskRegion;
NextStart = pCurrentDiskRegion->StartSector + 1;
NextSize = pCurrentDiskRegion->Next->StartSector - NextStart;
}
if (FirstContainer) {
ULONGLONG ExtEnd = FirstContainer->StartSector +
FirstContainer->SectorCount;
ULONGLONG FreeEnd = pCurrentDiskRegion->Next->StartSector;
//
// Split the free region into extended free and normal free region
// if needed
//
if (!SPPT_IS_REGION_CONTAINED(FirstContainer, pCurrentDiskRegion->Next) &&
(ExtEnd < FreeEnd)) {
PDISK_REGION ExtFree = NULL;
//
// If the free space doesnt overlap the extended partition
// then do not subtract from extended end
//
if (NextStart < ExtEnd){
NextSize = ExtEnd - NextStart;
}
if (NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) {
ExtFree = SpMemAlloc(sizeof(DISK_REGION));
if (!ExtFree) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
return STATUS_NO_MEMORY;
}
RtlZeroMemory(ExtFree, sizeof(DISK_REGION));
ExtFree->DiskNumber = DiskNumber;
ExtFree->StartSector = NextStart;
ExtFree->SectorCount = NextSize;
//
// insert the region after the current one
//
ExtFree->Next = pCurrentDiskRegion->Next;
pCurrentDiskRegion->Next = ExtFree;
//
// make the new region current
//
pCurrentDiskRegion = ExtFree;
}
//
// Fix the next free region start
//
NextStart += NextSize;
if (FreeEnd > NextStart) {
NextSize = FreeEnd - NextStart;
} else {
NextSize = 0;
}
}
}
} else {
//
// skip container partitions (expect for starting free space
// inside the container partition)
//
NextSize = 0;
if (SPPT_IS_MBR_DISK(DiskNumber) &&
IsContainerPartition(SPPT_GET_PARTITION_TYPE(pCurrentDiskRegion)) &&
(pCurrentDiskRegion->Next->StartSector > pCurrentDiskRegion->StartSector)) {
if (!FirstContainer) {
FirstContainer = pCurrentDiskRegion;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnFillDiskFreeSpaces():%p is the first container\n",
FirstContainer));
}
//
// We add one here because we should be able to differentiate the starting
// free region inside the extended partition from the extended partition
// itself.
//
NextStart = pCurrentDiskRegion->StartSector + 1;
NextSize = pCurrentDiskRegion->Next->StartSector - NextStart + 1;
}
}
//
// For ASR, allow partition size on GPT disks to be >= 1 sector.
// In all other cases, partition size must be >= 1 cylinder.
//
if ((NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) ||
(SpDrEnabled() && SPPT_IS_GPT_DISK(DiskNumber) && (NextSize >= 1))
) {
//
// Yes, there's free space and we need to insert
// a region here to represent it. Allocate a region
// and initialize it as unpartitioned space.
//
pTempDiskRegion = SpMemAlloc( sizeof(DISK_REGION) );
if(!pTempDiskRegion) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
return(STATUS_NO_MEMORY);
}
RtlZeroMemory( pTempDiskRegion, sizeof(DISK_REGION) );
pTempDiskRegion->DiskNumber = DiskNumber;
pTempDiskRegion->StartSector = NextStart;
pTempDiskRegion->SectorCount = NextSize;
pTempDiskRegion->Next = pCurrentDiskRegion->Next;
pCurrentDiskRegion->Next = pTempDiskRegion;
pCurrentDiskRegion = pTempDiskRegion;
}
}
pCurrentDiskRegion = pCurrentDiskRegion->Next;
}
return Status;
}
#ifdef NOT_USED_CURRENTLY
VOID
SpDeleteDiskDriveLetters(
VOID
)
/*++
Routine Description:
This routine will delete all drive letters assigned to disks and CD-ROM drives. The deletion will
occur only if setup was started booting from the CD or boot floppies (in which case drive letter
migration does not take place), and only if the non-removable dissks have no partitioned spaces.
This ensures that on a clean install from the CD or boot floppies, the drive letters assigned to
partitions on removable disks and CD-ROM drives will always be greater than the drive letters assigned
to partitions on non-removable disks (unless the partitions on the removable disks were created before
the ones in the removable disks, during textmode setup).
Arguments:
None.
Return Value:
None.
--*/
{
ULONG DiskNumber;
PDISK_REGION pDiskRegion;
PWCHAR MyTempBuffer = NULL;
unsigned pass;
BOOLEAN PartitionedSpaceFound = FALSE;
if( WinntSetup ) {
//
// If setup started from winnt32.exe then do not delete the drive letters since we want to preserve them
//
return;
}
//
// Setup started booting from a CD.
//
// Find out if the disks contain at least one partition that is not a container.
// Note that we do not take into consideration partitions that are on removable media.
// This is to avoid the situation in which a newly created partition on a non-removable disk ends up with
// a drive letter that is greater than the one assigned to an existing partition on a removable disk.
//
for(DiskNumber = 0; !PartitionedSpaceFound && (DiskNumber<HardDiskCount); DiskNumber++) {
if( PartitionedDisks[DiskNumber].HardDisk->Geometry.MediaType != RemovableMedia) {
//
// This disk isn't removable. Let's look at all the areas and see
// if there's anything that's partitioned.
//
pDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
while( pDiskRegion ) {
if(SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
PartitionedSpaceFound = TRUE;
}
//
// Now get the next region on this disk.
//
pDiskRegion = pDiskRegion->Next;
}
}
}
if( !PartitionedSpaceFound ) {
//
// There are no partitions on this machine. Delete all drive letters
// so that the drive letters for each CD-ROM drive also get deleted.
//
// We'll do this by sending an IOCTL to the MountManager and ask him
// to whack all his knowledge of drive letters.
//
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING UnicodeString;
HANDLE Handle;
INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
Status = ZwOpenFile( &Handle,
(ACCESS_MASK)(FILE_GENERIC_READ | FILE_GENERIC_WRITE),
&Obja,
&IoStatusBlock,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE );
if( NT_SUCCESS( Status ) ) {
MOUNTMGR_MOUNT_POINT MountMgrMountPoint;
MountMgrMountPoint.SymbolicLinkNameOffset = 0;
MountMgrMountPoint.SymbolicLinkNameLength = 0;
MountMgrMountPoint.UniqueIdOffset = 0;
MountMgrMountPoint.UniqueIdLength = 0;
MountMgrMountPoint.DeviceNameOffset = 0;
MountMgrMountPoint.DeviceNameLength = 0;
Status = ZwDeviceIoControlFile( Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_MOUNTMGR_DELETE_POINTS,
&MountMgrMountPoint,
sizeof( MOUNTMGR_MOUNT_POINT ),
TemporaryBuffer,
sizeof( TemporaryBuffer ) );
if( !NT_SUCCESS( Status ) ) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Unable to delete drive letters. "
"ZwDeviceIoControl( IOCTL_MOUNTMGR_DELETE_POINTS ) failed."
"Status = %lx \n", Status));
} else {
//
// If the drive letters got deleted then reset the drive letters assigned to all partitions.
// Note that we only really care about resetting the drive letters on the partitions on the
// removable disks, since, if we got that far, there won't be any partition on the non-removable
// disks
//
for(DiskNumber = 0; DiskNumber<HardDiskCount; DiskNumber++) {
//
// This disk isn't removable. Let's look at all the areas and see
// if there's anything that's partitioned.
//
pDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
while( pDiskRegion ) {
pDiskRegion->DriveLetter = 0;
//
// Now get the next region on this disk.
//
pDiskRegion = pDiskRegion->Next;
}
}
}
ZwClose( Handle );
} else {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Unable to delete drive letters. "
"ZwOpenFile( %ls ) failed. Status = %lx \n",
MOUNTMGR_DEVICE_NAME,
Status));
}
}
}
NTSTATUS
SpAssignDiskDriveLetters(
VOID
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG DiskNumber;
PDISK_REGION pDiskRegion;
PWCHAR MyTempBuffer = NULL;
unsigned pass;
//
// Before initializing the drive letters, delete them if necessary.
// This is to get rid of the letters assigned to CD-ROM drives and removables, when the disks have no
// partitioned space.
//
SpDeleteDiskDriveLetters();
//
// Initialize all drive letters to nothing.
// If it the region is a partitioned space, then assign a drive letter also.
//
for( DiskNumber=0; DiskNumber<HardDiskCount; DiskNumber++ ) {
pDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
while( pDiskRegion ) {
pDiskRegion->DriveLetter = 0;
if(SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
//
// Retrieve nt pathname for this region.
//
MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
if( !MyTempBuffer ) {
//
// No memory...
//
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpPtAssignDriveLetters: SpMemAlloc failed!\n" ));
return(STATUS_NO_MEMORY);
}
SpNtNameFromRegion( pDiskRegion,
MyTempBuffer,
MAX_NTPATH_LENGTH,
PrimaryArcPath );
//
// Assign the drive letter.
//
pDiskRegion->DriveLetter = SpGetDriveLetter( MyTempBuffer, NULL );
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtAssignDriveLetters: Partition = %ls, DriveLetter = %wc: \n",
MyTempBuffer, pDiskRegion->DriveLetter));
SpMemFree( MyTempBuffer );
MyTempBuffer = NULL;
}
//
// Now get the next region on this disk.
//
pDiskRegion = pDiskRegion->Next;
}
}
return( Status );
}
#endif // NOT_USED_CURRENTLY
//
// ============================================================================
// ============================================================================
//
// The following code provides support for disk/partition selection.
//
// ============================================================================
// ============================================================================
//
#define MENU_LEFT_X 3
#define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
#define MENU_INDENT 4
extern ULONG PartitionMnemonics[];
VOID
SpPtnAutoCreatePartitions(
IN PVOID SifHandle,
IN PWSTR SetupSourceDevicePath,
IN PWSTR DirectoryOnSetupSource
)
/*++
Routine Description:
If there are no partitions on any disks, create some.
Arguments:
SifHandle : Handle to txtsetup.sif
SetupSourceDevicePath : Device from which setup was launced
DirectoryOnSetupSource : Directory from where the kernel was loaded on
Setup device
Return Value:
None.
--*/
{
PDISK_REGION p = NULL;
PDISK_REGION Region = NULL;
ULONG Index;
BOOLEAN Found = FALSE;
WCHAR RegionStr[128] = {0};
NTSTATUS FormatStatus;
ULONG MyPartitionSizeMB = 0;
NTSTATUS Status;
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - Checking for any existing partitions.\n" ));
Found = FALSE;
for(Index = 0; (Index < HardDiskCount) && (!Found); Index++) {
Region = SPPT_GET_PRIMARY_DISK_REGION( Index );
while( (Region) && (!Found) ) {
if( Region->PartitionedSpace &&
!SPPT_IS_REGION_RESERVED_PARTITION(Region)) {
//
// He's got something on the disk.
//
Found = TRUE;
}
Region = Region->Next;
}
}
if( !Found ) {
//
// The disks are all empty. We need to go
// create some partitions for the installation.
//
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - No existing partitions were found.\n" ));
if (SpIsArc()) {
//
// If we're on an ARC machine, go create a system
// partition first.
//
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - About to "
"auto-generate a system partition.\n" ));
#if defined(_IA64_)
Status = SpPtnCreateESP(FALSE);
if (!NT_SUCCESS(Status)) {
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - Could not "
"autocreate ESP : %lx\n",
Status));
return;
}
#endif
}
//
// Now create a partition to install the operating system.
//
// To do this, we're going to take the following steps:
// 1. go find some free space on a disk that's big enough.
// 2. create a partitions that's half of this guy's free space, (make the
// partition at least 4Gig).
//
KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - About to "
"auto-generate an installation partition.\n" ));
Found = FALSE;
for(Index = 0; (Index < HardDiskCount) && (!Found); Index++) {
Region = SPPT_GET_PRIMARY_DISK_REGION( Index );
while( (Region) && (!Found) ) {
if( (!Region->PartitionedSpace) &&
(SPPT_REGION_FREESPACE_KB(Region)/1024 >= (SUGGESTED_INSTALL_PARTITION_SIZE_MB)) ) {
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - I found an area big enough for an installation.\n" ));
MyPartitionSizeMB = max( (ULONG)(SPPT_REGION_FREESPACE_KB(Region)/(2*1024)), SUGGESTED_INSTALL_PARTITION_SIZE_MB );
if( SpPtnDoCreate( Region,
&p,
TRUE,
MyPartitionSizeMB,
NULL,
FALSE ) ) {
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - I just created an installation partition.\n" ));
//
// Got it.
//
Found = TRUE;
Region = p;
//
// Now format it.
//
swprintf( RegionStr,
L"\\Harddisk%u\\Partition%u",
Region->DiskNumber,
Region->PartitionNumber );
//
// Format the system region with NTFS file system
//
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - I'm about to go format the installation partition.\n" ));
FormatStatus = SpDoFormat( RegionStr,
Region,
FilesystemNtfs,
TRUE,
TRUE,
FALSE,
SifHandle,
0, // default cluster size
SetupSourceDevicePath,
DirectoryOnSetupSource );
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - Format of an installation partition is complete.\n" ));
} else {
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - I failed to create an installation partition.\n" ));
}
}
Region = Region->Next;
}
}
} else {
// let 'em know
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnAutoCreatePartitions - Existing partitions were found.\n" ));
}
}
NTSTATUS
SpPtnPrepareDisks(
IN PVOID SifHandle,
OUT PDISK_REGION *InstallArea,
OUT PDISK_REGION *SystemPartitionArea,
IN PWSTR SetupSourceDevicePath,
IN PWSTR DirectoryOnSetupSource,
IN BOOLEAN RemoteBootRepartition
)
/*++
Routine Description:
Shows the use the disk menu (with partitions) and locates
the system and boot partition
Arguments:
SifHandle : Handle to txtsetup.sif
InstallArea : Place holder for boot partition
SystemPartitionArea : Place holder for system partition
SetupSourceDevicePath : Device from which setup was launced
DirectoryOnSetupSource : Directory from where the kernel was loaded on
Setup device
RemoteBootRePartition : Whether to repartition the disk for remote boot
Return Value:
Appropriate status code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
WCHAR Buffer[256] = {0};
ULONG DiskNumber;
PVOID Menu;
ULONG MenuTopY;
ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
ULONG ValidKeysCmdCons[2] = { ASCI_ESC, 0 };
ULONG Keypress;
PDISK_REGION pDiskRegion;
PDISK_REGION FirstDiskRegion,DefaultDiskRegion;
BOOLEAN unattended = UnattendedOperation;
BOOLEAN OldUnattendedOperation;
BOOLEAN createdMenu;
ULONG LastUsedDisk = -1;
BOOLEAN Win9xPartition = FALSE;
//
// Do some special partitioning if there's nothing
// on the disk and the user has asked us to do an express
// installation.
//
if( (!CustomSetup) && (UnattendedOperation) && (HardDiskCount != 0)
#if defined(REMOTE_BOOT)
&& (!RemoteBootSetup) && (!RemoteInstallSetup)
#endif
) {
//
// See if we need to auto-generate some partitions for the
// installation.
//
SpPtnAutoCreatePartitions( SifHandle,
SetupSourceDevicePath,
DirectoryOnSetupSource );
}
if (SpIsArc()) {
//
// Select a system partition from among those defined in NV-RAM.
//
*SystemPartitionArea = SpPtnValidSystemPartitionArc(SifHandle,
SetupSourceDevicePath,
DirectoryOnSetupSource,
FALSE);
if (*SystemPartitionArea) {
(*SystemPartitionArea)->IsSystemPartition = TRUE;
}
}
//
// If the user selected any accessibility option and wanted to choose partition, show the partition screen
//
if(AccessibleSetup && !AutoPartitionPicker) {
unattended = FALSE;
}
//
// Save the current unattended mode and put the temp one
//
OldUnattendedOperation = UnattendedOperation;
UnattendedOperation = unattended;
while(1) {
createdMenu = FALSE;
Keypress = 0;
#if defined(REMOTE_BOOT)
if (RemoteBootSetup && !RemoteInstallSetup && HardDiskCount == 0) {
//
// If there are no hard disks, allow diskless install
//
pDiskRegion = NULL;
//
// Run through the rest of the code as if the user had just
// hit enter to select this partition.
//
Keypress = ASCI_CR;
} else
#endif // defined(REMOTE_BOOT)
if (unattended && RemoteBootRepartition) {
ULONG DiskNumber;
ULONG DiskSpaceRequiredKB = 2 * 1024 * 1024; // 2 GB
//
// What's the space we required for installation
//
SpFetchDiskSpaceRequirements(SifHandle,
4 * 1024,
&DiskSpaceRequiredKB,
NULL);
//
// Prepare the disk for remote boot installation. This involves
// converting disk 0 into as big a partition as possible.
//
if (*SystemPartitionArea != NULL) {
DiskNumber = (*SystemPartitionArea)->DiskNumber;
} else {
DiskNumber = SpDetermineDisk0();
}
#ifdef _IA64_
Status = SpPtnRepartitionGPTDisk(DiskNumber,
DiskSpaceRequiredKB,
&pDiskRegion);
#else
Status = SpPtPartitionDiskForRemoteBoot(DiskNumber,
&pDiskRegion);
#endif
if (NT_SUCCESS(Status)) {
SpPtRegionDescription(
&PartitionedDisks[pDiskRegion->DiskNumber],
pDiskRegion,
Buffer,
sizeof(Buffer)
);
//
// Run through the rest of the code as if the user had just
// hit enter to select this partition.
//
Keypress = ASCI_CR;
}
}
if (Keypress == 0) {
//
// Display the text that goes above the menu on the partitioning screen.
//
SpDisplayScreen(ConsoleRunning ? SP_SCRN_PARTITION_CMDCONS:SP_SCRN_PARTITION,
3,CLIENT_TOP+1);
//
// Calculate menu placement. Leave one blank line
// and one line for a frame.
//
MenuTopY = NextMessageTopLine + 2;
//
// Create a menu.
//
Menu = SpMnCreate(
MENU_LEFT_X,
MenuTopY,
MENU_WIDTH,
(VideoVars.ScreenHeight - MenuTopY -
(SplangQueryMinimizeExtraSpacing() ? 1 : 2) - STATUS_HEIGHT)
);
if(!Menu) {
UnattendedOperation = OldUnattendedOperation;
return(STATUS_NO_MEMORY);
}
createdMenu = TRUE;
//
// Build up a menu of partitions and free spaces.
//
FirstDiskRegion = NULL;
for(DiskNumber=0; DiskNumber<HardDiskCount; DiskNumber++) {
if( !SpPtnGenerateDiskMenu(Menu, DiskNumber, &FirstDiskRegion) ) {
SpMnDestroy(Menu);
UnattendedOperation = OldUnattendedOperation;
return(STATUS_NO_MEMORY);
}
}
ASSERT(FirstDiskRegion);
//
// If this is unattended operation, try to use the local source
// region if there is one. If this fails, the user will have to
// intervene manually.
//
if(!AutoPartitionPicker && unattended && LocalSourceRegion && CustomSetup &&
(!LocalSourceRegion->DynamicVolume || LocalSourceRegion->DynamicVolumeSuitableForOS)) {
pDiskRegion = LocalSourceRegion;
Keypress = ASCI_CR;
} else {
pDiskRegion = NULL;
//
// Unless we've been told not to, go look at each partition on each
// disk and see if we can find anything suitable for an OS installation.
//
if( AutoPartitionPicker && !ConsoleRunning
#if defined(REMOTE_BOOT)
&& (!RemoteBootSetup || RemoteInstallSetup)
#endif // defined(REMOTE_BOOT)
) {
PDISK_REGION pCurrentDiskRegion = NULL;
ULONG RequiredKB = 0;
ULONG SectorNo;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: -------------------------------------------------------------\n" ));
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: Looking for an install partition\n\n" ));
for( DiskNumber=0;
((DiskNumber < HardDiskCount) && (!pCurrentDiskRegion));
DiskNumber++ ) {
pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
while( pCurrentDiskRegion ) {
//
// Fetch the amount of free space required on the windows nt drive.
//
SpFetchDiskSpaceRequirements( SifHandle,
pCurrentDiskRegion->BytesPerCluster,
&RequiredKB,
NULL );
if( SpPtDeterminePartitionGood(pCurrentDiskRegion, RequiredKB, TRUE) ) {
//
// Got it. Remember the partition and pretend the user
// hit the <enter> key.
//
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: Selected install partition = "
"(DiskNumber:%d),(DriveLetter:%wc:),(%ws)\n",
DiskNumber,pCurrentDiskRegion->DriveLetter,
pCurrentDiskRegion->VolumeLabel));
pDiskRegion = pCurrentDiskRegion;
Keypress = ASCI_CR;
break;
}
pCurrentDiskRegion = pCurrentDiskRegion->Next;
}
}
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: -------------------------------------------------------------\n" ));
}
if( !pDiskRegion ) {
//
// We didn't find any suitable partitions, which means we'll be putting up a
// menu very quickly. Initialize the partition to highlight in the
// menu.
//
if (LastUsedDisk == -1) {
DefaultDiskRegion = FirstDiskRegion;
} else {
//
// Select the first region on the disk which the user last
// operated on
//
PDISK_REGION ValidRegion = SPPT_GET_PRIMARY_DISK_REGION(LastUsedDisk);
while (ValidRegion && SPPT_IS_REGION_CONTAINER_PARTITION(ValidRegion)) {
ValidRegion = ValidRegion->Next;
}
if (!ValidRegion)
ValidRegion = FirstDiskRegion;
DefaultDiskRegion = ValidRegion;
}
//
// Call the menu callback to initialize the status line.
//
SpPtMenuCallback( (ULONG_PTR)DefaultDiskRegion );
SpMnDisplay( Menu,
(ULONG_PTR)DefaultDiskRegion,
TRUE,
ConsoleRunning ? ValidKeysCmdCons : ValidKeys,
PartitionMnemonics,
SpPtMenuCallback,
SpPtIsNotReservedPartition,
&Keypress,
(PULONG_PTR)(&pDiskRegion) );
}
}
}
LastUsedDisk = pDiskRegion ? pDiskRegion->DiskNumber : -1;
//
// Now act on the user's selection.
//
if(Keypress & KEY_MNEMONIC) {
Keypress &= ~KEY_MNEMONIC;
}
//
// Disallow certain operations on partitions that contain local source
// or are the system partition (in the amd64/x86 floppiless case).
//
switch(Keypress) {
case MnemonicCreatePartition:
case MnemonicMakeSystemPartition:
case MnemonicDeletePartition:
case MnemonicChangeDiskStyle:
if( (pDiskRegion->IsLocalSource) ||
((Keypress == MnemonicDeletePartition) &&
(SpPtnIsDeleteAllowedForRegion(pDiskRegion) == FALSE))
#if defined(_AMD64_) || defined(_X86_)
|| (IsFloppylessBoot &&
pDiskRegion == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))
#endif // defined(_AMD64_) || defined(_X86_)
) {
//
// Inform the user that we can't do this operation on this
// partition.
//
ULONG MyValidKeys[] = { ASCI_CR };
SpDisplayScreen(SP_SCRN_CONFIRM_INABILITY,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0
);
SpInputDrain();
SpWaitValidKey(MyValidKeys,NULL,NULL);
//
// Now change the keypress so we'll fall through the next switch.
//
Keypress = MnemonicUnused;
}
}
switch(Keypress) {
case MnemonicCreatePartition:
SpPtnDoCreate(pDiskRegion, NULL, FALSE, 0, 0, TRUE);
break;
case MnemonicMakeSystemPartition: {
//
// Make sure we don't have any other system partition
//
if (SPPT_IS_REGION_SYSTEMPARTITION(pDiskRegion)) {
ValidArcSystemPartition = TRUE;
}
if (!ValidArcSystemPartition && pDiskRegion->PartitionedSpace && SpIsArc() &&
(pDiskRegion->Filesystem != FilesystemNtfs)) {
if (NT_SUCCESS(SpPtnMakeRegionArcSysPart(pDiskRegion))) {
PDISK_REGION SysPartRegion = NULL;
//
// Ok format the partition if required
//
SysPartRegion = SpPtnValidSystemPartitionArc(SifHandle,
SetupSourceDevicePath,
DirectoryOnSetupSource,
FALSE);
if (SysPartRegion) {
ULONG SysPartDiskNumber = SysPartRegion->DiskNumber;
BOOLEAN Changes = FALSE;
if ((NT_SUCCESS(SpPtnCommitChanges(SysPartDiskNumber,
&Changes))) &&
(NT_SUCCESS(SpPtnInitializeDiskDrive(SysPartDiskNumber)))) {
//
// create MSR partition if needed
//
SpPtnInitializeGPTDisk(SysPartDiskNumber);
}
}
} else {
ValidArcSystemPartition = FALSE;
}
}
break;
}
case MnemonicDeletePartition: {
BOOLEAN SysPartDeleted = FALSE;
BOOLEAN DeletionResult;
SysPartDeleted = SPPT_IS_REGION_SYSTEMPARTITION(pDiskRegion);
DeletionResult = SpPtnDoDelete(pDiskRegion,
SpMnGetText(Menu,(ULONG_PTR)pDiskRegion),
TRUE);
if (DeletionResult && SysPartDeleted && SpIsArc()) {
//
// Find out if there are any other
// valid system partitions
//
SpPtnValidSystemPartitionArc(SifHandle,
SetupSourceDevicePath,
DirectoryOnSetupSource,
FALSE);
}
break;
}
case MnemonicChangeDiskStyle: {
//
// Before changing style make sure, its allowed
// on this platform for the selected disk
//
if (SpPtnIsDiskStyleChangeAllowed(pDiskRegion->DiskNumber)) {
PARTITION_STYLE Style = SPPT_DEFAULT_PARTITION_STYLE;
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_PLEASE_WAIT,
0);
//
// flip the style
//
if (!SPPT_IS_RAW_DISK(pDiskRegion->DiskNumber)) {
Style = SPPT_IS_GPT_DISK(pDiskRegion->DiskNumber) ?
PARTITION_STYLE_MBR : PARTITION_STYLE_GPT;
}
Status = SpPtnInitializeDiskStyle(pDiskRegion->DiskNumber,
Style, NULL);
if (NT_SUCCESS(Status)) {
Status = SpPtnInitializeDiskDrive(pDiskRegion->DiskNumber);
#if defined(_IA64_)
//
// Go and figure out the ESP partitions and
// initialize the MSR partitions on valid GPT
// disks, if none present
//
if (Style == PARTITION_STYLE_GPT) {
ULONG DiskNumber = pDiskRegion->DiskNumber;
if (SpIsArc() && !ValidArcSystemPartition && !SpDrEnabled()) {
//
// Create a system partition
//
Status = SpPtnCreateESP(TRUE);
}
//
// Initialize the GPT disks, to have MSR
// partition
//
Status = SpPtnInitializeGPTDisk(DiskNumber);
}
#endif
}
}
break;
}
case KEY_F3:
SpConfirmExit();
break;
case ASCI_ESC:
if( ConsoleRunning ) {
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_PLEASE_WAIT,
0);
SpPtDoCommitChanges();
}
if (createdMenu) {
SpMnDestroy(Menu);
}
UnattendedOperation = OldUnattendedOperation;
return(STATUS_SUCCESS);
case ASCI_CR:
Win9xPartition = FALSE;
if( SpPtDoPartitionSelection( &pDiskRegion,
((Buffer[0]) ? Buffer : SpMnGetText(Menu,(ULONG_PTR)pDiskRegion)),
SifHandle,
unattended,
SetupSourceDevicePath,
DirectoryOnSetupSource,
RemoteBootRepartition,
&Win9xPartition) ) {
*InstallArea = pDiskRegion;
#if defined(REMOTE_BOOT)
//
// Set the install region differently if this is a remote
// boot -- in that case, the install region is always remote.
//
if (RemoteBootSetup && !RemoteInstallSetup) {
*InstallArea = RemoteBootTargetRegion;
}
#endif // defined(REMOTE_BOOT)
//
// We need to figure out where the system partition is.
//
if (!SpIsArc()) {
*SystemPartitionArea = SpPtnValidSystemPartition();
} else {
PWSTR p;
NTSTATUS TempStatus;
//
// Select a system partition from among those defined in NV-RAM.
// We have to do this again because the user may have deleted the
// system partition previously detected.
//
*SystemPartitionArea = SpPtnValidSystemPartitionArc(SifHandle,
SetupSourceDevicePath,
DirectoryOnSetupSource,
FALSE);
if (!(*SystemPartitionArea)) {
SpPtnPromptForSysPart(SifHandle);
break; // user pressed escape to mark the system partition
}
//
// Make sure we can see the disk from the firmware/BIOS.
// If not then we need to put up a message asking to enable the
// ROM BIOS for the disabled disk containing the system partition
//
p = SpNtToArc( HardDisks[(*SystemPartitionArea)->DiskNumber].DevicePath,
PrimaryArcPath );
if (p == NULL) {
ULONG ValidKeys[] = { KEY_F3, ASCI_ESC, 0 };
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: Enable the ROM BIOS for the Disk containing system partition\n" ));
SpDisplayScreen(SP_ENABLE_ESP_DISK_IN_FIRMWARE, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
0);
//
// Wait for user input
//
SpInputDrain();
switch (SpWaitValidKey(ValidKeys, NULL, NULL)){
case KEY_F3 :
// User has chosen to reboot
SpDone(0,FALSE,FALSE);
case ASCI_ESC:
// User wants to go to the partitioning screen
break;
}
break;
}
//
// Disallow installation onto ESP / MSR
//
if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(*InstallArea) ||
SPPT_IS_REGION_MSFT_RESERVED(*InstallArea)) {
ULONG ValidKeys[] = { ASCI_CR, 0 };
SpDisplayScreen(SP_ESP_INSTALL_PARTITION_SAME, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
//
// Wait for user input
//
SpInputDrain();
SpWaitValidKey(ValidKeys, NULL, NULL);
break;
}
//
// Disallow non GPT ESPs
//
if (SpIsArc() && !SPPT_IS_GPT_DISK((*SystemPartitionArea)->DiskNumber)) {
ULONG ValidKeys[] = { ASCI_CR, 0 };
SpDisplayScreen(SP_NON_GPT_SYSTEM_PARTITION, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
//
// Wait for user input
//
SpInputDrain();
SpWaitValidKey(ValidKeys, NULL, NULL);
break;
}
//
// Disallow installation if MSR does not exist on the disk containing the ESP.
//
TempStatus = SpPtnInitializeGPTDisk((*SystemPartitionArea)->DiskNumber);
if (NT_SUCCESS(TempStatus) &&
(!SpIsMSRPresentOnDisk((*SystemPartitionArea)->DiskNumber))){
ULONG ValidKeys[] = { ASCI_CR, 0 };
SpDisplayScreen(SP_MSR_NOT_PRESENT, 3, HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0);
//
// Wait for user input
//
SpInputDrain();
SpWaitValidKey(ValidKeys, NULL, NULL);
break;
}
}
//
// We're done here.
//
if (createdMenu) {
SpMnDestroy(Menu);
}
#if defined(REMOTE_BOOT)
ASSERT(*SystemPartitionArea ||
(RemoteBootSetup && !RemoteInstallSetup && (HardDiskCount == 0)));
#else
ASSERT(*SystemPartitionArea);
ASSERT((*SystemPartitionArea)->Filesystem >= FilesystemFat);
#endif // defined(REMOTE_BOOT)
#ifdef _X86_
//
// If we are installing on to the same partition as Win9x then
// remove the boot entry for the old operating system
//
if (Win9xPartition) {
DiscardOldSystemLine = TRUE;
}
#endif
UnattendedOperation = OldUnattendedOperation;
return(STATUS_SUCCESS);
} else {
//
// Something happened when we tried to select the
// partition. Make sure that autopartition-picker
// doesn't invoke next time through our while loop.
//
AutoPartitionPicker = FALSE;
}
break;
}
if (createdMenu) {
SpMnDestroy(Menu);
}
unattended = FALSE;
}
}
BOOLEAN
SpPtnGenerateDiskMenu(
IN PVOID Menu,
IN ULONG DiskNumber,
OUT PDISK_REGION *FirstDiskRegion
)
/*++
Routine Description:
Examine the disk for partitioning information and fill in our
menu.
Arguments:
DiskNumber - supplies the disk number of the disk whose partitions
we want to inspect for determining their types.
Return Value:
TRUE Everything went okay.
FALSE Something horrible happened.
--*/
{
WCHAR Buffer[128];
ULONG MessageId;
PDISK_REGION Region = NULL;
WCHAR DriveLetter[3];
WCHAR PartitionName[128];
ULONGLONG FreeSpaceMB;
ULONGLONG AreaSizeMB;
ULONGLONG AreaSizeBytes;
ULONGLONG OneMB = 1024 * 1024;
PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
//
// Get a pointer to the list of regions.
//
Region = PartDisk->PrimaryDiskRegions;
//
// Add the disk name/description.
//
if(!SpMnAddItem(Menu, Disk->Description, MENU_LEFT_X, MENU_WIDTH, FALSE, 0)) {
return(FALSE);
}
//
// Only add a line between the disk name and partitions if we have space on
// the screen. Not fatal if the space can't be added.
//
if(!SplangQueryMinimizeExtraSpacing()) {
SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0);
}
//
// If the disk is off-line, add a message indicating such.
//
if((Disk->Status == DiskOffLine) || !Region) {
MessageId = SP_TEXT_DISK_OFF_LINE;
if( Disk->Characteristics & FILE_REMOVABLE_MEDIA ) {
//
// This is removable media, then just tell the user there's
// no media in the drive.
//
MessageId = SP_TEXT_HARD_DISK_NO_MEDIA;
}
SpFormatMessage( Buffer,
sizeof(Buffer),
MessageId );
return SpMnAddItem(Menu,
Buffer,
MENU_LEFT_X + MENU_INDENT,
MENU_WIDTH - (2 * MENU_INDENT),
FALSE,
0);
}
//
// Now iterate through the areas on the disk and insert that info into the
// menu.
//
while( Region ) {
if (!SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
//
// remember the very first area that we examine.
//
if(*FirstDiskRegion == NULL) {
*FirstDiskRegion = Region;
}
//
// Figure out how big this disk area is and how much
// free space we've got.
//
if (Region->AdjustedFreeSpaceKB != -1) {
FreeSpaceMB = Region->AdjustedFreeSpaceKB / 1024;
} else {
FreeSpaceMB = 0;
}
AreaSizeBytes = Region->SectorCount * Disk->Geometry.BytesPerSector;
AreaSizeMB = AreaSizeBytes / OneMB;
if ((AreaSizeBytes % OneMB) > (OneMB / 2))
AreaSizeMB++;
/*
SpPtDumpDiskRegion(Region);
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Menu Item Details Free:%I64d,%I64d,%I64d\n",
FreeSpaceMB, AreaSizeBytes, AreaSizeMB));
*/
//
// See if this guy's partitioned.
//
if(SPPT_IS_REGION_PARTITIONED(Region)){
//
// Pickup the driveletter
//
if( Region->DriveLetter ) {
DriveLetter[0] = Region->DriveLetter;
} else {
DriveLetter[0] = L'-';
}
DriveLetter[1] = L':';
DriveLetter[2] = 0;
//
// Format the partition name
//
PartitionName[0] = 0;
SpPtnGetPartitionName(Region,
PartitionName,
sizeof(PartitionName)/sizeof(PartitionName[0]));
SpFormatMessage( Buffer,
sizeof( Buffer ),
SP_TEXT_REGION_DESCR_1,
DriveLetter,
SplangPadString(-35, PartitionName),
(ULONG)AreaSizeMB,
(ULONG)FreeSpaceMB );
} else {
//
// It's an unformatted area. Use a different message.
//
SpFormatMessage( Buffer,
sizeof( Buffer ),
SP_TEXT_REGION_DESCR_3,
(ULONG)AreaSizeMB );
}
//
// Add the formatted information into the menu.
//
if(!SpMnAddItem(Menu, Buffer, MENU_LEFT_X + MENU_INDENT,
MENU_WIDTH - (2 * MENU_INDENT), TRUE, (ULONG_PTR)Region)) {
return(FALSE);
}
}
Region = Region->Next;
}
return (SplangQueryMinimizeExtraSpacing() ?
TRUE : SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0));
}
PDISK_REGION
SpPtnValidSystemPartition(
VOID
)
/*++
Routine Description:
Determine whether there is a valid disk partition suitable for use
as the system partition on an amd64/x86 machine (ie, C:).
A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable.
If there is a partition that meets these criteria that is marked active,
then it is the system partition, regardless of whether there are other
partitions that also meet the criteria.
Arguments:
None.
Return Value:
Pointer to a disk region descriptor for a suitable system partition (C:)
for an amd64/x86 machine.
NULL if no such partition currently exists.
--*/
{
PDISK_REGION ActiveRegion , FirstRegion, CurrRegion;
PHARD_DISK Disk = NULL;
ULONG DiskNumber;
DiskNumber = SpDetermineDisk0();
#if defined(REMOTE_BOOT)
//
// If this is a diskless remote boot setup, there is no drive 0.
//
if ( DiskNumber == (ULONG)-1 ) {
return NULL;
}
#endif // defined(REMOTE_BOOT)
if (!PartitionedDisks) {
return NULL;
}
//
// Look for the active partition on drive 0
// and for the first recognized primary partition on drive 0.
//
CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
FirstRegion = NULL;
ActiveRegion = NULL;
while (CurrRegion) {
if (SPPT_IS_REGION_PRIMARY_PARTITION(CurrRegion)) {
UCHAR PartitionType = SPPT_GET_PARTITION_TYPE(CurrRegion);
if(!IsContainerPartition(PartitionType) &&
((IsRecognizedPartition(PartitionType)) ||
(CurrRegion->DynamicVolume && CurrRegion->DynamicVolumeSuitableForOS) ||
((RepairWinnt || WinntSetup || SpDrEnabled() ) && CurrRegion->FtPartition))) {
if (!FirstRegion)
FirstRegion = CurrRegion;
if (!ActiveRegion && SPPT_IS_REGION_ACTIVE_PARTITION(CurrRegion)) {
ActiveRegion = CurrRegion;
break;
}
}
}
CurrRegion = CurrRegion->Next;
}
#ifdef TESTING_SYSTEM_PARTITION
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"%p Active, %p First\n",
ActiveRegion,
FirstRegion));
if (ActiveRegion)
FirstRegion = ActiveRegion;
ActiveRegion = NULL;
#endif
/*
//
// Don't do commit here as the multiple caller's are trying
// to reuse the old region from the existing linked list
// of regions for the disk after this
//
if (!ActiveRegion && FirstRegion) {
BOOLEAN Changes = FALSE;
ULONGLONG StartSector = FirstRegion->StartSector;
SpPtnMakeRegionActive(FirstRegion);
SPPT_MARK_REGION_AS_SYSTEMPARTITION(FirstRegion, TRUE);
if (NT_SUCCESS(SpPtnCommitChanges(DiskNumber, &Changes)) && Changes) {
SPPT_MARK_REGION_AS_ACTIVE(FirstRegion, TRUE);
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnValidSystempartition():succeeded in marking\n"));
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP:SpPtnValidSystempartition():Could not mark the first "
"partition on primary disk as active\n"));
}
}
*/
//
// If there is an active, recognized region, use it as the
// system partition. Otherwise, use the first primary
// we encountered as the system partition. If there is
// no recognized primary, then there is no valid system partition.
//
return (ActiveRegion ? ActiveRegion : FirstRegion);
}
#if 0
ULONG
SpDetermineDisk0(
VOID
)
/*++
Routine Description:
Determine the real disk 0, which may not be the same as \device\harddisk0.
Consider the case where we have 2 scsi adapters and
the NT drivers load in an order such that the one with the BIOS
gets loaded *second* -- meaning that the system partition is actually
on disk 1, not disk 0.
Arguments:
None.
Return Value:
NT disk ordinal suitable for use in generating nt device paths
of the form \device\harddiskx.
--*/
{
ULONG DiskNumber = SpArcDevicePathToDiskNumber(L"multi(0)disk(0)rdisk(0)");
#if defined(REMOTE_BOOT)
//
// If this is a diskless remote boot setup, there is no drive 0.
//
if ( RemoteBootSetup && (DiskNumber == (ULONG)-1) && (HardDiskCount == 0) ) {
return DiskNumber;
}
#endif // defined(REMOTE_BOOT)
return((DiskNumber == (ULONG)(-1)) ? 0 : DiskNumber);
}
#endif
BOOL
SpPtnIsSystemPartitionRecognizable(
VOID
)
/*++
Routine Description:
Determine whether the active partition is suitable for use
as the system partition on an amd64/x86 machine (ie, C:).
A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable.
Arguments:
None.
Return Value:
TRUE - We found a suitable partition
FALSE - We didn't find a suitable partition
--*/
{
ULONG DiskNumber;
PDISK_REGION Region = NULL;
//
// Any partitions on NEC98 are primary and active. So don't need to check on NEC98.
//
if( IsNEC_98 ) {
return TRUE;
}
DiskNumber = SpDetermineDisk0();
//
// Look for the active partition on drive 0
// and for the first recognized primary partition on drive 0.
//
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
if (SPPT_IS_GPT_DISK(DiskNumber)) {
//
// On GPT we just need a valid formatted partition
//
while (Region) {
if (SPPT_IS_REGION_PARTITIONED(Region) &&
SPPT_IS_RECOGNIZED_FILESYSTEM(Region->Filesystem)) {
break;
}
Region = Region->Next;
}
} else {
//
// On MBR we need a valid active formatted partition
//
while (Region) {
if (SPPT_IS_REGION_ACTIVE_PARTITION(Region) &&
SPPT_IS_RECOGNIZED_FILESYSTEM(Region->Filesystem)) {
break;
}
Region = Region->Next;
}
}
return (Region) ? TRUE : FALSE;
}
BOOLEAN
SpPtnValidSystemPartitionArcRegion(
IN PVOID SifHandle,
IN PDISK_REGION Region
)
{
BOOLEAN Valid = FALSE;
if (SPPT_IS_REGION_SYSTEMPARTITION(Region) &&
(Region->FreeSpaceKB != -1) &&
(Region->Filesystem == FilesystemFat)) {
ULONG TotalSizeOfFilesOnOsWinnt = 0;
ULONG RequiredSpaceKB = 0;
//
// On non-x86 platformrs, specially alpha machines that in general
// have small system partitions (~3 MB), we should compute the size
// of the files on \os\winnt (currently, osloader.exe and hall.dll),
// and consider this size as available disk space. We can do this
// since these files will be overwritten by the new ones.
// This fixes the problem that we see on Alpha, when the system
// partition is too full.
//
SpFindSizeOfFilesInOsWinnt( SifHandle,
Region,
&TotalSizeOfFilesOnOsWinnt );
//
// Transform the size into KB
//
TotalSizeOfFilesOnOsWinnt /= 1024;
//
// Determine the amount of free space required on a system partition.
//
SpFetchDiskSpaceRequirements( SifHandle,
Region->BytesPerCluster,
NULL,
&RequiredSpaceKB );
if ((Region->FreeSpaceKB + TotalSizeOfFilesOnOsWinnt) >= RequiredSpaceKB) {
Valid = TRUE;
}
}
return Valid;
}
PDISK_REGION
SpPtnValidSystemPartitionArc(
IN PVOID SifHandle,
IN PWSTR SetupSourceDevicePath,
IN PWSTR DirectoryOnSetupSource,
IN BOOLEAN SysPartNeeded
)
/*++
Routine Description:
Determine whether there is a valid disk partition suitable for use
as the system partition on an ARC machine.
A partition is suitable if it is marked as a system partition in nvram,
has the required free space and is formatted with the FAT filesystem.
Arguments:
SifHandle - supplies handle to loaded setup information file.
Return Value:
Pointer to a disk region descriptor for a suitable system partition.
Does not return if no such partition exists.
--*/
{
ULONG RequiredSpaceKB = 0;
PDISK_REGION Region = NULL;
PPARTITIONED_DISK PartDisk;
ULONG Index;
//
// Go through all the regions. The one that's maked system partition
// or is valid system partition is used for further validation.
//
for(Index = 0; (Index < HardDiskCount) && (!Region); Index++) {
PartDisk = SPPT_GET_PARTITIONED_DISK(Index);
Region = SPPT_GET_PRIMARY_DISK_REGION(Index);
while (Region) {
if (SPPT_IS_REGION_PARTITIONED(Region) &&
SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
break; // found the required region
}
Region = Region->Next;
}
}
//
// If the region is there and not formatted format it as FAT
// file system
//
if (Region && (Region->Filesystem < FilesystemFat)) {
WCHAR DriveLetterString[4] = {0};
DriveLetterString[0] = Region->DriveLetter;
if (!UnattendedOperation) {
ULONG ValidKeys[] = { KEY_F3, 0 };
ULONG Mnemonics[] = { MnemonicFormat, 0 };
ULONG KeyPressed;
ULONG EscKey = SysPartNeeded ? KEY_F3 : ASCI_ESC;
ValidKeys[0] = SysPartNeeded ? KEY_F3 : ASCI_ESC;
SpStartScreen(SysPartNeeded ?
SP_SCRN_C_UNKNOWN_1 : SP_SCRN_C_UNKNOWN,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
DriveLetterString
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F_EQUALS_FORMAT,
SysPartNeeded ?
SP_STAT_F3_EQUALS_EXIT : SP_STAT_ESC_EQUALS_CANCEL,
0);
SpInputDrain();
KeyPressed = SpWaitValidKey(ValidKeys, NULL, Mnemonics);
if (KeyPressed == EscKey) {
Region = NULL;
}
}
if (Region) {
WCHAR RegionStr[128];
NTSTATUS FormatStatus;
swprintf( RegionStr,
L"\\Harddisk%u\\Partition%u",
Region->DiskNumber,
Region->PartitionNumber );
//
// Format the system region with Fat file system
//
FormatStatus = SpDoFormat(RegionStr,
Region,
FilesystemFat,
TRUE,
TRUE,
FALSE,
SifHandle,
0, // default cluster size
SetupSourceDevicePath,
DirectoryOnSetupSource);
if (!NT_SUCCESS(FormatStatus)) {
SpStartScreen(SP_SCRN_SYSPART_FORMAT_ERROR,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
DriveLetterString
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
0);
SpInputDrain();
while(SpInputGetKeypress() != KEY_F3) ;
SpDone(0, FALSE, TRUE);
}
//
// Since we have formatted system partition, make sure
// it has adequate space to hold the startup files
//
if(!SpPtnValidSystemPartitionArcRegion(SifHandle, Region))
Region = NULL;
}
}
if (!Region && SysPartNeeded) {
//
// Make sure we don't look bad.
//
if( RequiredSpaceKB == 0 ) {
SpFetchDiskSpaceRequirements( SifHandle,
(32 * 1024),
NULL,
&RequiredSpaceKB );
}
//
// No valid system partition.
//
SpStartScreen(
SP_SCRN_NO_SYSPARTS,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
RequiredSpaceKB
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
0);
SpInputDrain();
//
// wait for F3
//
while (SpInputGetKeypress() != KEY_F3) ;
SpDone(0, FALSE, TRUE);
}
ValidArcSystemPartition = (Region != NULL);
return Region;
}
NTSTATUS
SpPtnMarkLogicalDrives(
IN ULONG DiskId
)
/*++
Routine Description:
Walks through the region linked list and marks the container
partition and the logical drives. Also marks the free
space inside container partition as contained space
Arguments:
DiskId : Disk to process
Return Value:
STATUS_SUCCESS if successful, otherwise approprite error code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
if (SPPT_IS_MBR_DISK(DiskId)) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
PDISK_REGION FirstContainer = NULL;
PDISK_REGION PrevContainer = NULL;
while (Region) {
if (SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
if (!FirstContainer) {
FirstContainer = Region;
Region->Container = NULL;
} else {
Region->Container = FirstContainer;
}
PrevContainer = Region;
} else {
if (PrevContainer) {
if (SPPT_IS_REGION_CONTAINED(PrevContainer, Region)) {
Region->Container = PrevContainer;
if (SPPT_IS_REGION_PARTITIONED(Region))
SPPT_SET_REGION_EPT(Region, EPTLogicalDrive);
} else {
if (SPPT_IS_REGION_CONTAINED(FirstContainer, Region))
Region->Container = FirstContainer;
}
}
}
Region = Region->Next;
}
}
return Status;
}
ULONG
SpPtnGetOrdinal(
IN PDISK_REGION Region,
IN PartitionOrdinalType OrdinalType
)
/*++
Routine Description:
Gets the Ordinal for the specified region of the specified
type.
Arguments:
Region - Region whose ordinal has to be found
OrdinalType - Type of ordinal for the region
Return Value:
-1 if invalid request, otherwise appropriate ordinal number
for the region.
--*/
{
ULONG Ordinal = -1;
if (Region && Region->PartitionNumber && SPPT_IS_REGION_PARTITIONED(Region)) {
switch (OrdinalType) {
case PartitionOrdinalOnDisk:
if (SPPT_IS_MBR_DISK(Region->DiskNumber) &&
!SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
Ordinal = Region->TablePosition;
} else if (SPPT_IS_GPT_DISK(Region->DiskNumber)) {
Ordinal = Region->TablePosition;
}
//
// Ordinal zero is not valid
//
if (Ordinal == 0) {
Ordinal = -1;
}
break;
default:
Ordinal = Region->PartitionNumber;
break;
}
}
if( Ordinal == -1 ) {
//
// This is really bad. We're about to
// fall over. Atleast try...
//
ASSERT(FALSE);
Ordinal = 1;
KdPrintEx(( DPFLTR_SETUP_ID,
DPFLTR_INFO_LEVEL,
"SETUP: SpPtnGetOrdinal: We didn't get an ordinal! Force it.\n" ));
}
return Ordinal;
}
VOID
SpPtnGetSectorLayoutInformation(
IN PDISK_REGION Region,
OUT PULONGLONG HiddenSectors,
OUT PULONGLONG VolumeSectorCount
)
/*++
Routine Description:
Gets the hidden sector and sector count for the formatted
partitions (volumes)
Arguments:
Region - The region for which the sector layout information
is needed
HiddenSectors - Place holder to return the # of hidden sectors
for the region
VolumeSectorCount- Place holder to return the # of valid sectors
for the volume
Return Value:
None
--*/
{
ULONGLONG Hidden = 0;
if (Region) {
if (ARGUMENT_PRESENT(HiddenSectors)) {
if (Region->PartInfo.PartitionStyle == PARTITION_STYLE_MBR)
Hidden = Region->PartInfo.Mbr.HiddenSectors;
else
Hidden = 0;
*HiddenSectors = Hidden;
}
if (ARGUMENT_PRESENT(VolumeSectorCount)) {
*VolumeSectorCount = Region->SectorCount - Hidden;
}
}
}
NTSTATUS
SpPtnUnlockDevice(
IN PWSTR DeviceName
)
/*++
Routine Description:
Attempts to unlock the media for the given device
name (NT device pathname)
Arguments:
DeviceName : The device for which the media needs to be
unlocked
Return Value:
STATUS_SUCCESS if successful, otherwise appropriate error
code
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (DeviceName) {
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
HANDLE Handle;
PREVENT_MEDIA_REMOVAL PMRemoval;
INIT_OBJA(&ObjectAttributes,
&UnicodeString,
DeviceName);
//
// Open the device
//
Status = ZwCreateFile(
&Handle,
FILE_GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
NULL, // allocation size
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_VALID_FLAGS, // full sharing
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, // no EAs
0
);
if( NT_SUCCESS(Status) ) {
//
// Allow media removal
//
PMRemoval.PreventMediaRemoval = FALSE;
Status = ZwDeviceIoControlFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_STORAGE_MEDIA_REMOVAL,
&PMRemoval,
sizeof(PMRemoval),
NULL,
0
);
ZwClose(Handle);
if( !NT_SUCCESS(Status) ) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"Setup: SpPtnUnlockDevice(%ws) - "
"Failed to tell the floppy to release its media.\n",
DeviceName));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"Setup: SpPtnUnlockDevice(%ws) - Failed to open the device.\n",
DeviceName));
}
}
return Status;
}
VOID
SpPtnAssignOrdinals(
IN ULONG DiskNumber
)
/*++
Routine Description:
Assigns the on disk ordinal for the partitions for
the requested disk. This on disk ordinal is used in
the boot.ini (or NVRAM) ARC names to identify the
boot and system partition devices.
Arguments:
DiskNumber : Disk Index for the disk which needs to
be assigned on disk ordinal for its
partitions
Return Value:
None.
--*/
{
if ((DiskNumber < HardDiskCount)) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
ULONG OnDiskOrdinal = 1;
if (SPPT_IS_MBR_DISK(DiskNumber)) {
//
// assign the ordinals to the primary partitions first
//
while (Region) {
if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
Region->TablePosition = OnDiskOrdinal++;
}
Region = Region->Next;
}
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
//
// assign the ordinals to the logical drives next
//
while (Region) {
if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
Region->TablePosition = OnDiskOrdinal++;
}
Region = Region->Next;
}
} else {
//
// assign ordinals to the valid partition entries
//
while (Region) {
if (SPPT_IS_REGION_PARTITIONED(Region)) {
Region->TablePosition = OnDiskOrdinal++;
}
Region = Region->Next;
}
}
}
}
VOID
SpPtnLocateSystemPartitions(
VOID
)
/*++
Routine Description:
Locates and marks the system partition, by looking into all the
partitioned space on all the disks.
For non ARC machines, locates and marks the system partition
only on the primary disk
Arguments:
None
Return Value:
None
--*/
{
ULONG DiskNumber;
if (SpIsArc()) {
for (DiskNumber = 0; DiskNumber < HardDiskCount; DiskNumber++) {
SpPtnLocateDiskSystemPartitions(DiskNumber);
}
} else {
DiskNumber = SpDetermineDisk0();
if (DiskNumber != -1)
SpPtnLocateDiskSystemPartitions(DiskNumber);
}
}
VOID
SpPtnLocateDiskSystemPartitions(
IN ULONG DiskNumber
)
/*++
Routine Description:
Locates and marks the system partition for the requested
disk (if none exists)
For non ARC machine, only operates on primary disk
Arguments:
DiskNumber : Disk index, for which system partition
needs to be located and marked.
Return Value:
None.
--*/
{
PDISK_REGION Region = NULL;
if(!SpIsArc()) {
//
// Note: On amd64/X86 we currently don't allow system partitions to reside
// on GPT disks
//
if (SPPT_IS_MBR_DISK(DiskNumber) && (DiskNumber == SpDetermineDisk0())) {
//
// On x86 machines, we will mark any primary partitions on drive 0
// as system partition, since such a partition is potentially bootable.
//
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
while (Region && !SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
Region = Region->Next;
}
if (!Region) {
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
while (Region) {
if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
break;
}
Region = Region->Next;
}
}
}
} else {
PSP_BOOT_ENTRY BootEntry;
//
// Don't look for system partitions on MBR disks
// on IA64
//
if (!SPPT_IS_GPT_DISK(DiskNumber)) {
return;
}
//
// On ARC machines, system partitions are specifically enumerated
// in the NVRAM boot environment.
//
Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
while (Region) {
//
// Skip if not a partition or extended partition.
//
if(SPPT_IS_REGION_PARTITIONED(Region)) {
//
// Get the nt pathname for this region.
//
SpNtNameFromRegion(
Region,
TemporaryBuffer,
sizeof(TemporaryBuffer),
PartitionOrdinalOriginal
);
//
// Determine if it is a system partition.
//
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if(!IS_BOOT_ENTRY_DELETED(BootEntry) &&
IS_BOOT_ENTRY_WINDOWS(BootEntry) &&
(BootEntry->LoaderPartitionNtName != 0) &&
!_wcsicmp(BootEntry->LoaderPartitionNtName,TemporaryBuffer)) {
if (!SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
SPPT_SET_REGION_DIRTY(Region, TRUE);
ValidArcSystemPartition = TRUE;
}
break;
}
}
}
Region = Region->Next;
}
}
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP:SpPtnLocateDiskSystemPartitions(%d):%p\n",
DiskNumber,
Region));
if (Region)
SpPtDumpDiskRegion(Region);
}
BOOLEAN
SpPtnIsDiskStyleChangeAllowed(
IN ULONG DiskNumber
)
/*++
Routine Description:
Finds out whether disk style change is allowed for the
given disk.
On AXP machines disk style change is not allowed. On
X-86 machines currently disk style change is disabled for
primary disks.
Arguments:
DiskNumber : Disk, whose style needs to be changed.
Return Value:
TRUE if disk style change is allowed, otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
if (DiskNumber < HardDiskCount) {
#if defined(_AMD64_) || defined(_X86_)
//
// On non ARC x86 machines, the disk should be a clean
// non-removable secondary disk
//
// Don't allow MBR to GPT disk conversion on X86
//
Result = (!SPPT_IS_REMOVABLE_DISK(DiskNumber) &&
SPPT_IS_BLANK_DISK(DiskNumber) &&
!SpIsArc() && SPPT_IS_GPT_DISK(DiskNumber));
#elif defined (_IA64_)
//
// Don't allow conversion from GPT to MBR on IA-64
//
Result = !SPPT_IS_REMOVABLE_DISK(DiskNumber) &&
SPPT_IS_BLANK_DISK(DiskNumber) &&
SPPT_IS_MBR_DISK(DiskNumber);
#endif // defined(_AMD64_) || defined(_X86_)
}
return Result;
}
VOID
SpPtnPromptForSysPart(
IN PVOID SifHandle
)
/*++
Routine Description:
Prompts the user about the absence of system partition
while installating to another valid non-system partition.
Allows the user to quit setup or continue (generally go
back to the partitioning engine)
Arguments:
SifHandle : Handle to txtsetup.sif (to do space calculation)
Return Value:
None
--*/
{
ULONG RequiredSpaceKB = 0;
ULONG KeyPressed = 0;
SpFetchDiskSpaceRequirements( SifHandle,
(32 * 1024),
NULL,
&RequiredSpaceKB );
//
// No valid system partition.
//
SpStartScreen(
SP_SCRN_MARK_SYSPART,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
RequiredSpaceKB
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ESC_EQUALS_CANCEL,
SP_STAT_F3_EQUALS_EXIT,
0);
SpInputDrain();
//
// wait for F3 or ESC key
//
while ((KeyPressed != KEY_F3) && (KeyPressed != ASCI_ESC)) {
KeyPressed = SpInputGetKeypress();
}
if (KeyPressed == KEY_F3) {
SpDone(0, FALSE, TRUE);
}
}
BOOLEAN
SpPtnIsDeleteAllowedForRegion(
IN PDISK_REGION Region
)
/*++
Routine Description:
Given a region this function tries to find out if the region
can be deleted.
Arguments:
Region : Pointer to region which is to be checked for
deletion
Return Value:
TRUE if the given region can be deleted otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
if (Region && SPPT_IS_REGION_PARTITIONED(Region)) {
PDISK_REGION BootRegion = SpRegionFromNtName(NtBootDevicePath,
PartitionOrdinalCurrent);
ULONG DiskNumber = Region->DiskNumber;
if (SPPT_IS_REGION_DYNAMIC_VOLUME(Region)) {
//
// Don't delete the dynamic volume if its on
// the same disk as local source or system partition
//
if (!(LocalSourceRegion &&
(LocalSourceRegion->DiskNumber == DiskNumber)) &&
!(BootRegion &&
(BootRegion->DiskNumber == DiskNumber))) {
Result = TRUE;
}
} else {
Result = ((BootRegion != Region) && (LocalSourceRegion != Region));
}
}
return Result;
}
BOOLEAN
SpPtnIsRawDiskDriveLayout(
IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
)
/*++
Routine Description:
Given a drive layout tests whether the given drive layout
could be for a raw disk
NOTE : If all the partition entries are empty entries or
if there are no partition entries then we assume the disk
to be RAW disk.
Arguments:
DriveLayout : Drive layout information that needs to
be tested
Return Value:
TRUE if the given disk is RAW otherwise FALSE
--*/
{
BOOLEAN Result = TRUE;
if (DriveLayout && DriveLayout->PartitionCount &&
(DriveLayout->PartitionStyle != PARTITION_STYLE_RAW)) {
ULONG Index;
for (Index=0; Index < DriveLayout->PartitionCount; Index++) {
PPARTITION_INFORMATION_EX PartInfo = DriveLayout->PartitionEntry + Index;
//
// Partition is invalid partition if
// - starting offset is 0 and
// - length is 0 and
// - partition number is 0
//
if ((PartInfo->StartingOffset.QuadPart) ||
(PartInfo->PartitionLength.QuadPart) ||
(PartInfo->PartitionNumber)) {
Result = FALSE;
break; // found an valid partition entry
}
}
}
return Result;
}
BOOLEAN
SpPtnIsDynamicDisk(
IN ULONG DiskIndex
)
/*++
Routine Description:
Determines whether the given disk is dynamic i.e. it has
atleast a single dynamic volume
Arguments:
DiskIndex - Zero based index of the disk to test
Return Value:
TRUE, if the disk has a dynamic volume otherwise FALSE
--*/
{
BOOLEAN Result = FALSE;
if ((DiskIndex < HardDiskCount) &&
!SPPT_IS_REMOVABLE_DISK(DiskIndex)) {
PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskIndex);
while (Region && !SPPT_IS_REGION_DYNAMIC_VOLUME(Region)) {
Region = Region->Next;
}
if (Region) {
Result = TRUE;
}
}
return Result;
}
//
// Callback context structure for finding the Guid volume name
// for the specified NT partition name
//
typedef struct _NT_TO_GUID_VOLUME_NAME {
WCHAR NtName[MAX_PATH];
WCHAR GuidVolumeName[MAX_PATH];
} NT_TO_GUID_VOLUME_NAME, *PNT_TO_GUID_VOLUME_NAME;
static
BOOLEAN
SppPtnCompareGuidNameForPartition(
IN PVOID Context,
IN PMOUNTMGR_MOUNT_POINTS MountPoints,
IN PMOUNTMGR_MOUNT_POINT MountPoint
)
/*++
Routine Description:
Callback routine for searching the appropriate GUID
volume name for the specified NT partition.
Arguments:
Context : PNT_TO_GUID_VOLUME_NAME pointer disguised as PVOID
MountPoints : The MountPoints which were received from mountmgr.
NOTE : The only reason this is here is because
somebody created MOUNT_POINT structure abstraction
contained inside MOUNT_POINTS which has some fields
(like SymbolicNameOffset) which are relative to
the MOUNT_POINTS.
MountPoint : The current mountpoint (as part of MountPoints)
Return Value:
TRUE if we found a match and want to terminate the iteration else
FALSE.
--*/
{
BOOLEAN Result = FALSE;
if (Context && MountPoint && MountPoint->SymbolicLinkNameLength) {
WCHAR CanonicalName[MAX_PATH];
PWSTR GuidName = NULL;
UNICODE_STRING String;
PNT_TO_GUID_VOLUME_NAME Map = (PNT_TO_GUID_VOLUME_NAME)Context;
GuidName = SpMemAlloc(MountPoint->SymbolicLinkNameLength + 2);
if (GuidName) {
//
// Copy over the symbolic name and null terminate it
//
RtlCopyMemory(GuidName,
((PCHAR)MountPoints) + MountPoint->SymbolicLinkNameOffset,
MountPoint->SymbolicLinkNameLength);
GuidName[MountPoint->SymbolicLinkNameLength/sizeof(WCHAR)] = UNICODE_NULL;
RtlInitUnicodeString(&String, GuidName);
//
// We are only bothered about volume names &
// resolve the actual object name
//
if (MOUNTMGR_IS_VOLUME_NAME(&String) &&
NT_SUCCESS(SpQueryCanonicalName(GuidName,
-1,
CanonicalName,
sizeof(CanonicalName)))) {
//
// Do the names compare correctly
//
Result = (_wcsicmp(CanonicalName, Map->NtName) == 0);
if (Result) {
//
// Copy the name to the result
//
RtlZeroMemory(Map->GuidVolumeName,
sizeof(Map->GuidVolumeName));
wcsncpy(Map->GuidVolumeName,
GuidName,
sizeof(Map->GuidVolumeName)/sizeof(WCHAR) - 1);
Map->GuidVolumeName[sizeof(Map->GuidVolumeName)/sizeof(WCHAR) - 1] = UNICODE_NULL;
}
}
SpMemFree(GuidName);
}
}
return Result;
}
NTSTATUS
SpPtnGetGuidNameForPartition(
IN PWSTR NtPartitionName,
IN OUT PWSTR VolumeName
)
/*++
Routine Description:
Gets the GUID volume name (in \\??\Volume{a-b-c-d} format) for
the given NT partition name (in \Device\harddiskX\PartitionY format).
Arguments:
NtPartitionName : NT partition name
VolumeName : Place holder buffer for receiving the GUID volume name.
Should be atlease MAX_PATH in length.
Return Value:
Approriate NTSTATUS code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (NtPartitionName && VolumeName) {
NT_TO_GUID_VOLUME_NAME Context = {0};
//
// Resolve the NT name to actual object name
//
Status = SpQueryCanonicalName(NtPartitionName,
-1,
Context.NtName,
sizeof(Context.NtName));
if (NT_SUCCESS(Status)) {
//
// Iterate through mountpoints and try to
// get the GUID volume name for the NT name
//
Status = SpIterateMountMgrMountPoints(&Context,
SppPtnCompareGuidNameForPartition);
if (NT_SUCCESS(Status)) {
if (Context.GuidVolumeName[0]) {
//
// Copy over the result
//
wcscpy(VolumeName, Context.GuidVolumeName);
} else {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
}
}
return Status;
}