mirror of https://github.com/lianthony/NT4.0
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.
4508 lines
125 KiB
4508 lines
125 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sppartit.c
|
|
|
|
Abstract:
|
|
|
|
Partitioning module in text setup.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 7-September-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
#include <bootmbr.h>
|
|
|
|
|
|
PPARTITIONED_DISK PartitionedDisks;
|
|
|
|
//
|
|
// Disk region containing the local source directory
|
|
// in the winnt.exe setup case.
|
|
//
|
|
// If WinntSetup is TRUE, then this should be non-null.
|
|
// If it is not non-null, then we couldn't locate the local source.
|
|
//
|
|
//
|
|
PDISK_REGION LocalSourceRegion;
|
|
|
|
//
|
|
// Flag indicating whether we detected any HPFS volumes.
|
|
// Used during upgrades, so we can warn the user that he won't
|
|
// be able to see or convert the drives from >= nt4.00.
|
|
//
|
|
BOOLEAN AnyHpfsDrives;
|
|
|
|
VOID
|
|
SpPtReadPartitionTables(
|
|
IN PPARTITIONED_DISK pDisk
|
|
);
|
|
|
|
VOID
|
|
SpPtInitializePartitionStructures(
|
|
IN ULONG DiskNumber
|
|
);
|
|
|
|
VOID
|
|
SpPtDeterminePartitionTypes(
|
|
IN ULONG DiskNumber
|
|
);
|
|
|
|
VOID
|
|
SpPtDetermineVolumeFreeSpace(
|
|
IN ULONG DiskNumber
|
|
);
|
|
|
|
VOID
|
|
SpPtLocateSystemPartitions(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
SpMasterBootCode(
|
|
IN ULONG DiskNumber,
|
|
IN HANDLE Partition0Handle,
|
|
OUT PULONG NewNTFTSignature
|
|
);
|
|
|
|
VOID
|
|
SpPtGuessDriveLetters(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
SpPtInitialize(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG disk;
|
|
PHARD_DISK harddisk;
|
|
PPARTITIONED_DISK partdisk;
|
|
ULONG Disk0Ordinal = 0;
|
|
|
|
ASSERT(HardDisksDetermined);
|
|
|
|
//
|
|
// If there are no hard disks, bail now.
|
|
//
|
|
if(!HardDiskCount) {
|
|
SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,3,HEADER_HEIGHT+1);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
|
|
SpkbdDrain();
|
|
while(SpkbdGetKeypress() != KEY_F3) ;
|
|
SpDone(FALSE,TRUE);
|
|
}
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
|
|
#ifdef _X86_
|
|
Disk0Ordinal = SpDetermineDisk0();
|
|
#endif
|
|
|
|
//
|
|
// 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));
|
|
|
|
//
|
|
// For each hard disk attached to the system, read its partition table.
|
|
//
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
harddisk = &HardDisks[disk];
|
|
|
|
SpDisplayStatusText(
|
|
SP_STAT_EXAMINING_DISK_N,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
harddisk->Description
|
|
);
|
|
|
|
partdisk = &PartitionedDisks[disk];
|
|
|
|
partdisk->HardDisk = harddisk;
|
|
|
|
//
|
|
// Read the partition tables.
|
|
//
|
|
SpPtReadPartitionTables(partdisk);
|
|
|
|
//
|
|
// Initialize structures that are based on the partition tables.
|
|
//
|
|
SpPtInitializePartitionStructures(disk);
|
|
|
|
//
|
|
// Determine the type name for each partition on this disk.
|
|
//
|
|
SpPtDeterminePartitionTypes(disk);
|
|
}
|
|
|
|
//
|
|
// Guess drive letters.
|
|
//
|
|
SpPtGuessDriveLetters();
|
|
|
|
//
|
|
// DoubleSpace initialization.
|
|
//
|
|
|
|
//
|
|
// Load dblspace.ini file
|
|
//
|
|
if( SpLoadDblspaceIni() ) {
|
|
SpDisplayStatusText(
|
|
SP_STAT_EXAMINING_DISK_N,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
HardDisks[Disk0Ordinal].Description
|
|
);
|
|
|
|
//
|
|
// Build lists of compressed drives and add them to the DISK_REGION
|
|
// structures
|
|
//
|
|
SpInitializeCompressedDrives();
|
|
}
|
|
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
SpDisplayStatusText(
|
|
SP_STAT_EXAMINING_DISK_N,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
HardDisks[disk].Description
|
|
);
|
|
|
|
//
|
|
// Determine the amount of free space on recognized volumes.
|
|
//
|
|
SpPtDetermineVolumeFreeSpace(disk);
|
|
}
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// If the mbr on disk 0 was not valid, inform the user that
|
|
// continuing will mean the loss of whatever was on the disk.
|
|
//
|
|
// We won't actually write it out here. We know that in order to
|
|
// continue, the user will HAVE to create a C: partition on this drive
|
|
// so we'll end up writing the master boot code when that change is comitted.
|
|
//
|
|
if(!PartitionedDisks[Disk0Ordinal].MbrWasValid) {
|
|
|
|
ULONG ValidKeys[2] = { KEY_F3, 0 };
|
|
ULONG Mnemonics[2] = { MnemonicContinueSetup,0 };
|
|
|
|
while(1) {
|
|
|
|
SpDisplayScreen(SP_SCRN_INVALID_MBR_0,3,HEADER_HEIGHT+1);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_C_EQUALS_CONTINUE_SETUP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
default:
|
|
//
|
|
// must be c=continue
|
|
//
|
|
goto x1;
|
|
}
|
|
}
|
|
}
|
|
|
|
x1:
|
|
#endif
|
|
|
|
//
|
|
// Figure out which partitions are system partitions.
|
|
//
|
|
SpPtLocateSystemPartitions();
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtDeterminePartitionTypes(
|
|
IN ULONG DiskNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the partition types of each partition currently on a disk.
|
|
|
|
The partition type is determined by the system id byte in the partition
|
|
table entry. If the partition type is one we recognize as a Windows NT
|
|
compatible filesystem (types 1,4,6,7) then we dig a little deeper and
|
|
actually determine the filesystem on the volume and use the result as
|
|
the type name.
|
|
|
|
Unused spaces are not given type names.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - supplies the disk number of the disk whose partitions
|
|
we want to inspect for determining their types.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
PDISK_REGION pRegion;
|
|
ULONG NameId;
|
|
UCHAR SysId;
|
|
FilesystemType FsType;
|
|
unsigned pass;
|
|
static BOOLEAN WarnedHpfs = FALSE;
|
|
ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
|
|
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
|
|
for(pass=0; pass<2; pass++) {
|
|
|
|
pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
|
|
for( ; pRegion; pRegion=pRegion->Next) {
|
|
|
|
pRegion->TypeName[0] = 0;
|
|
pRegion->Filesystem = FilesystemUnknown;
|
|
|
|
//
|
|
// If this is a free space, skip it.
|
|
//
|
|
if(!pRegion->PartitionedSpace) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Fetch the system id.
|
|
//
|
|
SysId = pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId;
|
|
|
|
//
|
|
// If this is the extended partition, skip it.
|
|
//
|
|
if(IsContainerPartition(SysId)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If this is a 'recognized' partition type, then determine
|
|
// the filesystem on it. Otherwise use a precanned name.
|
|
//
|
|
if(PartitionNameIds[SysId] == (UCHAR)(-1)) {
|
|
|
|
FsType = SpIdentifyFileSystem(
|
|
HardDisks[DiskNumber].DevicePath,
|
|
HardDisks[DiskNumber].Geometry.BytesPerSector,
|
|
SpPtGetOrdinal(pRegion,PartitionOrdinalOnDisk)
|
|
);
|
|
|
|
//
|
|
// Hpfs is no longer recognized but we do detect it
|
|
// so we can prompt the user, etc. If we see any HPFS
|
|
// here, tell the user he won't see them under NT.
|
|
//
|
|
if(FsType == FilesystemHpfs) {
|
|
if(!UnattendedOperation && !WarnedHpfs) {
|
|
|
|
while(1) {
|
|
SpDisplayScreen(SP_SCRN_HPFS,3,HEADER_HEIGHT+1);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
if(SpWaitValidKey(ValidKeys,NULL,NULL) == KEY_F3) {
|
|
SpConfirmExit();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
|
|
SpDisplayStatusText(
|
|
SP_STAT_EXAMINING_DISK_N,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
pDisk->HardDisk->Description
|
|
);
|
|
|
|
WarnedHpfs = TRUE;
|
|
}
|
|
FsType = FilesystemUnknown;
|
|
AnyHpfsDrives = TRUE;
|
|
}
|
|
|
|
NameId = SP_TEXT_FS_NAME_BASE + FsType;
|
|
|
|
pRegion->Filesystem = FsType;
|
|
|
|
} else {
|
|
|
|
NameId = SP_TEXT_PARTITION_NAME_BASE + (ULONG)PartitionNameIds[SysId];
|
|
}
|
|
|
|
//
|
|
// Get the final type name from the resources.
|
|
//
|
|
SpFormatMessage(
|
|
pRegion->TypeName,
|
|
sizeof(pRegion->TypeName),
|
|
NameId
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtDetermineRegionSpace(
|
|
IN PDISK_REGION pRegion
|
|
)
|
|
{
|
|
HANDLE Handle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING UnicodeString;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_FS_SIZE_INFORMATION SizeInfo;
|
|
ULONG r;
|
|
NTSTATUS Status;
|
|
WCHAR Buffer[512];
|
|
struct LABEL_BUFFER {
|
|
FILE_FS_VOLUME_INFORMATION VolumeInfo;
|
|
WCHAR Label[256];
|
|
} LabelBuffer;
|
|
PFILE_FS_VOLUME_INFORMATION LabelInfo;
|
|
#ifdef _X86_
|
|
static BOOLEAN LookForUndelete = TRUE;
|
|
PWSTR UndeleteFiles[1] = { L"SENTRY" };
|
|
#endif
|
|
PWSTR LocalSourceFiles[1] = { LocalSourceDirectory };
|
|
ULONG ExtraSpace;
|
|
|
|
//
|
|
// Assume unknown.
|
|
//
|
|
pRegion->FreeSpaceKB = (ULONG)(-1);
|
|
pRegion->AdjustedFreeSpaceKB = (ULONG)(-1);
|
|
|
|
//
|
|
// If region is free space of an unknown type, skip it.
|
|
//
|
|
if(pRegion->Filesystem >= FilesystemFirstKnown) {
|
|
|
|
//
|
|
// Form the name of the root directory.
|
|
//
|
|
SpNtNameFromRegion(pRegion,Buffer,sizeof(Buffer),PartitionOrdinalCurrent);
|
|
SpConcatenatePaths(Buffer,L"");
|
|
|
|
//
|
|
// Delete \pagefile.sys if it's there. This makes disk free space
|
|
// calculations a little easier.
|
|
//
|
|
SpDeleteFile(Buffer,L"pagefile.sys",NULL);
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Check to see if Undelete (dos 6) delete sentry or delete tracking
|
|
// methods are in use. If so, give a warning because the free space
|
|
// value we will display for this drive will be off.
|
|
//
|
|
if(LookForUndelete
|
|
&& (pRegion->Filesystem == FilesystemFat)
|
|
&& SpNFilesExist(Buffer,UndeleteFiles,ELEMENT_COUNT(UndeleteFiles),TRUE)) {
|
|
|
|
SpDisplayScreen(SP_SCRN_FOUND_UNDELETE,3,HEADER_HEIGHT+1);
|
|
SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
|
|
SpkbdDrain();
|
|
while(SpkbdGetKeypress() != ASCI_CR) ;
|
|
LookForUndelete = FALSE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If this is a winnt setup, then look for the local source
|
|
// on this drive if we haven't found it already.
|
|
//
|
|
if(WinntSetup && !LocalSourceRegion
|
|
&& SpNFilesExist(Buffer,LocalSourceFiles,ELEMENT_COUNT(LocalSourceFiles),TRUE)) {
|
|
|
|
PWSTR SifName;
|
|
PVOID SifHandle;
|
|
ULONG ErrorLine;
|
|
NTSTATUS Status;
|
|
PWSTR p;
|
|
|
|
LocalSourceRegion = pRegion;
|
|
pRegion->IsLocalSource = TRUE;
|
|
|
|
ExtraSpace = 0;
|
|
|
|
//
|
|
// Open the small ini file that text setup put there to tell us
|
|
// how much space is taken up by the local source.
|
|
//
|
|
wcscpy((PWSTR)TemporaryBuffer,Buffer);
|
|
SpConcatenatePaths((PWSTR)TemporaryBuffer,LocalSourceDirectory);
|
|
SpConcatenatePaths((PWSTR)TemporaryBuffer,L"size.sif");
|
|
|
|
SifName = SpDupStringW((PWSTR)TemporaryBuffer);
|
|
|
|
Status = SpLoadSetupTextFile(SifName,NULL,0,&SifHandle,&ErrorLine);
|
|
if(NT_SUCCESS(Status)) {
|
|
p = SpGetSectionKeyIndex(SifHandle,L"Data",L"Size",0);
|
|
if(p) {
|
|
ExtraSpace = (ULONG)SpStringToLong(p,NULL,10);
|
|
}
|
|
SpFreeTextFile(SifHandle);
|
|
}
|
|
|
|
SpMemFree(SifName);
|
|
|
|
KdPrint(("SETUP: %ws is the local source (occupying %lx bytes)\n",Buffer,ExtraSpace));
|
|
}
|
|
|
|
//
|
|
// Open the root directory on the partition's filesystem.
|
|
//
|
|
INIT_OBJA(&Obja,&UnicodeString,Buffer);
|
|
Status = ZwCreateFile(
|
|
&Handle,
|
|
FILE_GENERIC_READ,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: Unable to open %ws (%lx)\n",Buffer,Status));
|
|
//pRegion->Filesystem = FilesystemUnknown;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Fetch volume size info.
|
|
//
|
|
Status = ZwQueryVolumeInformationFile(
|
|
Handle,
|
|
&IoStatusBlock,
|
|
&SizeInfo,
|
|
sizeof(SizeInfo),
|
|
FileFsSizeInformation
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
LARGE_INTEGER FreeBytes;
|
|
LARGE_INTEGER AdjustedFreeBytes;
|
|
|
|
//
|
|
// Calculate the amount of free space on the drive.
|
|
// Use the Rtl multiply routine because there is a compiler
|
|
// problem/chip errata on MIPS with 64-bit arithmetic
|
|
// (tedm 2/28/96).
|
|
//
|
|
FreeBytes = RtlExtendedIntegerMultiply(
|
|
SizeInfo.AvailableAllocationUnits,
|
|
SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector
|
|
);
|
|
|
|
AdjustedFreeBytes = FreeBytes;
|
|
if(pRegion->IsLocalSource) {
|
|
AdjustedFreeBytes.QuadPart += ExtraSpace;
|
|
}
|
|
|
|
//
|
|
// convert this to a number of KB.
|
|
//
|
|
pRegion->FreeSpaceKB = RtlExtendedLargeIntegerDivide(FreeBytes,1024,&r).LowPart;
|
|
if(r >= 512) {
|
|
pRegion->FreeSpaceKB++;
|
|
}
|
|
pRegion->AdjustedFreeSpaceKB = RtlExtendedLargeIntegerDivide(AdjustedFreeBytes,1024,&r).LowPart;
|
|
if(r >= 512) {
|
|
pRegion->AdjustedFreeSpaceKB++;
|
|
}
|
|
|
|
|
|
if( pRegion->Filesystem == FilesystemDoubleSpace ) {
|
|
//
|
|
// If this the regison is a double space drive, then initialize
|
|
// sector count correctly, so that the drive size can be calculated
|
|
// correctly later on.
|
|
//
|
|
pRegion->SectorCount = (ULONG)( SizeInfo.TotalAllocationUnits.QuadPart
|
|
* SizeInfo.SectorsPerAllocationUnit
|
|
);
|
|
}
|
|
|
|
} else {
|
|
KdPrint(("SETUP: ZwQueryVolumeInformationFile for freespace failed (%lx)\n",Status));
|
|
}
|
|
|
|
//
|
|
// Fetch volume label info.
|
|
//
|
|
Status = ZwQueryVolumeInformationFile(
|
|
Handle,
|
|
&IoStatusBlock,
|
|
&LabelBuffer,
|
|
sizeof(LabelBuffer),
|
|
FileFsVolumeInformation
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
ULONG SaveCharCount;
|
|
|
|
LabelInfo = &LabelBuffer.VolumeInfo;
|
|
|
|
//
|
|
// We'll only save away the first <n> characters of
|
|
// the volume label.
|
|
//
|
|
SaveCharCount = min(
|
|
LabelInfo->VolumeLabelLength + sizeof(WCHAR),
|
|
sizeof(pRegion->VolumeLabel)
|
|
)
|
|
/ sizeof(WCHAR);
|
|
|
|
if(SaveCharCount) {
|
|
SaveCharCount--; // allow for terminating NUL.
|
|
}
|
|
|
|
wcsncpy(pRegion->VolumeLabel,LabelInfo->VolumeLabel,SaveCharCount);
|
|
pRegion->VolumeLabel[SaveCharCount] = 0;
|
|
|
|
} else {
|
|
KdPrint(("SETUP: ZwQueryVolumeInformationFile for label failed (%lx)\n",Status));
|
|
}
|
|
|
|
ZwClose(Handle);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SpPtDetermineVolumeFreeSpace(
|
|
IN ULONG DiskNumber
|
|
)
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
PDISK_REGION pRegion;
|
|
unsigned pass;
|
|
#ifdef FULL_DOUBLE_SPACE_SUPPORT
|
|
PDISK_REGION CompressedDrive;
|
|
#endif // FULL_DOUBLE_SPACE_SUPPORT
|
|
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
|
|
for(pass=0; pass<2; pass++) {
|
|
|
|
pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
|
|
for( ; pRegion; pRegion=pRegion->Next) {
|
|
|
|
SpPtDetermineRegionSpace( pRegion );
|
|
#ifdef FULL_DOUBLE_SPACE_SUPPORT
|
|
if( ( pRegion->Filesystem == FilesystemFat ) &&
|
|
( pRegion->NextCompressed != NULL ) ) {
|
|
//
|
|
// If the region is a FAT partition that contains compressed
|
|
// volumes, then determine the available space on each
|
|
// compressed volume
|
|
//
|
|
for( CompressedDrive = pRegion->NextCompressed;
|
|
CompressedDrive;
|
|
CompressedDrive = CompressedDrive->NextCompressed ) {
|
|
SpPtDetermineRegionSpace( CompressedDrive );
|
|
}
|
|
}
|
|
#endif // FULL_DOUBLE_SPACE_SUPPORT
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtLocateSystemPartitions(
|
|
VOID
|
|
)
|
|
{
|
|
#ifdef _X86_
|
|
PDISK_REGION pRegion;
|
|
ULONG Disk0Ordinal = SpDetermineDisk0();
|
|
|
|
//
|
|
// On x86 machines, we will mark any primary partitions on drive 0
|
|
// as system partition, since such a partition is potentially bootable.
|
|
//
|
|
for(pRegion=PartitionedDisks[Disk0Ordinal].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
|
|
//
|
|
// Skip if free space or extended partition.
|
|
//
|
|
if(pRegion->PartitionedSpace
|
|
&& !IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId))
|
|
{
|
|
//
|
|
// It's a primary partition -- declare it a system partition.
|
|
//
|
|
pRegion->IsSystemPartition = TRUE;
|
|
}
|
|
}
|
|
|
|
#else
|
|
PDISK_REGION pRegion;
|
|
PPARTITIONED_DISK pDisk;
|
|
unsigned pass;
|
|
PUCHAR pch;
|
|
PWSTR p,*Components;
|
|
ULONG NumComponents,i,disk;
|
|
|
|
//
|
|
// On ARC machines, system partitions are specifically enumerated
|
|
// in the NVRAM boot environment.
|
|
//
|
|
|
|
//
|
|
// Get the systempartition environment variable.
|
|
//
|
|
pch = SppGetArcEnvVar(SYSTEMPARTITION);
|
|
SpGetEnvVarWComponents(pch,&Components,&NumComponents);
|
|
SpMemFree(pch);
|
|
|
|
//
|
|
// Convert each of the components into NT pathnames.
|
|
//
|
|
for(i=0; i<NumComponents; i++) {
|
|
|
|
p = SpArcToNt(Components[i]);
|
|
SpMemFree(Components[i]);
|
|
Components[i] = p ? p : SpDupStringW(L"");
|
|
}
|
|
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
pDisk = &PartitionedDisks[disk];
|
|
|
|
for(pass=0; pass<2; pass++) {
|
|
|
|
pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
|
|
for( ; pRegion; pRegion=pRegion->Next) {
|
|
|
|
//
|
|
// Skip if not a partition or extended partition.
|
|
//
|
|
if(pRegion->PartitionedSpace
|
|
&& !IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId))
|
|
{
|
|
|
|
//
|
|
// Get the nt pathname for this region.
|
|
//
|
|
SpNtNameFromRegion(
|
|
pRegion,
|
|
(PWSTR)TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalOriginal
|
|
);
|
|
|
|
//
|
|
// Determine if it is a system partition.
|
|
//
|
|
for(i=0; i<NumComponents; i++) {
|
|
if(!_wcsicmp(Components[i],(PWSTR)TemporaryBuffer)) {
|
|
pRegion->IsSystemPartition = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SpFreeEnvVarComponents(Components);
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtReadPartitionTables(
|
|
IN PPARTITIONED_DISK pDisk
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read partition tables from a given disk.
|
|
|
|
Arguments:
|
|
|
|
pDisk - supplies pointer to disk descriptor to be filled in.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
PUCHAR Buffer;
|
|
PUCHAR UnalignedBuffer;
|
|
PON_DISK_MBR pBr;
|
|
BOOLEAN InMbr;
|
|
ULONG ExtendedStart;
|
|
ULONG NextSector;
|
|
PMBR_INFO pEbr,pLastEbr;
|
|
BOOLEAN FoundLink;
|
|
ULONG i,x;
|
|
BOOLEAN Ignore;
|
|
ULONG bps;
|
|
ULONG SectorsInBootrec;
|
|
|
|
//
|
|
// If this disk is off-line, nothing to do.
|
|
//
|
|
if(pDisk->HardDisk->Status != DiskOnLine) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Open partition 0 of this disk.
|
|
//
|
|
Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,FALSE);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
pDisk->HardDisk->Status = DiskOffLine;
|
|
return;
|
|
}
|
|
|
|
bps = pDisk->HardDisk->Geometry.BytesPerSector;
|
|
SectorsInBootrec = (512/bps) ? (512/bps) : 1;
|
|
|
|
//
|
|
// Allocate and align a buffer for sector i/o.
|
|
//
|
|
ASSERT(sizeof(ON_DISK_MBR)==512);
|
|
UnalignedBuffer = SpMemAlloc(2 * SectorsInBootrec * bps);
|
|
Buffer = ALIGN(UnalignedBuffer,bps);
|
|
|
|
//
|
|
// Read the MBR (sector 0).
|
|
//
|
|
NextSector = 0;
|
|
#ifdef _X86_
|
|
readmbr:
|
|
#endif
|
|
Status = SpReadWriteDiskSectors(Handle,NextSector,SectorsInBootrec,bps,Buffer,FALSE);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: Unable to read mbr for disk %ws (%lx)\n",pDisk->HardDisk->DevicePath,Status));
|
|
pDisk->HardDisk->Status = DiskOffLine;
|
|
ZwClose(Handle);
|
|
SpMemFree(UnalignedBuffer);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Move the data we just read into the partitioned disk descriptor.
|
|
//
|
|
RtlMoveMemory(&pDisk->MbrInfo.OnDiskMbr,Buffer,sizeof(ON_DISK_MBR));
|
|
|
|
//
|
|
// If this MBR is not valid, initialize it. Otherwise, fetch all logical drives
|
|
// (EBR) info as well.
|
|
//
|
|
if(U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) == MBR_SIGNATURE) {
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// EZDrive support: if the first entry in the partition table is
|
|
// type 0x55, then the actual partition table is on sector 1.
|
|
//
|
|
// Only for x86 because on non-x86, the firmware can't see EZDrive
|
|
// partitions, so we don;t want to install on them!
|
|
//
|
|
if(!NextSector && (pDisk->MbrInfo.OnDiskMbr.PartitionTable[0].SystemId == 0x55)) {
|
|
NextSector = 1;
|
|
pDisk->HardDisk->EZDrive = TRUE;
|
|
goto readmbr;
|
|
}
|
|
#endif
|
|
|
|
pDisk->MbrWasValid = TRUE;
|
|
|
|
pBr = &pDisk->MbrInfo.OnDiskMbr;
|
|
InMbr = TRUE;
|
|
ExtendedStart = 0;
|
|
pLastEbr = NULL;
|
|
|
|
do {
|
|
|
|
//
|
|
// Look at all the entries in the current boot record to see if there
|
|
// is a link entry.
|
|
//
|
|
FoundLink = FALSE;
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
if(IsContainerPartition(pBr->PartitionTable[i].SystemId)) {
|
|
|
|
FoundLink = TRUE;
|
|
NextSector = ExtendedStart + U_ULONG(pBr->PartitionTable[i].RelativeSectors);
|
|
|
|
if(NextSector == 0) {
|
|
//
|
|
// Then we've got ourselves one seriously screwed up boot record. We'll
|
|
// just return, and present this mess as free space.
|
|
//
|
|
// BUGBUG we should warn the user that we are going to ignore
|
|
// partitions past this point because the structures are damaged.
|
|
//
|
|
|
|
KdPrint(("SETUP: Bad partition table for %ws\n",pDisk->HardDisk->DevicePath));
|
|
ZwClose(Handle);
|
|
SpMemFree(UnalignedBuffer);
|
|
return;
|
|
}
|
|
|
|
pEbr = SpMemAlloc(sizeof(MBR_INFO));
|
|
ASSERT(pEbr);
|
|
RtlZeroMemory(pEbr,sizeof(MBR_INFO));
|
|
|
|
//
|
|
// Sector number on the disk where this boot sector is.
|
|
//
|
|
pEbr->OnDiskSector = NextSector;
|
|
|
|
if(InMbr) {
|
|
ExtendedStart = NextSector;
|
|
InMbr = FALSE;
|
|
}
|
|
|
|
//
|
|
// Read the next boot sector and break out of the loop through
|
|
// the current partition table.
|
|
//
|
|
|
|
Status = SpReadWriteDiskSectors(
|
|
Handle,
|
|
NextSector,
|
|
SectorsInBootrec,
|
|
bps,
|
|
Buffer,
|
|
FALSE
|
|
);
|
|
|
|
RtlMoveMemory(&pEbr->OnDiskMbr,Buffer,sizeof(ON_DISK_MBR));
|
|
|
|
if(!NT_SUCCESS(Status)
|
|
|| (U_USHORT(pEbr->OnDiskMbr.AA55Signature) != MBR_SIGNATURE))
|
|
{
|
|
//
|
|
// BUGBUG we should warn the user that we are going to ignore
|
|
// partitions part this point because we could not read the disk
|
|
// or the structures are damaged.
|
|
//
|
|
|
|
KdPrint(("SETUP: Unable to read ebr on %ws at sector %lx (%lx)\n",pDisk->HardDisk->DevicePath,NextSector,Status));
|
|
ZwClose(Handle);
|
|
if(pLastEbr) {
|
|
SpMemFree(pEbr);
|
|
}
|
|
SpMemFree(UnalignedBuffer);
|
|
return;
|
|
}
|
|
|
|
pBr = &pEbr->OnDiskMbr;
|
|
|
|
//
|
|
// We just read the next boot sector. If all that boot sector contains
|
|
// is a link entry, the only thing we need the boot sector for is to find
|
|
// the next boot sector. This happens when there is free space at the start
|
|
// of the extended partition.
|
|
//
|
|
Ignore = TRUE;
|
|
for(x=0; x<PTABLE_DIMENSION; x++) {
|
|
if((pBr->PartitionTable[x].SystemId != PARTITION_ENTRY_UNUSED)
|
|
&& !IsContainerPartition(pBr->PartitionTable[x].SystemId)) {
|
|
|
|
Ignore = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Link the Ebr into the logical volume list if we're not ignoring it.
|
|
//
|
|
if(!Ignore) {
|
|
if(pLastEbr) {
|
|
pLastEbr->Next = pEbr;
|
|
} else {
|
|
ASSERT(pDisk->FirstEbrInfo.Next == NULL);
|
|
pDisk->FirstEbrInfo.Next = pEbr;
|
|
}
|
|
pLastEbr = pEbr;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while(FoundLink);
|
|
|
|
} else {
|
|
|
|
pDisk->MbrWasValid = FALSE;
|
|
|
|
RtlZeroMemory(&pDisk->MbrInfo,sizeof(MBR_INFO));
|
|
|
|
U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = MBR_SIGNATURE;
|
|
|
|
U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = SpComputeSerialNumber();
|
|
}
|
|
|
|
//
|
|
// Close partition0.
|
|
//
|
|
ZwClose(Handle);
|
|
|
|
SpMemFree(UnalignedBuffer);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PDISK_REGION
|
|
SpPtAllocateDiskRegionStructure(
|
|
IN ULONG DiskNumber,
|
|
IN ULONG StartSector,
|
|
IN ULONG SectorCount,
|
|
IN BOOLEAN PartitionedSpace,
|
|
IN PMBR_INFO MbrInfo,
|
|
IN ULONG TablePosition
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allcoate and initialize a structure of type DISK_REGION.
|
|
|
|
Arguments:
|
|
|
|
Values to be filled into the fields of the newly allocated
|
|
disk region structure.
|
|
|
|
Return Value:
|
|
|
|
Pointer to new disk region structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISK_REGION p;
|
|
|
|
p = SpMemAlloc(sizeof(DISK_REGION));
|
|
ASSERT(p);
|
|
|
|
if(p) {
|
|
|
|
RtlZeroMemory(p,sizeof(DISK_REGION));
|
|
|
|
p->DiskNumber = DiskNumber;
|
|
p->StartSector = StartSector;
|
|
p->SectorCount = SectorCount;
|
|
p->PartitionedSpace = PartitionedSpace;
|
|
p->MbrInfo = MbrInfo;
|
|
p->TablePosition = TablePosition;
|
|
}
|
|
|
|
return(p);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtInsertDiskRegionStructure(
|
|
IN PDISK_REGION Region,
|
|
IN OUT PDISK_REGION *ListHead
|
|
)
|
|
{
|
|
PDISK_REGION RegionCur,RegionPrev;
|
|
|
|
//
|
|
// Insert the region entry into the relevent list of region entries.
|
|
// Note that these lists are kept sorted by start sector.
|
|
//
|
|
if(RegionCur = *ListHead) {
|
|
|
|
if(Region->StartSector < RegionCur->StartSector) {
|
|
|
|
//
|
|
// Stick at head of list.
|
|
//
|
|
Region->Next = RegionCur;
|
|
*ListHead = Region;
|
|
|
|
} else {
|
|
|
|
while(1) {
|
|
|
|
RegionPrev = RegionCur;
|
|
RegionCur = RegionCur->Next;
|
|
|
|
if(RegionCur) {
|
|
|
|
if(RegionCur->StartSector > Region->StartSector) {
|
|
|
|
Region->Next = RegionCur;
|
|
RegionPrev->Next = Region;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Stick at end of list.
|
|
//
|
|
RegionPrev->Next = Region;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
*ListHead = Region;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SpPtAssignOrdinals(
|
|
IN PPARTITIONED_DISK pDisk,
|
|
IN BOOLEAN InitCurrentOrdinals,
|
|
IN BOOLEAN InitOnDiskOrdinals,
|
|
IN BOOLEAN InitOriginalOrdinals
|
|
)
|
|
{
|
|
PMBR_INFO pBrInfo;
|
|
ULONG i;
|
|
USHORT ordinal;
|
|
|
|
ordinal = 0;
|
|
|
|
for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
PON_DISK_PTE pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
|
|
|
|
if((pte->SystemId != PARTITION_ENTRY_UNUSED)
|
|
&& !IsContainerPartition(pte->SystemId)) {
|
|
|
|
ordinal++;
|
|
|
|
if(InitCurrentOrdinals) {
|
|
pBrInfo->CurrentOrdinals[i] = ordinal;
|
|
}
|
|
|
|
if(InitOnDiskOrdinals) {
|
|
pBrInfo->OnDiskOrdinals[i] = ordinal;
|
|
}
|
|
|
|
if(InitOriginalOrdinals) {
|
|
pBrInfo->OriginalOrdinals[i] = ordinal;
|
|
}
|
|
|
|
} else {
|
|
|
|
if(InitCurrentOrdinals) {
|
|
pBrInfo->CurrentOrdinals[i] = 0;
|
|
}
|
|
|
|
if(InitOnDiskOrdinals) {
|
|
pBrInfo->OnDiskOrdinals[i] = 0;
|
|
}
|
|
|
|
if(InitOriginalOrdinals) {
|
|
pBrInfo->OriginalOrdinals[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtInitializePartitionStructures(
|
|
IN ULONG DiskNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform additional initialization on the partition structures,
|
|
beyond what has been performed in SpPtReadPartitionTables.
|
|
|
|
Specifically, determine partition ordinals, offsets, and sizes.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - disk ordinal of disk descriptor to be filled in.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i,pass;
|
|
PMBR_INFO pBrInfo;
|
|
BOOLEAN InMbr;
|
|
ULONG ExtendedStart = 0;
|
|
ULONG ExtendedEnd,ExtendedSize;
|
|
ULONG offset,size;
|
|
ULONG bps;
|
|
PDISK_REGION pRegion,pRegionCur,pRegionPrev;
|
|
PPARTITIONED_DISK pDisk = &PartitionedDisks[DiskNumber];
|
|
|
|
|
|
//
|
|
// If this disk is off-line, nothing to do.
|
|
//
|
|
if(pDisk->HardDisk->Status != DiskOnLine) {
|
|
return;
|
|
}
|
|
|
|
InMbr = TRUE;
|
|
bps = pDisk->HardDisk->Geometry.BytesPerSector;
|
|
|
|
//
|
|
// Link the EBR chain to the MBR.
|
|
//
|
|
pDisk->MbrInfo.Next = &pDisk->FirstEbrInfo;
|
|
|
|
for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
PON_DISK_PTE pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
|
|
|
|
if(pte->SystemId != PARTITION_ENTRY_UNUSED) {
|
|
|
|
if(IsContainerPartition(pte->SystemId)) {
|
|
|
|
//
|
|
// If we're in the MBR, ExtendedStart will be 0.
|
|
//
|
|
offset = ExtendedStart + U_ULONG(pte->RelativeSectors);
|
|
|
|
size = U_ULONG(pte->SectorCount);
|
|
|
|
//
|
|
// Track the start of the extended partition.
|
|
//
|
|
|
|
if(InMbr) {
|
|
ExtendedStart = U_ULONG(pte->RelativeSectors);
|
|
ExtendedEnd = ExtendedStart + U_ULONG(pte->SectorCount);
|
|
ExtendedSize = ExtendedEnd - ExtendedStart;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// In the MBR, the relative sectors field is the sector offset
|
|
// to the partition. In EBRs, the relative sectors field is the
|
|
// number of sectors between the start of the boot sector and
|
|
// the start of the filesystem data area. We will consider such
|
|
// partitions to start with their boot sectors.
|
|
//
|
|
offset = InMbr ? U_ULONG(pte->RelativeSectors) : pBrInfo->OnDiskSector;
|
|
|
|
size = U_ULONG(pte->SectorCount)
|
|
+ (InMbr ? 0 : U_ULONG(pte->RelativeSectors));
|
|
}
|
|
|
|
if(InMbr || !IsContainerPartition(pte->SystemId)) {
|
|
|
|
//
|
|
// Create a region entry for this used space.
|
|
//
|
|
pRegion = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
offset,
|
|
size,
|
|
TRUE,
|
|
pBrInfo,
|
|
i
|
|
);
|
|
|
|
ASSERT(pRegion);
|
|
|
|
//
|
|
// Insert the region entry into the relevent list of region entries.
|
|
// Note that these lists are kept sorted by start sector.
|
|
//
|
|
SpPtInsertDiskRegionStructure(
|
|
pRegion,
|
|
InMbr ? &pDisk->PrimaryDiskRegions : &pDisk->ExtendedDiskRegions
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(InMbr) {
|
|
InMbr = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize partition ordinals.
|
|
//
|
|
SpPtAssignOrdinals(pDisk,TRUE,TRUE,TRUE);
|
|
|
|
|
|
//
|
|
// Now go through the regions for this disk and insert free space descriptors
|
|
// where necessary.
|
|
//
|
|
// Pass 0 for the MBR; pass 1 for logical drives.
|
|
//
|
|
for(pass=0; pass<(ULONG)(ExtendedStart ? 2 : 1); pass++) {
|
|
|
|
if(pRegionPrev = (pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions)) {
|
|
|
|
ULONG EndSector,FreeSpaceSize;
|
|
|
|
ASSERT(pRegionPrev->PartitionedSpace);
|
|
|
|
//
|
|
// Handle any space occurring *before* the first partition.
|
|
//
|
|
if(pRegionPrev->StartSector != (pass ? ExtendedStart : 0)) {
|
|
|
|
ASSERT(pRegionPrev->StartSector > (pass ? ExtendedStart : 0));
|
|
|
|
pRegion = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
pass ? ExtendedStart : 0,
|
|
pRegionPrev->StartSector - (pass ? ExtendedStart : 0),
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pRegion);
|
|
|
|
pRegion->Next = pRegionPrev;
|
|
if(pass) {
|
|
// extended
|
|
pDisk->ExtendedDiskRegions = pRegion;
|
|
} else {
|
|
// mbr
|
|
pDisk->PrimaryDiskRegions = pRegion;
|
|
}
|
|
}
|
|
|
|
pRegionCur = pRegionPrev->Next;
|
|
|
|
while(pRegionCur) {
|
|
|
|
//
|
|
// If the start of this partition plus its size is less than the
|
|
// start of the next partition, then we need a new region.
|
|
//
|
|
EndSector = pRegionPrev->StartSector + pRegionPrev->SectorCount;
|
|
FreeSpaceSize = pRegionCur->StartSector - EndSector;
|
|
|
|
if((LONG)FreeSpaceSize > 0) {
|
|
|
|
pRegion = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
EndSector,
|
|
FreeSpaceSize,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pRegion);
|
|
|
|
pRegionPrev->Next = pRegion;
|
|
pRegion->Next = pRegionCur;
|
|
}
|
|
|
|
pRegionPrev = pRegionCur;
|
|
pRegionCur = pRegionCur->Next;
|
|
}
|
|
|
|
//
|
|
// Space at end of disk/extended partition.
|
|
//
|
|
EndSector = pRegionPrev->StartSector + pRegionPrev->SectorCount;
|
|
FreeSpaceSize = (pass ? ExtendedEnd : pDisk->HardDisk->DiskSizeSectors) - EndSector;
|
|
|
|
if((LONG)FreeSpaceSize > 0) {
|
|
|
|
pRegionPrev->Next = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
EndSector,
|
|
FreeSpaceSize,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pRegionPrev->Next);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Show whole disk/extended partition as free.
|
|
//
|
|
if(pass) {
|
|
//
|
|
// Extended partition.
|
|
//
|
|
ASSERT(ExtendedStart);
|
|
|
|
pDisk->ExtendedDiskRegions = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
ExtendedStart,
|
|
ExtendedSize,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pDisk->ExtendedDiskRegions);
|
|
|
|
} else {
|
|
//
|
|
// MBR.
|
|
//
|
|
pDisk->PrimaryDiskRegions = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
0,
|
|
pDisk->HardDisk->DiskSizeSectors,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pDisk->PrimaryDiskRegions);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtCountPrimaryPartitions(
|
|
IN PPARTITIONED_DISK pDisk,
|
|
OUT PULONG TotalPrimaryPartitionCount,
|
|
OUT PULONG RecognizedPrimaryPartitionCount,
|
|
OUT PBOOLEAN ExtendedExists
|
|
)
|
|
{
|
|
ULONG TotalCount;
|
|
ULONG RecognizedCount;
|
|
ULONG u;
|
|
UCHAR SysId;
|
|
|
|
#define DOS_PARTITION(x) (((x)==1) || ((x)==4) || ((x)==6) || ((x)==7))
|
|
|
|
TotalCount = 0;
|
|
RecognizedCount = 0;
|
|
*ExtendedExists = FALSE;
|
|
|
|
for(u=0; u<PTABLE_DIMENSION; u++) {
|
|
|
|
SysId = pDisk->MbrInfo.OnDiskMbr.PartitionTable[u].SystemId;
|
|
|
|
if(SysId != PARTITION_ENTRY_UNUSED) {
|
|
|
|
TotalCount++;
|
|
|
|
if(DOS_PARTITION(SysId)) {
|
|
RecognizedCount++;
|
|
}
|
|
|
|
if(IsContainerPartition(SysId)) {
|
|
*ExtendedExists = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*TotalPrimaryPartitionCount = TotalCount;
|
|
*RecognizedPrimaryPartitionCount = RecognizedCount;
|
|
}
|
|
|
|
|
|
|
|
PDISK_REGION
|
|
SpPtLookupRegionByStart(
|
|
IN PPARTITIONED_DISK pDisk,
|
|
IN BOOLEAN ExtendedPartition,
|
|
IN ULONG StartSector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locate a disk region, based on its starting sector.
|
|
The starting sector must match the starting sector of an existing
|
|
region EXACTLY for it to be considered a match.
|
|
|
|
Arguments:
|
|
|
|
pDisk - supplies disk on which to look for the region.
|
|
|
|
ExtendedPartition - if TRUE, then look in the extended partition to find
|
|
a match. Otherwise look in the main list.
|
|
|
|
StartSector - supplies the sector number of the first sector of the region.
|
|
|
|
Return Value:
|
|
|
|
NULL is region could not be found; otherwise a pointer to the matching
|
|
disk region structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISK_REGION p;
|
|
|
|
for( p = (ExtendedPartition ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions);
|
|
p && (StartSector != p->StartSector);
|
|
p = p->Next)
|
|
{
|
|
;
|
|
}
|
|
|
|
return(p);
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
SpPtAlignStart(
|
|
IN PHARD_DISK pHardDisk,
|
|
IN ULONG StartSector,
|
|
IN BOOLEAN ForExtended
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Snap a start sector to a cylinder boundary if it is not already
|
|
on a cylinder boundary. Any alignment that is necessary
|
|
is performed towards the end of the disk.
|
|
|
|
If the start sector is on cylinder 0, then alignment is to track 1
|
|
for primary partitions, or to track 0 on cylinder 1 for extended partitions.
|
|
|
|
Arguments:
|
|
|
|
pHardDisk - supplies disk descriptor for disk that the start sector is on.
|
|
|
|
StartSector - supplies the sector number of the first sector of the region.
|
|
|
|
ForExtended - if TRUE, then align the start sector as appropriate for creating
|
|
an extended partition. Otherwise align for a pimary partition or logical drive.
|
|
|
|
Return Value:
|
|
|
|
New (aligned) start sector. May or may not be different than StartSector.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISK_GEOMETRY pGeometry;
|
|
ULONG r;
|
|
ULONG C,H,S;
|
|
|
|
pGeometry = &pHardDisk->Geometry;
|
|
|
|
//
|
|
// Convert the start sector into cylinder, head, sector address.
|
|
//
|
|
C = StartSector / pHardDisk->SectorsPerCylinder;
|
|
r = StartSector % pHardDisk->SectorsPerCylinder;
|
|
H = r / pGeometry->SectorsPerTrack;
|
|
S = r % pGeometry->SectorsPerTrack;
|
|
|
|
//
|
|
// Align as necessary.
|
|
//
|
|
if(C) {
|
|
|
|
if(H || S) {
|
|
|
|
H = S = 0;
|
|
C++;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Start cylinder is 0. If the caller wants to create an
|
|
// extended partition, bump the start cylinder up to 1.
|
|
//
|
|
if(ForExtended) {
|
|
C = 1;
|
|
H = S = 0;
|
|
} else {
|
|
|
|
//
|
|
// Start cylinder is 0 and the caller does not want to
|
|
// create an extended partition. In this case, we want
|
|
// to start the partition on cylinder 0, track 1. If the
|
|
// start is beyond this already, start on cylinder 1.
|
|
//
|
|
if((H == 0) || ((H == 1) && !S)) {
|
|
H = 1;
|
|
S = 0;
|
|
} else {
|
|
H = S = 0;
|
|
C = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now calculate and return the new start sector.
|
|
//
|
|
return((C * pHardDisk->SectorsPerCylinder) + (H * pGeometry->SectorsPerTrack) + S);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SpPtQueryMinMaxCreationSizeMB(
|
|
IN ULONG DiskNumber,
|
|
IN ULONG StartSector,
|
|
IN BOOLEAN ForExtended,
|
|
IN BOOLEAN InExtended,
|
|
OUT PULONG MinSize,
|
|
OUT PULONG MaxSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given the starting sector of an unpartitioned space on a disk,
|
|
determine the minimum and maximum size in megabytes of the partition that can
|
|
be created in the space, taking all alignment and rounding
|
|
requirements into account.
|
|
|
|
Arguments:
|
|
|
|
DiskNumber - ordinal of disk on which partition will be created.
|
|
|
|
StartSector - starting sector of an unpartitioned space on the disk.
|
|
|
|
ForExtended - if TRUE, then the caller wants to know how large an
|
|
extended partition in that space could be. This may be smaller
|
|
than the general case, because an extended partition cannot start
|
|
on cylinder 0.
|
|
|
|
InExtended - if TRUE, then we want to create a logical drive. Otherwise
|
|
we want to create a primary (including extended) partition.
|
|
If TRUE, ForExtended must be FALSE.
|
|
|
|
MinSize - receives minimum size in megabytes for a partition in the space.
|
|
|
|
MaxSize - receives maximum size in megabytes for a partition in the space.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
ULONG AlignedStartSector;
|
|
ULONG AlignedEndSector;
|
|
ULONG SectorCount;
|
|
PDISK_REGION pRegion;
|
|
LARGE_INTEGER MB,temp;
|
|
ULONG remainder;
|
|
ULONG LeftOverSectors;
|
|
|
|
*MinSize = 0;
|
|
*MaxSize = 0;
|
|
|
|
ASSERT(DiskNumber < HardDiskCount);
|
|
|
|
if(InExtended) {
|
|
ASSERT(!ForExtended);
|
|
}
|
|
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
|
|
//
|
|
// Look up this region.
|
|
//
|
|
pRegion = SpPtLookupRegionByStart(pDisk,InExtended,StartSector);
|
|
ASSERT(pRegion);
|
|
if(!pRegion) {
|
|
return;
|
|
}
|
|
|
|
ASSERT(!pRegion->PartitionedSpace);
|
|
if(pRegion->PartitionedSpace) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Align the start to a proper boundary.
|
|
//
|
|
AlignedStartSector = SpPtAlignStart(pDisk->HardDisk,StartSector,ForExtended);
|
|
|
|
//
|
|
// Determine the maximum aligned end sector.
|
|
//
|
|
AlignedEndSector = pRegion->StartSector + pRegion->SectorCount;
|
|
|
|
if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) {
|
|
AlignedEndSector -= LeftOverSectors;
|
|
}
|
|
|
|
//
|
|
// Calculate the number of sectors in the properly aligned space.
|
|
//
|
|
SectorCount = AlignedEndSector - AlignedStartSector;
|
|
|
|
ASSERT((LONG)SectorCount >= 0);
|
|
|
|
//
|
|
// Convert sectors to MB.
|
|
//
|
|
temp.QuadPart = UInt32x32To64(SectorCount,pDisk->HardDisk->Geometry.BytesPerSector);
|
|
MB = RtlExtendedLargeIntegerDivide(temp,1024*1024,&remainder);
|
|
|
|
ASSERT(!MB.HighPart);
|
|
|
|
//
|
|
// If the remainder was greater than or equal to a half meg,
|
|
// bump up the number of megabytes.
|
|
//
|
|
*MaxSize = (MB.LowPart + ((remainder >= (512*1024)) ? 1 : 0));
|
|
|
|
//
|
|
// The mimimum size is one cylinder except that if a cylinder
|
|
// is smaller than 1 meg, the min size is 1 meg.
|
|
//
|
|
temp.QuadPart = UInt32x32To64(
|
|
pDisk->HardDisk->SectorsPerCylinder,
|
|
pDisk->HardDisk->Geometry.BytesPerSector
|
|
);
|
|
|
|
*MinSize = RtlExtendedLargeIntegerDivide(temp,1024*1024,&remainder).LowPart;
|
|
|
|
if((*MinSize == 0) || (remainder >= (512*1024))) {
|
|
(*MinSize)++;
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
SpPtSectorCountToMB(
|
|
IN PHARD_DISK pHardDisk,
|
|
IN ULONG SectorCount
|
|
)
|
|
{
|
|
LARGE_INTEGER ByteCount;
|
|
ULONG MB,r;
|
|
|
|
//
|
|
// Calculate the number of bytes that this number of
|
|
// sectors represents.
|
|
//
|
|
ByteCount.QuadPart = UInt32x32To64(
|
|
pHardDisk->Geometry.BytesPerSector,
|
|
SectorCount
|
|
);
|
|
|
|
//
|
|
// Calculate the number of megabytes this represents.
|
|
//
|
|
MB = RtlExtendedLargeIntegerDivide(ByteCount,(1024*1024),&r).LowPart;
|
|
|
|
//
|
|
// Round up if necessary.
|
|
//
|
|
if(r >= (512*1024)) {
|
|
MB++;
|
|
}
|
|
|
|
return(MB);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtInitializeCHSFields(
|
|
IN PHARD_DISK HardDisk,
|
|
IN ULONG AbsoluteStartSector,
|
|
IN ULONG AbsoluteSectorCount,
|
|
OUT PON_DISK_PTE pte
|
|
)
|
|
{
|
|
ULONG sC,sH,sS,r;
|
|
ULONG eC,eH,eS;
|
|
ULONG LastSector;
|
|
|
|
|
|
sC = AbsoluteStartSector / HardDisk->SectorsPerCylinder;
|
|
r = AbsoluteStartSector % HardDisk->SectorsPerCylinder;
|
|
sH = r / HardDisk->Geometry.SectorsPerTrack;
|
|
sS = r % HardDisk->Geometry.SectorsPerTrack;
|
|
|
|
LastSector = AbsoluteStartSector + AbsoluteSectorCount - 1;
|
|
|
|
eC = LastSector / HardDisk->SectorsPerCylinder;
|
|
r = LastSector % HardDisk->SectorsPerCylinder;
|
|
eH = r / HardDisk->Geometry.SectorsPerTrack;
|
|
eS = r % HardDisk->Geometry.SectorsPerTrack;
|
|
|
|
//
|
|
// If this partition extends past the 1024th cylinder,
|
|
// place reasonable values in the CHS fields.
|
|
//
|
|
if(eC >= 1024) {
|
|
|
|
pte->StartCylinder = 0;
|
|
pte->StartHead = 0;
|
|
pte->StartSector = 2;
|
|
|
|
pte->EndCylinder = 0;
|
|
pte->EndHead = 0;
|
|
pte->EndSector = 3;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Pack the CHS values into int13 format.
|
|
//
|
|
|
|
pte->StartCylinder = (UCHAR)sC;
|
|
pte->StartHead = (UCHAR)sH;
|
|
pte->StartSector = (UCHAR)((sS & 0x3f) | ((sC >> 2) & 0xc0)) + 1;
|
|
|
|
pte->EndCylinder = (UCHAR)eC;
|
|
pte->EndHead = (UCHAR)eH;
|
|
pte->EndSector = (UCHAR)((eS & 0x3f) | ((eC >> 2) & 0xc0)) + 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpPtCreate(
|
|
IN ULONG DiskNumber,
|
|
IN ULONG StartSector,
|
|
IN ULONG SizeMB,
|
|
IN BOOLEAN InExtended,
|
|
IN UCHAR SysId,
|
|
OUT PDISK_REGION *ActualDiskRegion OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a partition in a given free space.
|
|
Arguments:
|
|
|
|
DiskNumber - supplies the number of the disk on which we are
|
|
creating the partition.
|
|
|
|
StartSector - supplies the start sector of the free space in which
|
|
the parititon is to be created. This must exactly match the
|
|
start sector of the free space, and can be in either the primary
|
|
space list or the list of spaces in the extended partition.
|
|
|
|
SizeMB - supplies the size in megabytes of the partition.
|
|
|
|
InExtended - if TRUE, then the free space is within the extended partition,
|
|
and thus we are creating a logical drive. If FALSE, then the free
|
|
space is an ordinary unpartitioned space, and we are creating a
|
|
primary partition.
|
|
|
|
SysId - supplies the system id to give the partition. This may not
|
|
be 5/f (PARTITION_EXTENDED) if InExtended is TRUE or is an extended
|
|
partition already exists. No other checks are performed on this value.
|
|
|
|
ActualDiskRegion - if supplied, receives a pointer to the disk region in which
|
|
the partition was created.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the partition was created successfully.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
ULONG SectorCount;
|
|
ULONG AlignedStartSector;
|
|
ULONG AlignedEndSector;
|
|
PDISK_REGION pRegion,pRegionPrev,pRegionNew,*pRegionHead;
|
|
ULONG LeftOverSectors;
|
|
PMBR_INFO pBrInfo;
|
|
ULONG slot,i,spt;
|
|
PON_DISK_PTE pte;
|
|
ULONG ExtendedStart;
|
|
|
|
//
|
|
// Look up the disk region that describes this free space.
|
|
//
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
pRegion = SpPtLookupRegionByStart(pDisk,InExtended,StartSector);
|
|
ASSERT(pRegion);
|
|
if(!pRegion) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if(ActualDiskRegion) {
|
|
*ActualDiskRegion = pRegion;
|
|
}
|
|
|
|
ASSERT(!pRegion->PartitionedSpace);
|
|
if(pRegion->PartitionedSpace) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if(InExtended) {
|
|
ASSERT(!IsContainerPartition(SysId));
|
|
|
|
//
|
|
// Locate the start sector of the extended partition.
|
|
//
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
if(IsContainerPartition(pDisk->MbrInfo.OnDiskMbr.PartitionTable[i].SystemId)) {
|
|
ExtendedStart = U_ULONG(pDisk->MbrInfo.OnDiskMbr.PartitionTable[i].RelativeSectors);
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(ExtendedStart);
|
|
if(!ExtendedStart) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the number of sectors in the size passed in.
|
|
// Note: the calculation is performed such that intermediate results
|
|
// won't overflow a ULONG.
|
|
//
|
|
SectorCount = SizeMB * ((1024*1024)/pDisk->HardDisk->Geometry.BytesPerSector);
|
|
|
|
//
|
|
// Align the start sector.
|
|
//
|
|
AlignedStartSector = SpPtAlignStart(
|
|
pDisk->HardDisk,
|
|
StartSector,
|
|
(BOOLEAN)IsContainerPartition(SysId)
|
|
);
|
|
|
|
//
|
|
// Determine the end sector based on the size passed in.
|
|
//
|
|
AlignedEndSector = AlignedStartSector + SectorCount;
|
|
|
|
//
|
|
// Align the ending sector to a cylinder boundary. If it is not already
|
|
// aligned and is more than half way into the final cylinder, align it up,
|
|
// otherwise align it down.
|
|
//
|
|
if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) {
|
|
AlignedEndSector -= LeftOverSectors;
|
|
if(LeftOverSectors > pDisk->HardDisk->SectorsPerCylinder/2) {
|
|
AlignedEndSector += pDisk->HardDisk->SectorsPerCylinder;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the ending sector is past the end of the free space, shrink it
|
|
// so it fits.
|
|
//
|
|
while(AlignedEndSector > pRegion->StartSector + pRegion->SectorCount) {
|
|
AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder;
|
|
}
|
|
|
|
ASSERT((LONG)AlignedEndSector > 0);
|
|
if((LONG)AlignedEndSector < 0) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// If we are creating a logical drive, create a new mbr structure
|
|
// for it.
|
|
//
|
|
|
|
if(InExtended) {
|
|
|
|
//
|
|
// Create a boot record for this new logical drive; use slot #0
|
|
// for the partition entry (and slot #1 for the extended record,
|
|
// if necessary).
|
|
//
|
|
pBrInfo = SpMemAlloc(sizeof(MBR_INFO));
|
|
ASSERT(pBrInfo);
|
|
RtlZeroMemory(pBrInfo,sizeof(MBR_INFO));
|
|
slot = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Look for a free slot in the MBR's partition table.
|
|
//
|
|
pBrInfo = &pDisk->MbrInfo;
|
|
for(slot=0; slot<PTABLE_DIMENSION; slot++) {
|
|
|
|
if(pBrInfo->OnDiskMbr.PartitionTable[slot].SystemId == PARTITION_ENTRY_UNUSED) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if(slot == PTABLE_DIMENSION) {
|
|
ASSERT(0);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the partition table entry.
|
|
//
|
|
spt = pDisk->HardDisk->Geometry.SectorsPerTrack;
|
|
|
|
pte = &pBrInfo->OnDiskMbr.PartitionTable[slot];
|
|
|
|
pte->ActiveFlag = 0;
|
|
pte->SystemId = SysId;
|
|
|
|
U_ULONG(pte->RelativeSectors) = InExtended ? spt : AlignedStartSector;
|
|
|
|
U_ULONG(pte->SectorCount) = AlignedEndSector - AlignedStartSector - (InExtended ? spt : 0);
|
|
|
|
SpPtInitializeCHSFields(
|
|
pDisk->HardDisk,
|
|
AlignedStartSector + (InExtended ? spt : 0),
|
|
AlignedEndSector - AlignedStartSector - (InExtended ? spt : 0),
|
|
pte
|
|
);
|
|
|
|
//
|
|
// If we're in the extended partition we mark all entries in the
|
|
// boot record as dirty. Sometimes there is a turd boot record on
|
|
// the disk already, and by setting all entries to dirty we get
|
|
// the crud cleaned out if necessary. The only entries that should be
|
|
// in an EBR are the type 6 or whatever and a type 5 if there are
|
|
// additional logical drives in the extended partition.
|
|
//
|
|
if(InExtended) {
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
pBrInfo->Dirty[i] = TRUE;
|
|
}
|
|
} else {
|
|
pBrInfo->Dirty[slot] = TRUE;
|
|
}
|
|
|
|
//
|
|
// Don't zap the first sector of the extended partition,
|
|
// as this wipes out the first logical drive, and precludes
|
|
// access to all logical drives!
|
|
//
|
|
if(!IsContainerPartition(SysId)) {
|
|
pBrInfo->ZapBootSector[slot] = TRUE;
|
|
}
|
|
|
|
//
|
|
// Find the previous region (ie, the one that points to this one).
|
|
// This region (if it exists) will be partitioned space (otherwise
|
|
// it would have been part of the region we are trying to create
|
|
// a partition in!)
|
|
//
|
|
pRegionHead = InExtended ? &pDisk->ExtendedDiskRegions : &pDisk->PrimaryDiskRegions;
|
|
|
|
if(*pRegionHead == pRegion) {
|
|
pRegionPrev = NULL;
|
|
} else {
|
|
for(pRegionPrev = *pRegionHead; pRegionPrev; pRegionPrev = pRegionPrev->Next) {
|
|
if(pRegionPrev->Next == pRegion) {
|
|
ASSERT(pRegionPrev->PartitionedSpace);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(InExtended) {
|
|
|
|
PMBR_INFO PrevEbr;
|
|
|
|
//
|
|
// The new logical drive goes immediately after the
|
|
// previous logical drive (if any). Remember that if there is
|
|
// a previous region, it will be partitioned space (otherwise
|
|
// it would be a part of the region we are trying to create
|
|
// a partition in).
|
|
//
|
|
PrevEbr = pRegionPrev ? pRegionPrev->MbrInfo : NULL;
|
|
if(PrevEbr) {
|
|
pBrInfo->Next = PrevEbr->Next;
|
|
PrevEbr->Next = pBrInfo;
|
|
} else {
|
|
//
|
|
// No previous EBR or region. This means we are creating
|
|
// a logical drive at the beginning of the extended partition
|
|
// so set the First Ebr pointer to point to the new Ebr.
|
|
// Note that this does not mean that the extended partition
|
|
// is empty; the Next pointer in the new Ebr structure is
|
|
// set later.
|
|
//
|
|
pDisk->FirstEbrInfo.Next = pBrInfo;
|
|
if(pRegion->Next) {
|
|
//
|
|
// If there is a region following the one we're creating
|
|
// the partition in, it must be partitioned space, or else
|
|
// it would be part of the region we're creating the partition in.
|
|
//
|
|
ASSERT(pRegion->Next->PartitionedSpace);
|
|
ASSERT(pRegion->Next->MbrInfo);
|
|
pBrInfo->Next = pRegion->Next->MbrInfo;
|
|
} else {
|
|
//
|
|
// No more partitioned space in the extended partition;
|
|
// the logical drive we are creating is the only one.
|
|
//
|
|
pBrInfo->Next = NULL;
|
|
}
|
|
}
|
|
|
|
pBrInfo->OnDiskSector = AlignedStartSector;
|
|
|
|
//
|
|
// Create a link entry in the previous logical drive (if any).
|
|
//
|
|
if(PrevEbr) {
|
|
|
|
//
|
|
// If there is a link entry in there already, blow it away.
|
|
//
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
if(IsContainerPartition(PrevEbr->OnDiskMbr.PartitionTable[i].SystemId)) {
|
|
RtlZeroMemory(&PrevEbr->OnDiskMbr.PartitionTable[i],sizeof(ON_DISK_PTE));
|
|
PrevEbr->Dirty[i] = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find a free slot for the link entry.
|
|
//
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
pte = &PrevEbr->OnDiskMbr.PartitionTable[i];
|
|
|
|
if(pte->SystemId == PARTITION_ENTRY_UNUSED) {
|
|
|
|
pte->SystemId = PARTITION_EXTENDED;
|
|
pte->ActiveFlag = 0;
|
|
|
|
U_ULONG(pte->RelativeSectors) = AlignedStartSector - ExtendedStart;
|
|
|
|
U_ULONG(pte->SectorCount) = AlignedEndSector - AlignedStartSector;
|
|
|
|
SpPtInitializeCHSFields(
|
|
pDisk->HardDisk,
|
|
AlignedStartSector,
|
|
U_ULONG(pte->SectorCount),
|
|
pte
|
|
);
|
|
|
|
PrevEbr->Dirty[i] = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a link entry in this new logical drive if necessary.
|
|
//
|
|
if(pBrInfo->Next) {
|
|
|
|
//
|
|
// Find the next entry's logical drive.
|
|
//
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
if((pBrInfo->Next->OnDiskMbr.PartitionTable[i].SystemId != PARTITION_ENTRY_UNUSED)
|
|
&& !IsContainerPartition(pBrInfo->Next->OnDiskMbr.PartitionTable[i].SystemId))
|
|
{
|
|
pte = &pBrInfo->OnDiskMbr.PartitionTable[1];
|
|
|
|
pte->SystemId = PARTITION_EXTENDED;
|
|
pte->ActiveFlag = 0;
|
|
|
|
U_ULONG(pte->RelativeSectors) = pBrInfo->Next->OnDiskSector - ExtendedStart;
|
|
|
|
U_ULONG(pte->SectorCount) = U_ULONG(pBrInfo->Next->OnDiskMbr.PartitionTable[i].RelativeSectors)
|
|
+ U_ULONG(pBrInfo->Next->OnDiskMbr.PartitionTable[i].SectorCount);
|
|
|
|
SpPtInitializeCHSFields(
|
|
pDisk->HardDisk,
|
|
pBrInfo->Next->OnDiskSector,
|
|
U_ULONG(pte->SectorCount),
|
|
pte
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we just created a new extended partition, we need to
|
|
// create a blank region descriptor for it in the extended region list.
|
|
//
|
|
if(!InExtended && IsContainerPartition(SysId)) {
|
|
|
|
ASSERT(pDisk->ExtendedDiskRegions == NULL);
|
|
|
|
pDisk->ExtendedDiskRegions = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
AlignedStartSector,
|
|
AlignedEndSector - AlignedStartSector,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pDisk->ExtendedDiskRegions);
|
|
}
|
|
|
|
//
|
|
// Create a new disk region for the new free space at the
|
|
// beginning and end of the free space, if any.
|
|
//
|
|
if(AlignedStartSector - pRegion->StartSector) {
|
|
|
|
pRegionNew = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
pRegion->StartSector,
|
|
AlignedStartSector - pRegion->StartSector,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ASSERT(pRegionNew);
|
|
|
|
if(pRegionPrev) {
|
|
pRegionPrev->Next = pRegionNew;
|
|
} else {
|
|
*pRegionHead = pRegionNew;
|
|
}
|
|
pRegionNew->Next = pRegion;
|
|
}
|
|
|
|
if(pRegion->StartSector + pRegion->SectorCount - AlignedEndSector) {
|
|
|
|
pRegionNew = SpPtAllocateDiskRegionStructure(
|
|
DiskNumber,
|
|
AlignedEndSector,
|
|
pRegion->StartSector + pRegion->SectorCount - AlignedEndSector,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
pRegionNew->Next = pRegion->Next;
|
|
pRegion->Next = pRegionNew;
|
|
}
|
|
|
|
//
|
|
// Adjust the current disk region.
|
|
//
|
|
pRegion->StartSector = AlignedStartSector;
|
|
pRegion->SectorCount = AlignedEndSector - AlignedStartSector;
|
|
pRegion->PartitionedSpace = TRUE;
|
|
pRegion->TablePosition = slot;
|
|
pRegion->MbrInfo = pBrInfo;
|
|
|
|
pRegion->VolumeLabel[0] = 0;
|
|
pRegion->Filesystem = FilesystemNewlyCreated;
|
|
pRegion->FreeSpaceKB = (ULONG)(-1);
|
|
pRegion->AdjustedFreeSpaceKB = (ULONG)(-1);
|
|
SpFormatMessage(
|
|
pRegion->TypeName,
|
|
sizeof(pRegion->TypeName),
|
|
SP_TEXT_FS_NAME_BASE + pRegion->Filesystem
|
|
);
|
|
|
|
//
|
|
// Adjust partition ordinals on this disk.
|
|
//
|
|
SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE);
|
|
|
|
//
|
|
// Reassign drive letters.
|
|
//
|
|
SpPtGuessDriveLetters();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpPtDelete(
|
|
IN ULONG DiskNumber,
|
|
IN ULONG StartSector
|
|
)
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
PDISK_REGION pRegion,pRegionPrev,*pRegionHead,pRegionNext;
|
|
BOOLEAN InExtended;
|
|
PON_DISK_PTE pte;
|
|
PMBR_INFO pEbrPrev,pEbr;
|
|
ULONG i,j;
|
|
PHARD_DISK pHardDisk;
|
|
ULONG PartitionOrdinal;
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
|
|
//
|
|
// First try to look up this region in the extended partition.
|
|
// If we can find it, assume it's a logical drive.
|
|
//
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
pRegion = SpPtLookupRegionByStart(pDisk,TRUE,StartSector);
|
|
if(pRegion && pRegion->PartitionedSpace) {
|
|
InExtended = TRUE;
|
|
} else {
|
|
InExtended = FALSE;
|
|
pRegion = SpPtLookupRegionByStart(pDisk,FALSE,StartSector);
|
|
}
|
|
|
|
ASSERT(pRegion);
|
|
if(!pRegion) {
|
|
return(FALSE);
|
|
}
|
|
|
|
ASSERT(pRegion->PartitionedSpace);
|
|
if(!pRegion->PartitionedSpace) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// At this point, we dismount the volume (if it's not newly created),
|
|
// so we don't run into problems later on when we go to format
|
|
//
|
|
if(pRegion->Filesystem > FilesystemNewlyCreated) {
|
|
|
|
pHardDisk = &HardDisks[pRegion->DiskNumber];
|
|
PartitionOrdinal = SpPtGetOrdinal(pRegion, PartitionOrdinalOnDisk);
|
|
|
|
//
|
|
// Open the partition for read/write access.
|
|
// This shouldn't lock the volume so we need to lock it below.
|
|
//
|
|
Status = SpOpenPartition(
|
|
pHardDisk->DevicePath,
|
|
PartitionOrdinal,
|
|
&Handle,
|
|
TRUE
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint((
|
|
"SETUP: SpPtDelete: unable to open %ws partition %u (%lx)\n",
|
|
pHardDisk->DevicePath,
|
|
PartitionOrdinal,
|
|
Status
|
|
));
|
|
goto AfterDismount;
|
|
}
|
|
|
|
//
|
|
// Lock the drive.
|
|
//
|
|
Status = SpLockUnlockVolume(Handle, TRUE);
|
|
|
|
//
|
|
// We shouldn't have any file opened that would cause this volume
|
|
// to already be locked, so if we get failure (ie, STATUS_ACCESS_DENIED)
|
|
// something is really wrong. This typically indicates something is
|
|
// wrong with the hard disk that won't allow us to access it.
|
|
//
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: SpPtDelete: status %lx, unable to lock drive\n", Status));
|
|
ZwClose(Handle);
|
|
goto AfterDismount;
|
|
}
|
|
|
|
//
|
|
// Dismount the drive
|
|
//
|
|
Status = SpDismountVolume(Handle);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: SpPtDelete: status %lx, unable to dismount drive\n", Status));
|
|
SpLockUnlockVolume(Handle, FALSE);
|
|
ZwClose(Handle);
|
|
goto AfterDismount;
|
|
}
|
|
|
|
//
|
|
// Unlock the drive
|
|
//
|
|
Status = SpLockUnlockVolume(Handle, FALSE);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: SpPtDelete: status %lx, unable to unlock drive\n", Status));
|
|
}
|
|
|
|
ZwClose(Handle);
|
|
}
|
|
|
|
AfterDismount:
|
|
//
|
|
// Find the previous region (ie, the one that points to this one).
|
|
//
|
|
pRegionHead = InExtended ? &pDisk->ExtendedDiskRegions : &pDisk->PrimaryDiskRegions;
|
|
|
|
if(*pRegionHead == pRegion) {
|
|
pRegionPrev = NULL;
|
|
} else {
|
|
for(pRegionPrev = *pRegionHead; pRegionPrev; pRegionPrev = pRegionPrev->Next) {
|
|
if(pRegionPrev->Next == pRegion) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Additional processing for logical drives.
|
|
//
|
|
if(InExtended) {
|
|
|
|
//
|
|
// Locate the previous and next logical drives (if any).
|
|
//
|
|
pEbr = pRegion->MbrInfo;
|
|
|
|
for(pEbrPrev=pDisk->FirstEbrInfo.Next; pEbrPrev; pEbrPrev=pEbrPrev->Next) {
|
|
if(pEbrPrev->Next == pEbr) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is a previous logical drive, blow aways its link
|
|
// entry, because it points to the logical drive we're deleting.
|
|
//
|
|
if(pEbrPrev) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
pte = &pEbrPrev->OnDiskMbr.PartitionTable[i];
|
|
|
|
if(IsContainerPartition(pte->SystemId)) {
|
|
|
|
RtlZeroMemory(pte,sizeof(ON_DISK_PTE));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is a next logical drive and a previous logical drive,
|
|
// set a new link entry in previous logical drive to point to
|
|
// the next logical drive.
|
|
//
|
|
if(pEbrPrev && pEbr->Next) {
|
|
|
|
//
|
|
// Locate the link entry in the logical drive being deleted.
|
|
//
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
if(IsContainerPartition(pEbr->OnDiskMbr.PartitionTable[i].SystemId)) {
|
|
|
|
//
|
|
// Locate an empty slot in the previous logical drive's boot record
|
|
// and copy the link entry
|
|
//
|
|
for(j=0; j<PTABLE_DIMENSION; j++) {
|
|
if(pEbrPrev->OnDiskMbr.PartitionTable[j].SystemId == PARTITION_ENTRY_UNUSED) {
|
|
|
|
//
|
|
// Copy the link entry.
|
|
//
|
|
RtlMoveMemory(
|
|
&pEbr->OnDiskMbr.PartitionTable[i],
|
|
&pEbrPrev->OnDiskMbr.PartitionTable[j],
|
|
sizeof(ON_DISK_PTE)
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove the EBR for this logical drive.
|
|
//
|
|
if(pEbrPrev) {
|
|
pEbrPrev->Next = pEbr->Next;
|
|
} else {
|
|
ASSERT(pDisk->FirstEbrInfo.Next == pEbr);
|
|
pDisk->FirstEbrInfo.Next = pEbr->Next;
|
|
}
|
|
|
|
SpMemFree(pEbr);
|
|
|
|
} else {
|
|
|
|
ASSERT(pRegion->MbrInfo == &pDisk->MbrInfo);
|
|
|
|
pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
|
|
|
|
ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
|
|
|
|
//
|
|
// Mark the entry dirty in the MBR.
|
|
//
|
|
pDisk->MbrInfo.Dirty[pRegion->TablePosition] = TRUE;
|
|
|
|
//
|
|
// If this is the extended partition, verify that it is empty.
|
|
//
|
|
if(IsContainerPartition(pte->SystemId)) {
|
|
ASSERT(pDisk->ExtendedDiskRegions);
|
|
ASSERT(pDisk->ExtendedDiskRegions->PartitionedSpace == FALSE);
|
|
ASSERT(pDisk->ExtendedDiskRegions->Next == NULL);
|
|
ASSERT(pDisk->FirstEbrInfo.Next == NULL);
|
|
|
|
if(pDisk->ExtendedDiskRegions->Next || pDisk->FirstEbrInfo.Next) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Free the single disk region that covers the entire extended partition.
|
|
//
|
|
SpMemFree(pDisk->ExtendedDiskRegions);
|
|
pDisk->ExtendedDiskRegions = NULL;
|
|
}
|
|
|
|
//
|
|
// Adjust the PTE for this partition by zeroing it out.
|
|
//
|
|
RtlZeroMemory(pte,sizeof(ON_DISK_PTE));
|
|
}
|
|
|
|
|
|
//
|
|
// Adjust fields in the region to describe this space as free.
|
|
//
|
|
pRegion->MbrInfo->ZapBootSector[pRegion->TablePosition] = FALSE;
|
|
pRegion->PartitionedSpace = FALSE;
|
|
pRegion->MbrInfo = NULL;
|
|
pRegion->TablePosition = 0;
|
|
|
|
//
|
|
// If previous region is free space, coalesce it and the region
|
|
// we just made free.
|
|
//
|
|
if(pRegionPrev && !pRegionPrev->PartitionedSpace) {
|
|
|
|
PDISK_REGION p;
|
|
|
|
ASSERT(pRegionPrev->StartSector + pRegionPrev->SectorCount == pRegion->StartSector);
|
|
|
|
pRegion->SectorCount = pRegion->StartSector + pRegion->SectorCount - pRegionPrev->StartSector;
|
|
pRegion->StartSector = pRegionPrev->StartSector;
|
|
|
|
//
|
|
// Delete the previous region.
|
|
//
|
|
if(pRegionPrev == *pRegionHead) {
|
|
//
|
|
// The previous region was the first region.
|
|
//
|
|
*pRegionHead = pRegion;
|
|
} else {
|
|
|
|
for(p = *pRegionHead; p; p=p->Next) {
|
|
if(p->Next == pRegionPrev) {
|
|
ASSERT(p->PartitionedSpace);
|
|
p->Next = pRegion;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SpMemFree(pRegionPrev);
|
|
}
|
|
|
|
//
|
|
// If the next region is free space, coalesce it and the region
|
|
// we just made free.
|
|
//
|
|
if((pRegionNext = pRegion->Next) && !pRegionNext->PartitionedSpace) {
|
|
|
|
ASSERT(pRegion->StartSector + pRegion->SectorCount == pRegionNext->StartSector);
|
|
|
|
pRegion->SectorCount = pRegionNext->StartSector + pRegionNext->SectorCount - pRegion->StartSector;
|
|
|
|
//
|
|
// Delete the next region.
|
|
//
|
|
pRegion->Next = pRegionNext->Next;
|
|
SpMemFree(pRegionNext);
|
|
}
|
|
|
|
//
|
|
// Adjust the partition ordinals on this disk.
|
|
//
|
|
SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE);
|
|
|
|
//
|
|
// Reassign drive letters.
|
|
//
|
|
SpPtGuessDriveLetters();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpPtExtend(
|
|
IN PDISK_REGION Region
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Extends a partition by claiming any free space immedately following it
|
|
on the disk. The end boundary of the existing partition is adjusted
|
|
so that the partition encompasses the free space.
|
|
|
|
The partition may not be the extended partition and it may not be
|
|
a logical drive within the extended partition.
|
|
|
|
Note that no filesystem structures are manipulated or examined by
|
|
this routine. Essentially it deals only with the partition table entry.
|
|
|
|
Arguments:
|
|
|
|
Region - supplies the region descriptor for the partition to be
|
|
extended. That partition must not be the extended partition and
|
|
it cannot be a logical drive either.
|
|
|
|
Return Value:
|
|
|
|
Boolean value indicating whether anything actually changed.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISK_REGION NextRegion;
|
|
PPARTITIONED_DISK pDisk;
|
|
PMBR_INFO pBrInfo;
|
|
PON_DISK_PTE pte;
|
|
ULONG NewEndSector;
|
|
|
|
pDisk = &PartitionedDisks[Region->DiskNumber];
|
|
|
|
ASSERT(Region->PartitionedSpace);
|
|
if(!Region->PartitionedSpace) {
|
|
return(FALSE);
|
|
}
|
|
|
|
pBrInfo = Region->MbrInfo;
|
|
pte = &pBrInfo->OnDiskMbr.PartitionTable[Region->TablePosition];
|
|
|
|
//
|
|
// Make sure it's not the extended partition and is not
|
|
// in the extended partition.
|
|
//
|
|
if(pBrInfo->OnDiskSector || IsContainerPartition(pte->SystemId)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// If there's no next region then there's nothing to do.
|
|
// If there is a next region make sure it's empty.
|
|
//
|
|
NextRegion = Region->Next;
|
|
if(!NextRegion) {
|
|
return(FALSE);
|
|
}
|
|
if(NextRegion->PartitionedSpace) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Claim the entire free region and align the ending sector
|
|
// to a cylinder boundary.
|
|
//
|
|
NewEndSector = NextRegion->StartSector + NextRegion->SectorCount;
|
|
NewEndSector -= NewEndSector % pDisk->HardDisk->SectorsPerCylinder;
|
|
|
|
#if 0
|
|
//
|
|
// Cap the end at the 1024th cylinder if necessary.
|
|
//
|
|
if(Cap1024Cylinders && ((NewEndSector / pDisk->HardDisk->SectorsPerCylinder) >= 1024)) {
|
|
|
|
NewEndSector = 1024 * pDisk->HardDisk->SectorsPerCylinder;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Fix up the size and end CHS fields in the partition table entry
|
|
// for the partition.
|
|
//
|
|
U_ULONG(pte->SectorCount) = NewEndSector - Region->StartSector;
|
|
|
|
SpPtInitializeCHSFields(
|
|
pDisk->HardDisk,
|
|
Region->StartSector,
|
|
NewEndSector - Region->StartSector,
|
|
pte
|
|
);
|
|
|
|
pBrInfo->Dirty[Region->TablePosition] = TRUE;
|
|
|
|
//
|
|
// If there is space left over at the end of the free region
|
|
// we just stuck onto the end of the existing partition,
|
|
// adjust the free region's descriptor. Else get rid of it.
|
|
//
|
|
if(NextRegion->StartSector + NextRegion->SectorCount == NewEndSector) {
|
|
|
|
Region->Next = NextRegion->Next;
|
|
SpMemFree(NextRegion);
|
|
|
|
} else {
|
|
|
|
NextRegion->SectorCount = NextRegion->StartSector + NextRegion->SectorCount - NewEndSector;
|
|
NextRegion->StartSector = NewEndSector;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
#ifdef _X86_
|
|
VOID
|
|
SpPtMarkActive(
|
|
IN ULONG TablePosition
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Mark a partition on drive 0 active, and deactivate all others.
|
|
|
|
Arguments:
|
|
|
|
TablePosition - supplies offset within partition table (0-3)
|
|
of the partition entry to be activated.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
PON_DISK_PTE pte;
|
|
ULONG Disk0Ordinal;
|
|
|
|
ASSERT(TablePosition < PTABLE_DIMENSION);
|
|
|
|
Disk0Ordinal = SpDetermineDisk0();
|
|
|
|
//
|
|
// Deactivate all others.
|
|
//
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
pte = &PartitionedDisks[Disk0Ordinal].MbrInfo.OnDiskMbr.PartitionTable[i];
|
|
|
|
if((pte->SystemId != PARTITION_ENTRY_UNUSED)
|
|
&& pte->ActiveFlag
|
|
&& (i != TablePosition))
|
|
{
|
|
pte->ActiveFlag = 0;
|
|
PartitionedDisks[0].MbrInfo.Dirty[i] = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Activate the one we want to activate.
|
|
//
|
|
pte = &PartitionedDisks[Disk0Ordinal].MbrInfo.OnDiskMbr.PartitionTable[TablePosition];
|
|
ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
|
|
ASSERT(!IsContainerPartition(pte->SystemId));
|
|
ASSERT(PartitionNameIds[pte->SystemId] == (UCHAR)(-1));
|
|
if(!pte->ActiveFlag) {
|
|
pte->ActiveFlag = 0x80;
|
|
PartitionedDisks[Disk0Ordinal].MbrInfo.Dirty[TablePosition] = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
SpPtCommitChanges(
|
|
IN ULONG DiskNumber,
|
|
OUT PBOOLEAN AnyChanges
|
|
)
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
ULONG DiskLayoutSize;
|
|
PDISK_REGION pRegion;
|
|
PMBR_INFO pBrInfo;
|
|
ULONG BootRecordCount;
|
|
BOOLEAN NeedDummyEbr;
|
|
PDRIVE_LAYOUT_INFORMATION DriveLayout;
|
|
PPARTITION_INFORMATION PartitionInfo;
|
|
ULONG PartitionEntry;
|
|
ULONG bps;
|
|
PON_DISK_PTE pte;
|
|
ULONG ExtendedStart;
|
|
ULONG Offset;
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
ULONG i;
|
|
ULONG ZapSector;
|
|
PUCHAR Buffer,UBuffer;
|
|
ULONG NewSig;
|
|
|
|
|
|
ASSERT(DiskNumber < HardDiskCount);
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
*AnyChanges = FALSE;
|
|
bps = pDisk->HardDisk->Geometry.BytesPerSector;
|
|
ExtendedStart = 0;
|
|
|
|
//
|
|
// Determine the number of boot records that will used on this disk.
|
|
// There is one for the MBR, and one for each logical drive.
|
|
//
|
|
BootRecordCount = 1;
|
|
for(pRegion=pDisk->ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
|
|
if(pRegion->PartitionedSpace) {
|
|
BootRecordCount++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determine whether a dummy boot record is rquired at the start
|
|
// of the extended partition. This is the case when there is free
|
|
// space at its start.
|
|
//
|
|
if(pDisk->ExtendedDiskRegions
|
|
&& !pDisk->ExtendedDiskRegions->PartitionedSpace
|
|
&& pDisk->ExtendedDiskRegions->Next)
|
|
{
|
|
NeedDummyEbr = TRUE;
|
|
BootRecordCount++;
|
|
} else {
|
|
NeedDummyEbr = FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate a disk layout structure whose size is based on the
|
|
// number of boot records. This assumes that the structure contains
|
|
// one partition information structure in its definition.
|
|
//
|
|
DiskLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION)
|
|
+ (BootRecordCount * PTABLE_DIMENSION * sizeof(PARTITION_INFORMATION))
|
|
- sizeof(PARTITION_INFORMATION);
|
|
|
|
DriveLayout = SpMemAlloc(DiskLayoutSize);
|
|
ASSERT(DriveLayout);
|
|
RtlZeroMemory(DriveLayout,DiskLayoutSize);
|
|
|
|
//
|
|
// Set up some of the fields of the drive layout structure.
|
|
//
|
|
DriveLayout->PartitionCount = BootRecordCount * sizeof(PTABLE_DIMENSION);
|
|
|
|
//
|
|
// Go through each boot record and initialize the matching
|
|
// partition information structure in the drive layout structure.
|
|
//
|
|
for(PartitionEntry=0,pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
pBrInfo->UserData[i] = NULL;
|
|
}
|
|
|
|
//
|
|
// If we are going to need a dummy logical drive,
|
|
// leave space for it here.
|
|
//
|
|
if(pBrInfo == &pDisk->FirstEbrInfo) {
|
|
if(NeedDummyEbr) {
|
|
PartitionEntry += PTABLE_DIMENSION;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
ASSERT(PartitionEntry < BootRecordCount*PTABLE_DIMENSION);
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
//
|
|
// Point to partition information structure within
|
|
// drive layout structure.
|
|
//
|
|
PartitionInfo = &DriveLayout->PartitionEntry[PartitionEntry+i];
|
|
|
|
//
|
|
// Transfer this partition table entry
|
|
// into the drive layout structure, field by field.
|
|
//
|
|
pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
|
|
|
|
//
|
|
// If this is the extended partition, remember where it starts.
|
|
//
|
|
if((pBrInfo == &pDisk->MbrInfo)
|
|
&& IsContainerPartition(pte->SystemId)
|
|
&& !ExtendedStart)
|
|
{
|
|
ExtendedStart = U_ULONG(pte->RelativeSectors);
|
|
}
|
|
|
|
if(pte->SystemId != PARTITION_ENTRY_UNUSED) {
|
|
|
|
if(!IsContainerPartition(pte->SystemId)) {
|
|
pBrInfo->UserData[i] = PartitionInfo;
|
|
}
|
|
|
|
//
|
|
// Calculate starting offset. If we are within
|
|
// the extended parttion and this is a type 5 entry,
|
|
// then the relative sector field counts the number of sectors
|
|
// between the main extended partition's first sector and
|
|
// the logical drive described by this entry.
|
|
// Otherwise, the relative sectors field describes the number
|
|
// of sectors between the boot record and the actual start
|
|
// of the partition.
|
|
//
|
|
|
|
if((pBrInfo != &pDisk->MbrInfo) && IsContainerPartition(pte->SystemId)) {
|
|
ASSERT(ExtendedStart);
|
|
Offset = ExtendedStart + U_ULONG(pte->RelativeSectors);
|
|
} else {
|
|
Offset = pBrInfo->OnDiskSector + U_ULONG(pte->RelativeSectors);
|
|
}
|
|
|
|
PartitionInfo->StartingOffset.QuadPart = UInt32x32To64(Offset,bps);
|
|
|
|
//
|
|
// Calculate size.
|
|
//
|
|
PartitionInfo->PartitionLength.QuadPart = UInt32x32To64(U_ULONG(pte->SectorCount),bps);
|
|
}
|
|
|
|
//
|
|
// Other fields.
|
|
//
|
|
PartitionInfo->PartitionType = pte->SystemId;
|
|
PartitionInfo->BootIndicator = pte->ActiveFlag;
|
|
PartitionInfo->RewritePartition = pBrInfo->Dirty[i];
|
|
|
|
if(pBrInfo->Dirty[i]) {
|
|
*AnyChanges = TRUE;
|
|
}
|
|
|
|
pBrInfo->Dirty[i] = FALSE;
|
|
}
|
|
|
|
PartitionEntry += PTABLE_DIMENSION;
|
|
}
|
|
|
|
//
|
|
// If there are no changes, just return success now.
|
|
//
|
|
if(!(*AnyChanges)) {
|
|
SpMemFree(DriveLayout);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// If there is free space at the start of the extended partition,
|
|
// then we need to generate a dummy boot record.
|
|
//
|
|
if(NeedDummyEbr) {
|
|
|
|
pRegion = pDisk->ExtendedDiskRegions->Next;
|
|
|
|
ASSERT(pRegion->PartitionedSpace);
|
|
ASSERT(pRegion->StartSector == pRegion->MbrInfo->OnDiskSector);
|
|
ASSERT(ExtendedStart == pDisk->ExtendedDiskRegions->StartSector);
|
|
|
|
PartitionInfo = &DriveLayout->PartitionEntry[PTABLE_DIMENSION];
|
|
|
|
PartitionInfo->StartingOffset.QuadPart = UInt32x32To64(pRegion->StartSector,bps);
|
|
|
|
PartitionInfo->PartitionLength.QuadPart = UInt32x32To64(pRegion->SectorCount,bps);
|
|
|
|
PartitionInfo->PartitionType = PARTITION_EXTENDED;
|
|
PartitionInfo->RewritePartition = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// We now have everything set up. Open partition 0 on the disk.
|
|
//
|
|
Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,TRUE);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: committing changes, unable to open disk %u (%lx)\n",DiskNumber,Status));
|
|
SpMemFree(DriveLayout);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Make sure the mbr is valid before writing the changes.
|
|
//
|
|
if(!pDisk->MbrWasValid) {
|
|
Status = SpMasterBootCode(DiskNumber,Handle,&NewSig);
|
|
if(NT_SUCCESS(Status)) {
|
|
//
|
|
// If a new NTFT signature was generated, propagate it.
|
|
//
|
|
if(NewSig) {
|
|
U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = NewSig;
|
|
}
|
|
} else {
|
|
KdPrint(("SETUP: committing changes on disk %u, SpMasterBootCode returns %lx\n",DiskNumber,Status));
|
|
ZwClose(Handle);
|
|
SpMemFree(DriveLayout);
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
DriveLayout->Signature = U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature);
|
|
|
|
//
|
|
// Write the changes.
|
|
//
|
|
Status = ZwDeviceIoControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_DISK_SET_DRIVE_LAYOUT,
|
|
DriveLayout,
|
|
DiskLayoutSize,
|
|
DriveLayout,
|
|
DiskLayoutSize
|
|
);
|
|
|
|
// Deferred freeing memory till later on because we still need info in this structure (lonnym)
|
|
// SpMemFree(DriveLayout);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: committing changes on disk %u, ioctl returns %lx\n",DiskNumber,Status));
|
|
SpMemFree(DriveLayout);
|
|
ZwClose(Handle);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for zapping.
|
|
//
|
|
UBuffer = SpMemAlloc(2*bps);
|
|
ASSERT(UBuffer);
|
|
Buffer = ALIGN(UBuffer,bps);
|
|
RtlZeroMemory(Buffer,bps);
|
|
|
|
for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
//
|
|
// Update current partition ordinals.
|
|
//
|
|
if(pBrInfo->UserData[i]) {
|
|
|
|
PartitionInfo = (PPARTITION_INFORMATION)pBrInfo->UserData[i];
|
|
|
|
//
|
|
// The partition ordinal better be non-0!
|
|
//
|
|
if(PartitionInfo->PartitionNumber) {
|
|
|
|
//
|
|
// Update current partition ordinal.
|
|
//
|
|
pBrInfo->CurrentOrdinals[i] = (USHORT)PartitionInfo->PartitionNumber;
|
|
|
|
} else {
|
|
SpBugCheck(
|
|
SETUP_BUGCHECK_PARTITION,
|
|
PARTITIONBUG_A,
|
|
DiskNumber,
|
|
pBrInfo->CurrentOrdinals[i]
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there were any newly created partitions in this boot record,
|
|
// zap their filesystem boot sectors.
|
|
//
|
|
if(pBrInfo->ZapBootSector[i]) {
|
|
//
|
|
// We shouldn't be zapping any partitions that don't exist.
|
|
//
|
|
ASSERT(pBrInfo->OnDiskMbr.PartitionTable[i].SystemId != PARTITION_ENTRY_UNUSED);
|
|
|
|
//
|
|
// This calculation is correct for partitions and logical drives.
|
|
//
|
|
ZapSector = pBrInfo->OnDiskSector
|
|
+ U_ULONG(pBrInfo->OnDiskMbr.PartitionTable[i].RelativeSectors);
|
|
|
|
//
|
|
// The consequences for screw-up here are so huge that a special check
|
|
// is warranted to make sure we're not clobbering the MBR.
|
|
//
|
|
ASSERT(ZapSector);
|
|
if(ZapSector) {
|
|
Status = SpReadWriteDiskSectors(
|
|
Handle,
|
|
ZapSector,
|
|
1,
|
|
bps,
|
|
Buffer,
|
|
TRUE
|
|
);
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: zapping sector %lx on disk %u returned %lx\n",ZapSector,DiskNumber,Status));
|
|
SpMemFree(DriveLayout);
|
|
SpMemFree(UBuffer);
|
|
ZwClose(Handle);
|
|
return(Status);
|
|
}
|
|
|
|
pBrInfo->ZapBootSector[i] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SpMemFree(UBuffer);
|
|
ZwClose(Handle);
|
|
|
|
//
|
|
// Reassign on-disk ordinals (but not original ones).
|
|
//
|
|
SpPtAssignOrdinals(pDisk,FALSE,TRUE,FALSE);
|
|
|
|
SpMemFree(DriveLayout);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpMasterBootCode(
|
|
IN ULONG DiskNumber,
|
|
IN HANDLE Partition0Handle,
|
|
OUT PULONG NewNTFTSignature
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG BytesPerSector;
|
|
PUCHAR Buffer;
|
|
ULONG SectorCount;
|
|
PON_DISK_MBR Mbr;
|
|
|
|
BytesPerSector = HardDisks[DiskNumber].Geometry.BytesPerSector;
|
|
|
|
SectorCount = max(1,sizeof(ON_DISK_MBR)/BytesPerSector);
|
|
|
|
*NewNTFTSignature = 0;
|
|
|
|
//
|
|
// Allocate and align a buffer.
|
|
//
|
|
Buffer = SpMemAlloc(2 * SectorCount * BytesPerSector);
|
|
Mbr = ALIGN(Buffer,BytesPerSector);
|
|
|
|
//
|
|
// Read sector 0 (or 1, for EZDrive)
|
|
//
|
|
Status = SpReadWriteDiskSectors(
|
|
Partition0Handle,
|
|
HardDisks[DiskNumber].EZDrive ? 1 : 0,
|
|
SectorCount,
|
|
BytesPerSector,
|
|
Mbr,
|
|
FALSE
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// If it's valid, leave it alone.
|
|
// If it's not valid, put in boot code, zero out the partition table,
|
|
// and write the (now valid) sector back out.
|
|
//
|
|
if(U_USHORT(Mbr->AA55Signature) != MBR_SIGNATURE) {
|
|
|
|
ASSERT(X86BOOTCODE_SIZE == sizeof(ON_DISK_MBR));
|
|
|
|
RtlMoveMemory(Mbr,x86BootCode,X86BOOTCODE_SIZE);
|
|
|
|
*NewNTFTSignature = SpComputeSerialNumber();
|
|
U_ULONG(Mbr->NTFTSignature) = *NewNTFTSignature;
|
|
|
|
U_USHORT(Mbr->AA55Signature) = MBR_SIGNATURE;
|
|
|
|
//
|
|
// Write the sector(s).
|
|
//
|
|
Status = SpReadWriteDiskSectors(
|
|
Partition0Handle,
|
|
HardDisks[DiskNumber].EZDrive ? 1 : 0,
|
|
SectorCount,
|
|
BytesPerSector,
|
|
Mbr,
|
|
TRUE
|
|
);
|
|
}
|
|
}
|
|
|
|
SpMemFree(Buffer);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpPtGetSectorLayoutInformation(
|
|
IN PDISK_REGION Region,
|
|
OUT PULONG HiddenSectors,
|
|
OUT PULONG VolumeSectorCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a region describing a partition or logical drive, return information
|
|
about its layout on disk appropriate for the BPB when the volume is
|
|
formatted.
|
|
|
|
Arguments:
|
|
|
|
Region - supplies a pointer to the disk region descriptor for the
|
|
partition or logical drive in question.
|
|
|
|
HiidenSectors - receives the value that should be placed in the
|
|
hidden sectors field of the BPB when the volume is formatted.
|
|
|
|
HiidenSectors - receives the value that should be placed in the
|
|
sector count field of the BPB when the volume is formatted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PON_DISK_PTE pte;
|
|
|
|
ASSERT(Region->PartitionedSpace);
|
|
|
|
pte = &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition];
|
|
|
|
*HiddenSectors = U_ULONG(pte->RelativeSectors);
|
|
|
|
*VolumeSectorCount = U_ULONG(pte->SectorCount);
|
|
}
|
|
|
|
|
|
ULONG
|
|
SpPtGetOrdinal(
|
|
IN PDISK_REGION Region,
|
|
IN PartitionOrdinalType OrdinalType
|
|
)
|
|
{
|
|
ULONG ord;
|
|
|
|
switch(OrdinalType) {
|
|
|
|
case PartitionOrdinalOriginal:
|
|
|
|
ord = Region->MbrInfo->OriginalOrdinals[Region->TablePosition];
|
|
break;
|
|
|
|
case PartitionOrdinalOnDisk:
|
|
|
|
ord = Region->MbrInfo->OnDiskOrdinals[Region->TablePosition];
|
|
break;
|
|
|
|
case PartitionOrdinalCurrent:
|
|
|
|
ord = Region->MbrInfo->CurrentOrdinals[Region->TablePosition];
|
|
break;
|
|
}
|
|
|
|
return(ord);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
VOID
|
|
SpPtDoDelete(
|
|
IN PDISK_REGION pRegion,
|
|
IN PWSTR RegionDescription
|
|
);
|
|
|
|
#define MENU_LEFT_X 3
|
|
#define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
|
|
#define MENU_INDENT 4
|
|
|
|
BOOLEAN
|
|
SpPtRegionDescription(
|
|
IN PPARTITIONED_DISK pDisk,
|
|
IN PDISK_REGION pRegion,
|
|
OUT PWCHAR Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
{
|
|
WCHAR DriveLetter[3];
|
|
ULONG RegionSizeMB;
|
|
ULONG FreeSpace;
|
|
ULONG MessageId;
|
|
WCHAR TypeName[((sizeof(pRegion->TypeName)+sizeof(pRegion->VolumeLabel))/sizeof(WCHAR))+4];
|
|
#ifdef _FASTRECOVER_
|
|
ULONG RequiredKB;
|
|
ULONG RequiredMB;
|
|
#endif
|
|
|
|
//
|
|
// Get the size of the region.
|
|
//
|
|
RegionSizeMB = SpPtSectorCountToMB(pDisk->HardDisk, pRegion->SectorCount);
|
|
|
|
//
|
|
// Don't show spaces smaller than 1 MB.
|
|
//
|
|
if(!RegionSizeMB) {
|
|
return(FALSE);
|
|
}
|
|
|
|
#ifdef _FASTRECOVER_
|
|
if (!LocalSourceRegion)
|
|
{
|
|
SpFetchDiskSpaceRequirements(UnattendedSifHandle,&RequiredKB,NULL);
|
|
RequiredMB = RequiredKB / 1024;
|
|
|
|
if (pRegion->PartitionedSpace)
|
|
{
|
|
if (pRegion->Filesystem != FilesystemUnknown)
|
|
{
|
|
if ((pRegion->FreeSpaceKB == (ULONG)(-1) && RequiredMB <= RegionSizeMB) ||
|
|
(RequiredMB <= (pRegion->FreeSpaceKB / 1024)))
|
|
LocalSourceRegion = pRegion;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RequiredMB <= RegionSizeMB)
|
|
LocalSourceRegion = pRegion;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Get the drive letter field, type of region, and amount of free space,
|
|
// if this is a used region.
|
|
//
|
|
if(pRegion->PartitionedSpace) {
|
|
|
|
if(pRegion->DriveLetter) {
|
|
if( pRegion->Filesystem != FilesystemFat ) {
|
|
DriveLetter[0] = pRegion->DriveLetter;
|
|
} else {
|
|
if( pRegion->NextCompressed == NULL ) {
|
|
DriveLetter[0] = pRegion->DriveLetter;
|
|
} else {
|
|
DriveLetter[0] = pRegion->HostDrive;
|
|
}
|
|
}
|
|
DriveLetter[1] = L':';
|
|
} else {
|
|
if( pRegion->Filesystem != FilesystemDoubleSpace ) {
|
|
DriveLetter[0] = L'-';
|
|
DriveLetter[1] = L'-';
|
|
} else {
|
|
DriveLetter[0] = pRegion->MountDrive;
|
|
DriveLetter[1] = L':';
|
|
}
|
|
}
|
|
DriveLetter[2] = 0;
|
|
|
|
//
|
|
// Format the type name, which may include the volume label.
|
|
//
|
|
wcscpy(TypeName,pRegion->TypeName);
|
|
if(pRegion->VolumeLabel[0]) {
|
|
wcscat(TypeName,L" (");
|
|
wcscat(TypeName,pRegion->VolumeLabel);
|
|
wcscat(TypeName,L")");
|
|
}
|
|
|
|
//
|
|
// Format the text based on whether we know the amount of free space.
|
|
//
|
|
if(pRegion->FreeSpaceKB == (ULONG)(-1)) {
|
|
|
|
SpFormatMessage(
|
|
Buffer,
|
|
BufferSize,
|
|
SP_TEXT_REGION_DESCR_2,
|
|
DriveLetter,
|
|
SplangPadString(-35,TypeName),
|
|
RegionSizeMB
|
|
);
|
|
|
|
} else {
|
|
ULONG AuxFreeSpaceKB;
|
|
|
|
AuxFreeSpaceKB = (pRegion->IsLocalSource)? pRegion->AdjustedFreeSpaceKB :
|
|
pRegion->FreeSpaceKB;
|
|
|
|
//
|
|
// If there is less than 1 meg of free space,
|
|
// then use KB as the units for free space.
|
|
// Otherwise, use MB.
|
|
//
|
|
if(AuxFreeSpaceKB < 1024) {
|
|
MessageId = SP_TEXT_REGION_DESCR_1a;
|
|
FreeSpace = AuxFreeSpaceKB;
|
|
} else {
|
|
MessageId = SP_TEXT_REGION_DESCR_1;
|
|
FreeSpace = AuxFreeSpaceKB / 1024;
|
|
}
|
|
|
|
SpFormatMessage(
|
|
Buffer,
|
|
BufferSize,
|
|
MessageId,
|
|
DriveLetter,
|
|
SplangPadString(-35,TypeName),
|
|
RegionSizeMB,
|
|
FreeSpace
|
|
);
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Not a used region, use a separate format string.
|
|
//
|
|
SpFormatMessage(Buffer,BufferSize,SP_TEXT_REGION_DESCR_3,RegionSizeMB);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpPtIterateRegionList(
|
|
IN PVOID Menu,
|
|
IN PPARTITIONED_DISK pDisk,
|
|
IN PDISK_REGION pRegion,
|
|
IN BOOLEAN InMbr,
|
|
OUT PDISK_REGION *FirstRegion
|
|
)
|
|
{
|
|
WCHAR Buffer[256];
|
|
#ifdef FULL_DOUBLE_SPACE_SUPPORT
|
|
PDISK_REGION Pointer;
|
|
#endif // FULL_DOUBLE_SPACE_SUPPORT
|
|
|
|
for( ;pRegion; pRegion=pRegion->Next) {
|
|
|
|
PMBR_INFO pBrInfo = pRegion->MbrInfo;
|
|
|
|
//
|
|
// If this is the extended partition,
|
|
// iterate its contents now.
|
|
//
|
|
if(pRegion->PartitionedSpace
|
|
&& IsContainerPartition(pBrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId))
|
|
{
|
|
//
|
|
// This better be in the MBR!
|
|
//
|
|
ASSERT(InMbr);
|
|
|
|
if(!SpPtIterateRegionList(Menu,pDisk,pDisk->ExtendedDiskRegions,FALSE,FirstRegion)) {
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Format a description of this region and add it to the menu.
|
|
//
|
|
if(SpPtRegionDescription(pDisk,pRegion,Buffer,sizeof(Buffer))) {
|
|
|
|
if(*FirstRegion == NULL) {
|
|
*FirstRegion = pRegion;
|
|
}
|
|
|
|
if(!SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),TRUE,(ULONG)pRegion)) {
|
|
return(FALSE);
|
|
}
|
|
#ifdef FULL_DOUBLE_SPACE_SUPPORT
|
|
if( ( pRegion->Filesystem == FilesystemFat ) &&
|
|
( ( Pointer = pRegion->NextCompressed ) != NULL ) ) {
|
|
for( ; Pointer;
|
|
Pointer = Pointer->NextCompressed ) {
|
|
if(SpPtRegionDescription(pDisk,Pointer,Buffer,sizeof(Buffer))) {
|
|
if(!SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),TRUE,(ULONG)Pointer)) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // FULL_DOUBLE_SPACE_SUPPORT
|
|
}
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpPtGenerateMenu(
|
|
IN PVOID Menu,
|
|
IN PPARTITIONED_DISK pDisk,
|
|
OUT PDISK_REGION *FirstRegion
|
|
)
|
|
{
|
|
WCHAR Buffer[256];
|
|
|
|
//
|
|
// Add the disk name/description.
|
|
//
|
|
if(!SpMnAddItem(Menu,pDisk->HardDisk->Description,MENU_LEFT_X,MENU_WIDTH,FALSE,0)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Only add a line between the disk anme 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(pDisk->HardDisk->Status == DiskOffLine) {
|
|
|
|
SpFormatMessage(
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)
|
|
? SP_TEXT_HARD_DISK_NO_MEDIA
|
|
: SP_TEXT_DISK_OFF_LINE
|
|
);
|
|
|
|
return(SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),FALSE,0));
|
|
}
|
|
|
|
if(!SpPtIterateRegionList(Menu,pDisk,pDisk->PrimaryDiskRegions,TRUE,FirstRegion)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(SplangQueryMinimizeExtraSpacing() ? TRUE : SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0));
|
|
}
|
|
|
|
|
|
//
|
|
// We will change item #0 in the array below as appropriate for
|
|
// the currently highlighted region.
|
|
//
|
|
ULONG PartitionMnemonics[2] = { 0,0 };
|
|
|
|
VOID
|
|
SpPtMenuCallback(
|
|
IN ULONG UserData
|
|
)
|
|
{
|
|
PDISK_REGION pRegion = (PDISK_REGION)UserData;
|
|
|
|
//
|
|
// Don't allow deletion of the partition if the 'partition' is really
|
|
// a DoubleSpace drive, if it contains the local source, or if it is our
|
|
// system partition (in the floppyless boot case on x86).
|
|
//
|
|
|
|
if((pRegion->Filesystem == FilesystemDoubleSpace) || pRegion->IsLocalSource
|
|
#ifdef _X86_
|
|
|| (IsFloppylessBoot &&
|
|
pRegion == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))
|
|
#endif
|
|
) {
|
|
|
|
PartitionMnemonics[0] = 0;
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_INSTALL,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
} else {
|
|
|
|
PartitionMnemonics[0] = pRegion->PartitionedSpace
|
|
? MnemonicDeletePartition
|
|
: MnemonicCreatePartition;
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_INSTALL,
|
|
pRegion->PartitionedSpace ? SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpPtPrepareDisks(
|
|
IN PVOID SifHandle,
|
|
OUT PDISK_REGION *InstallRegion,
|
|
OUT PDISK_REGION *SystemPartitionRegion,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSetupSource
|
|
)
|
|
{
|
|
PPARTITIONED_DISK pDisk;
|
|
ULONG DiskNo;
|
|
PVOID Menu;
|
|
ULONG MenuTopY;
|
|
ULONG ValidKeys[4] = { ASCI_CR, KEY_F1, KEY_F3, 0 };
|
|
ULONG Keypress;
|
|
PDISK_REGION pRegion;
|
|
PDISK_REGION FirstRegion,DefaultRegion;
|
|
BOOLEAN unattended;
|
|
|
|
#ifndef _X86_
|
|
//
|
|
// Select a system partition from among those defined in NV-RAM.
|
|
//
|
|
*SystemPartitionRegion = SpPtValidSystemPartition(SifHandle);
|
|
(*SystemPartitionRegion)->IsSystemPartition = 2;
|
|
#endif
|
|
|
|
unattended = UnattendedOperation;
|
|
|
|
while(1) {
|
|
|
|
//
|
|
// Display the text that goes above the menu on the partitioning screen.
|
|
//
|
|
SpDisplayScreen(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) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Build up a menu of partitions and free spaces.
|
|
//
|
|
FirstRegion = NULL;
|
|
for(DiskNo=0; DiskNo<HardDiskCount; DiskNo++) {
|
|
|
|
pDisk = &PartitionedDisks[DiskNo];
|
|
|
|
if(!SpPtGenerateMenu(Menu,pDisk,&FirstRegion)) {
|
|
|
|
SpMnDestroy(Menu);
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
}
|
|
|
|
ASSERT(FirstRegion);
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//wfc
|
|
// If this option is set to allow for partitioning interaction,
|
|
// put this logic into attended mode operation for duration of
|
|
// the partitioning screens. In addition, if LocalSourceRegion is
|
|
// not assigned in fast recover unattended mode, then also jump into
|
|
// attended mode operation.
|
|
//
|
|
if (UnattendedPartitionInteract || !LocalSourceRegion)
|
|
unattended = FALSE;
|
|
#endif
|
|
|
|
//
|
|
// If this is unattended operation, try to use the local source
|
|
// region. If this fails, the user will have to intervene manually.
|
|
//
|
|
if(unattended) {
|
|
ASSERT(LocalSourceRegion);
|
|
|
|
pRegion = LocalSourceRegion;
|
|
Keypress = ASCI_CR;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If there is a local source, make it the default partition.
|
|
//
|
|
DefaultRegion = LocalSourceRegion ? LocalSourceRegion : FirstRegion;
|
|
|
|
//
|
|
// Call the menu callback to initialize the status line.
|
|
//
|
|
SpPtMenuCallback((ULONG)DefaultRegion);
|
|
|
|
SpMnDisplay(
|
|
Menu,
|
|
(ULONG)DefaultRegion,
|
|
TRUE,
|
|
ValidKeys,
|
|
PartitionMnemonics,
|
|
SpPtMenuCallback,
|
|
&Keypress,
|
|
(PULONG)(&pRegion)
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now act on the user's selection.
|
|
//
|
|
if(Keypress & KEY_MNEMONIC) {
|
|
Keypress &= ~KEY_MNEMONIC;
|
|
}
|
|
|
|
switch(Keypress) {
|
|
|
|
case MnemonicCreatePartition:
|
|
|
|
SpPtDoCreate(pRegion,NULL,FALSE);
|
|
break;
|
|
|
|
case MnemonicDeletePartition:
|
|
|
|
SpPtDoDelete(pRegion,SpMnGetText(Menu,(ULONG)pRegion));
|
|
break;
|
|
|
|
case KEY_F1:
|
|
SpHelp(SP_HELP_FDISK, NULL, SPHELP_HELPTEXT);
|
|
break;
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
case ASCI_CR:
|
|
|
|
if(SpPtDoPartitionSelection(&pRegion,
|
|
SpMnGetText(Menu,(ULONG)pRegion),
|
|
SifHandle,
|
|
unattended,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource)) {
|
|
//
|
|
// We're done here.
|
|
//
|
|
SpMnDestroy(Menu);
|
|
*InstallRegion = pRegion;
|
|
#ifdef _X86_
|
|
*SystemPartitionRegion = SpPtValidSystemPartition();
|
|
ASSERT(*SystemPartitionRegion);
|
|
#else
|
|
//
|
|
// 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.
|
|
// Note that SpPtValidSystemPartition(SifHandle) will not return if
|
|
// a valid system partition is not found.
|
|
//
|
|
*SystemPartitionRegion = SpPtValidSystemPartition(SifHandle);
|
|
ASSERT(*SystemPartitionRegion);
|
|
#endif
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
break;
|
|
}
|
|
|
|
SpMnDestroy(Menu);
|
|
unattended = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SpPtDoDelete(
|
|
IN PDISK_REGION pRegion,
|
|
IN PWSTR RegionDescription
|
|
)
|
|
{
|
|
ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; // do not change order
|
|
ULONG Mnemonics[2] = { MnemonicDeletePartition2, 0 };
|
|
ULONG k;
|
|
BOOLEAN b;
|
|
PPARTITIONED_DISK pDisk;
|
|
BOOLEAN LastLogical;
|
|
ULONG Count;
|
|
|
|
//
|
|
// Special warning if this is a system partition.
|
|
//
|
|
if(pRegion->IsSystemPartition) {
|
|
|
|
SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_SYSPART,3,HEADER_HEIGHT+1);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
0
|
|
);
|
|
|
|
if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// CR is no longer a valid key.
|
|
//
|
|
ValidKeys[1] = 0;
|
|
|
|
pDisk = &PartitionedDisks[pRegion->DiskNumber];
|
|
|
|
//
|
|
// Put up the confirmation screen.
|
|
//
|
|
if( ( pRegion->Filesystem == FilesystemFat ) &&
|
|
( pRegion->NextCompressed != NULL ) ) {
|
|
//
|
|
// Warn the user that the partition contains compressed volumes
|
|
//
|
|
|
|
Count = SpGetNumberOfCompressedDrives( pRegion );
|
|
|
|
SpStartScreen(
|
|
SP_SCRN_CONFIRM_REMOVE_PARTITION_COMPRESSED,
|
|
3,
|
|
CLIENT_TOP+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
RegionDescription,
|
|
pDisk->HardDisk->Description,
|
|
Count
|
|
);
|
|
} else {
|
|
|
|
SpStartScreen(
|
|
SP_SCRN_CONFIRM_REMOVE_PARTITION,
|
|
3,
|
|
CLIENT_TOP+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
RegionDescription,
|
|
pDisk->HardDisk->Description
|
|
);
|
|
}
|
|
|
|
//
|
|
// Display the staus text.
|
|
//
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_L_EQUALS_DELETE,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
0
|
|
);
|
|
|
|
k = SpWaitValidKey(ValidKeys,NULL,Mnemonics);
|
|
|
|
if(k == ASCI_ESC) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// User wants to go ahead.
|
|
// Determine whether this is the last logical drive in the
|
|
// extended partition.
|
|
//
|
|
if((pRegion->MbrInfo == pDisk->FirstEbrInfo.Next)
|
|
&& (pDisk->FirstEbrInfo.Next->Next == NULL))
|
|
{
|
|
LastLogical = TRUE;
|
|
} else {
|
|
LastLogical = FALSE;
|
|
}
|
|
//
|
|
// Get rid of the compressed drives, if any
|
|
//
|
|
if( pRegion->NextCompressed != NULL ) {
|
|
SpDisposeCompressedDrives( pRegion->NextCompressed );
|
|
pRegion->NextCompressed = NULL;
|
|
pRegion->MountDrive = 0;
|
|
pRegion->HostDrive = 0;
|
|
}
|
|
|
|
b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
|
|
|
|
ASSERT(b);
|
|
|
|
//
|
|
// If we deleted the last logical drive in the extended partition,
|
|
// then remove the extended partition also.
|
|
//
|
|
if(LastLogical) {
|
|
|
|
//
|
|
// Locate the extended partition.
|
|
//
|
|
for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
|
|
if(pRegion->PartitionedSpace
|
|
&& IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId))
|
|
{
|
|
//
|
|
// Found it -- now delete it.
|
|
//
|
|
b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
|
|
ASSERT(b);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ValidationValue
|
|
SpPtGetSizeCB(
|
|
IN ULONG Key
|
|
)
|
|
{
|
|
if(Key == ASCI_ESC) {
|
|
//
|
|
// User wants to bail.
|
|
//
|
|
return(ValidateTerminate);
|
|
}
|
|
|
|
|
|
if(Key & KEY_NON_CHARACTER) {
|
|
return(ValidateIgnore);
|
|
}
|
|
|
|
//
|
|
// Allow only digits.
|
|
//
|
|
return(((Key >= L'0') && (Key <= L'9')) ? ValidateAccept : ValidateReject);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpPtDoCreate(
|
|
IN PDISK_REGION pRegion,
|
|
OUT PDISK_REGION *pActualRegion, OPTIONAL
|
|
IN BOOLEAN ForNT
|
|
)
|
|
{
|
|
ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 };
|
|
BOOLEAN b;
|
|
PPARTITIONED_DISK pDisk;
|
|
ULONG MinMB,MaxMB;
|
|
ULONG TotalPrimary,RecogPrimary;
|
|
BOOLEAN InExtended;
|
|
UCHAR CreateSysId;
|
|
BOOLEAN ExtendedExists;
|
|
ULONG SizeMB,RealSizeMB;
|
|
WCHAR Buffer[200];
|
|
WCHAR SizeBuffer[10];
|
|
|
|
ASSERT(!pRegion->PartitionedSpace);
|
|
|
|
pDisk = &PartitionedDisks[pRegion->DiskNumber];
|
|
|
|
//
|
|
// Determine whether this space is within the extended partition.
|
|
//
|
|
InExtended = (BOOLEAN)(SpPtLookupRegionByStart(pDisk,TRUE,pRegion->StartSector) != NULL);
|
|
|
|
//
|
|
// Determine the type of partition to create in the space.
|
|
//
|
|
// If the free space is within the extended partition, create
|
|
// a logical drive.
|
|
//
|
|
// If there is no primary partition, create a primary partition.
|
|
//
|
|
// If there is a primary partition and no extended partition,
|
|
// create an extended partition spanning the entire space and
|
|
// then a logical drive within it of the size given by the user.
|
|
//
|
|
// If there is space in the partition table, create a primary partition.
|
|
//
|
|
if(InExtended) {
|
|
|
|
CreateSysId = PARTITION_HUGE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Get statistics about primary partitions.
|
|
//
|
|
SpPtCountPrimaryPartitions(pDisk,&TotalPrimary,&RecogPrimary,&ExtendedExists);
|
|
|
|
//
|
|
// If there is no primary partition, create one.
|
|
//
|
|
if(!RecogPrimary) {
|
|
|
|
CreateSysId = PARTITION_HUGE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Make sure we can create a new primary/extended partition.
|
|
//
|
|
if(TotalPrimary < PTABLE_DIMENSION) {
|
|
|
|
//
|
|
// If there is an extended partition, then we have no choice but
|
|
// to create another primary.
|
|
//
|
|
CreateSysId = ExtendedExists ? PARTITION_HUGE : PARTITION_EXTENDED;
|
|
|
|
} else {
|
|
|
|
while(1) {
|
|
|
|
ULONG ks[3] = { KEY_F1,ASCI_CR,0 };
|
|
|
|
SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,3,CLIENT_HEIGHT+1);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
0
|
|
);
|
|
|
|
switch(SpWaitValidKey(ks,NULL,NULL)) {
|
|
case ASCI_CR:
|
|
return(FALSE);
|
|
case KEY_F1:
|
|
SpHelp(SP_HELP_PARTITION_TABLE_FULL, NULL, SPHELP_HELPTEXT);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the mimimum and maximum sizes for the partition.
|
|
//
|
|
SpPtQueryMinMaxCreationSizeMB(
|
|
pRegion->DiskNumber,
|
|
pRegion->StartSector,
|
|
(BOOLEAN)IsContainerPartition(CreateSysId),
|
|
InExtended,
|
|
&MinMB,
|
|
&MaxMB
|
|
);
|
|
|
|
if(ForNT) {
|
|
|
|
SizeMB = MaxMB;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Put up a screen displaying min/max size info.
|
|
//
|
|
SpStartScreen(
|
|
SP_SCRN_CONFIRM_CREATE_PARTITION,
|
|
3,
|
|
CLIENT_TOP+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
pDisk->HardDisk->Description,
|
|
MinMB,
|
|
MaxMB
|
|
);
|
|
|
|
//
|
|
// Display the staus text.
|
|
//
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CREATE,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Get and display the size prompt.
|
|
//
|
|
SpFormatMessage(Buffer,sizeof(Buffer),SP_TEXT_SIZE_PROMPT);
|
|
|
|
SpvidDisplayString(Buffer,DEFAULT_ATTRIBUTE,3,NextMessageTopLine);
|
|
|
|
//
|
|
// Get the size from the user.
|
|
//
|
|
do {
|
|
|
|
swprintf(SizeBuffer,L"%u",MaxMB);
|
|
if(!SpGetInput(SpPtGetSizeCB,SplangGetColumnCount(Buffer)+5,NextMessageTopLine,5,SizeBuffer,TRUE)) {
|
|
|
|
//
|
|
// User pressed escape and bailed.
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
SizeMB = (ULONG)SpStringToLong(SizeBuffer,NULL,10);
|
|
|
|
} while((SizeMB < MinMB) || (SizeMB > MaxMB));
|
|
}
|
|
|
|
if(IsContainerPartition(CreateSysId)) {
|
|
RealSizeMB = SizeMB;
|
|
SizeMB = MaxMB;
|
|
}
|
|
|
|
//
|
|
// Create the partition.
|
|
//
|
|
b = SpPtCreate(
|
|
pRegion->DiskNumber,
|
|
pRegion->StartSector,
|
|
SizeMB,
|
|
InExtended,
|
|
CreateSysId,
|
|
pActualRegion
|
|
);
|
|
|
|
ASSERT(b);
|
|
|
|
//
|
|
// Create the logical drive if we just created the extended partition.
|
|
//
|
|
if(IsContainerPartition(CreateSysId)) {
|
|
|
|
ASSERT(!InExtended);
|
|
|
|
b = SpPtCreate(
|
|
pRegion->DiskNumber,
|
|
pRegion->StartSector,
|
|
RealSizeMB,
|
|
TRUE,
|
|
PARTITION_HUGE,
|
|
pActualRegion
|
|
);
|
|
|
|
ASSERT(b);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// The following table contains offsets from SP_TEXT_PARTITION_NAME_BASE
|
|
// to get the message id of the name of each type of partition.
|
|
// A -1 entry means there is no name in the message file for this type
|
|
// of partition or that the filesystem should be determined instead.
|
|
//
|
|
//
|
|
#define PT(id) ((UCHAR)((SP_TEXT_PARTITION_NAME_##id)-SP_TEXT_PARTITION_NAME_BASE))
|
|
#define UNKNOWN PT(UNK)
|
|
#define M1 ((UCHAR)(-1))
|
|
|
|
UCHAR PartitionNameIds[256] = {
|
|
|
|
M1,M1,PT(XENIX),PT(XENIX), // 00-03
|
|
M1,M1,M1,M1, // 04-07
|
|
UNKNOWN,UNKNOWN,PT(BOOTMANAGER),PT(FAT32), // 08-0b
|
|
PT(FAT32),UNKNOWN,M1,M1, // 0c-0f
|
|
UNKNOWN,UNKNOWN,PT(EISA),UNKNOWN, // 10-13
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 14-17
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 18-1b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 1c-1f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 20-23
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 24-27
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 28-2b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 2c-2f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 30-33
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 34-37
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 38-3b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 3c-3f
|
|
UNKNOWN,PT(PPCBOOT),UNKNOWN,UNKNOWN, // 40-43
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 44-47
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 48-4b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 4c-4f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 50-53
|
|
UNKNOWN,PT(EZDRIVE),UNKNOWN,UNKNOWN, // 54-57
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 58-5b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 5c-5f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,PT(UNIX), // 60-63
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 64-67
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 68-6b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 6c-6f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 70-73
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 74-77
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 78-7b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 7c-7f
|
|
UNKNOWN,PT(NTFT),UNKNOWN,UNKNOWN, // 80-83
|
|
PT(NTFT),UNKNOWN,PT(NTFT),PT(NTFT), // 84-87
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 88-8b
|
|
UNKNOWN,UNKNOWN,PT(NTFT),UNKNOWN, // 8c-8f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 90-93
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 94-97
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 98-9b
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 9c-9f
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a0-a3
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a4-a7
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a8-ab
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // ac-af
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b0-b3
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b4-b7
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b8-bb
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // bc-bf
|
|
UNKNOWN,PT(NTFT),UNKNOWN,UNKNOWN, // c0-c3
|
|
PT(NTFT),UNKNOWN,PT(NTFT),PT(NTFT), // c4-c7
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // c8-cb
|
|
UNKNOWN,UNKNOWN,PT(NTFT),UNKNOWN, // cc-cf
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d0-d3
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d4-d7
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d8-db
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // dc-df
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e0-e3
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e4-e7
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e8-eb
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // ec-ef
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f0-f3
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f4-f7
|
|
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f8-fb
|
|
UNKNOWN,UNKNOWN,UNKNOWN,PT(XENIXTABLE) // fc-ff
|
|
};
|
|
|
|
|
|
|
|
VOID
|
|
SpPtGuessDriveLetters(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG disk;
|
|
PPARTITIONED_DISK pDisk;
|
|
PDISK_REGION *Sort;
|
|
PON_DISK_PTE pte;
|
|
ULONG ActiveIndex;
|
|
UCHAR SysId;
|
|
WCHAR dlet;
|
|
PDISK_REGION pRegion;
|
|
ULONG i;
|
|
|
|
|
|
//
|
|
// Initialize all drive letters to nothing.
|
|
//
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
for(pRegion=PartitionedDisks[disk].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
pRegion->DriveLetter = 0;
|
|
}
|
|
for(pRegion=PartitionedDisks[disk].ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
pRegion->DriveLetter = 0;
|
|
}
|
|
}
|
|
|
|
Sort = SpMemAlloc(PTABLE_DIMENSION * HardDiskCount * sizeof(PDISK_REGION));
|
|
if(!Sort) {
|
|
KdPrint(("SETUP: Can't allocate memory for drive letter assignment\n"));
|
|
return;
|
|
}
|
|
RtlZeroMemory(Sort,PTABLE_DIMENSION * HardDiskCount * sizeof(PDISK_REGION));
|
|
|
|
dlet = L'C';
|
|
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
pDisk = &PartitionedDisks[disk];
|
|
ActiveIndex = (ULONG)(-1);
|
|
|
|
//
|
|
// Skip removable media. If a disk is off-line it's hard to imagine
|
|
// that we'll actually have any partitioned spaces on it so
|
|
// we don't do any special checks here for that condition.
|
|
//
|
|
if(!(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)) {
|
|
|
|
for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
|
|
if(pRegion->PartitionedSpace) {
|
|
|
|
pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
|
|
SysId = pte->SystemId;
|
|
|
|
if(!IsContainerPartition(SysId) && (PartitionNameIds[SysId] == (UCHAR)(-1))) {
|
|
|
|
//
|
|
// This guy gets a drive letter.
|
|
//
|
|
ASSERT(pRegion->TablePosition < PTABLE_DIMENSION);
|
|
Sort[(disk*PTABLE_DIMENSION) + pRegion->TablePosition] = pRegion;
|
|
|
|
if(pte->ActiveFlag && (ActiveIndex != (ULONG)(-1))) {
|
|
ActiveIndex = pRegion->TablePosition;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we found an active partition, shove it to the start of
|
|
// the list for this drive unless it's already at the start.
|
|
//
|
|
if((ActiveIndex != (ULONG)(-1)) && ActiveIndex) {
|
|
|
|
PDISK_REGION p;
|
|
|
|
ASSERT(ActiveIndex < PTABLE_DIMENSION);
|
|
|
|
p = Sort[(disk*PTABLE_DIMENSION)+ActiveIndex];
|
|
|
|
RtlMoveMemory(
|
|
&Sort[(disk*PTABLE_DIMENSION)+1],
|
|
&Sort[(disk*PTABLE_DIMENSION)],
|
|
ActiveIndex * sizeof(PDISK_REGION)
|
|
);
|
|
|
|
Sort[disk*PTABLE_DIMENSION] = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now assign drive letters to the first primary partitions
|
|
// for each non-removable on-line disk.
|
|
//
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
if(Sort[(disk*PTABLE_DIMENSION)+i]) {
|
|
|
|
Sort[(disk*PTABLE_DIMENSION)+i]->DriveLetter = dlet++;
|
|
Sort[(disk*PTABLE_DIMENSION)+i] = NULL;
|
|
if(dlet > L'Z') {
|
|
goto dletdone;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// For each disk, assign drive letters to all the logical drives.
|
|
// For removable drives, we assume a single partition, and that
|
|
// partition gets a drive letter as if it were a logical drive.
|
|
//
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
pDisk = &PartitionedDisks[disk];
|
|
|
|
if(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) {
|
|
|
|
//
|
|
// Give the first primary partition the drive letter
|
|
// and ignore other partitions. Even if there are no
|
|
// partitions, reserve a drive letter.
|
|
//
|
|
for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
|
|
if(pRegion->PartitionedSpace) {
|
|
|
|
pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
|
|
SysId = pte->SystemId;
|
|
|
|
if(!IsContainerPartition(SysId) && (PartitionNameIds[SysId] == (UCHAR)(-1))) {
|
|
pRegion->DriveLetter = dlet;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
dlet++;
|
|
if(dlet > L'Z') {
|
|
goto dletdone;
|
|
}
|
|
|
|
} else {
|
|
for(pRegion=pDisk->ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) {
|
|
|
|
if(pRegion->PartitionedSpace) {
|
|
|
|
pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
|
|
SysId = pte->SystemId;
|
|
|
|
if(!IsContainerPartition(SysId) && (PartitionNameIds[SysId] == (UCHAR)(-1))) {
|
|
|
|
//
|
|
// This guy gets a drive letter.
|
|
//
|
|
pRegion->DriveLetter = dlet++;
|
|
if(dlet > L'Z') {
|
|
goto dletdone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// For each non-removable on-line disk, assign drive letters
|
|
// to all remaining primary partitions.
|
|
//
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
for(i=0; i<PTABLE_DIMENSION; i++) {
|
|
|
|
if(Sort[(disk*PTABLE_DIMENSION)+i]) {
|
|
|
|
Sort[(disk*PTABLE_DIMENSION)+i]->DriveLetter = dlet++;
|
|
if(dlet > L'Z') {
|
|
goto dletdone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
dletdone:
|
|
|
|
SpMemFree(Sort);
|
|
}
|