mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
3715 lines
118 KiB
C
3715 lines
118 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS text-mode setup
|
|
* FILE: base/setup/usetup/partlist.c
|
|
* PURPOSE: Partition list functions
|
|
* PROGRAMMER: Eric Kohl
|
|
* Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
*/
|
|
|
|
#include "usetup.h"
|
|
|
|
#include <ntddscsi.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
//#define DUMP_PARTITION_TABLE
|
|
|
|
/* HELPERS FOR PARTITION TYPES **********************************************/
|
|
|
|
typedef struct _PARTITION_TYPE
|
|
{
|
|
UCHAR Type;
|
|
PCHAR Description;
|
|
} PARTITION_TYPE, *PPARTITION_TYPE;
|
|
|
|
/*
|
|
* This partition type list was ripped off the kernelDisk.c module from:
|
|
*
|
|
* Visopsys Operating System
|
|
* Copyright (C) 1998-2015 J. Andrew McLaughlin
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*
|
|
* See also https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
|
|
* and http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
|
|
* for a complete list.
|
|
*/
|
|
|
|
/* This is a table for keeping known partition type codes and descriptions */
|
|
static PARTITION_TYPE PartitionTypes[] =
|
|
{
|
|
{ 0x00, "(Empty)" },
|
|
{ 0x01, "FAT12" },
|
|
{ 0x02, "XENIX root" },
|
|
{ 0x03, "XENIX /usr" },
|
|
{ 0x04, "FAT16 (small)" },
|
|
{ 0x05, "Extended" },
|
|
{ 0x06, "FAT16" },
|
|
{ 0x07, "NTFS/HPFS/exFAT" },
|
|
{ 0x08, "OS/2 or AIX boot" },
|
|
{ 0x09, "AIX data" },
|
|
{ 0x0A, "OS/2 Boot Manager" },
|
|
{ 0x0B, "FAT32" },
|
|
{ 0x0C, "FAT32 (LBA)" },
|
|
{ 0x0E, "FAT16 (LBA)" },
|
|
{ 0x0F, "Extended (LBA)" },
|
|
{ 0x11, "Hidden FAT12" },
|
|
{ 0x12, "FAT diagnostic" },
|
|
{ 0x14, "Hidden FAT16 (small)" },
|
|
{ 0x16, "Hidden FAT16" },
|
|
{ 0x17, "Hidden HPFS or NTFS" },
|
|
{ 0x1B, "Hidden FAT32" },
|
|
{ 0x1C, "Hidden FAT32 (LBA)" },
|
|
{ 0x1E, "Hidden FAT16 (LBA)" },
|
|
{ 0x35, "JFS" },
|
|
{ 0x39, "Plan 9" },
|
|
{ 0x3C, "PartitionMagic" },
|
|
{ 0x3D, "Hidden Netware" },
|
|
{ 0x41, "PowerPC PReP" },
|
|
{ 0x42, "Win2K dynamic extended" },
|
|
{ 0x43, "Old Linux" },
|
|
{ 0x44, "GoBack" },
|
|
{ 0x4D, "QNX4.x" },
|
|
{ 0x4D, "QNX4.x 2nd" },
|
|
{ 0x4D, "QNX4.x 3rd" },
|
|
{ 0x50, "Ontrack R/O" },
|
|
{ 0x51, "Ontrack R/W or Novell" },
|
|
{ 0x52, "CP/M" },
|
|
{ 0x63, "GNU HURD or UNIX SysV" },
|
|
{ 0x64, "Netware 2" },
|
|
{ 0x65, "Netware 3/4" },
|
|
{ 0x66, "Netware SMS" },
|
|
{ 0x67, "Novell" },
|
|
{ 0x68, "Novell" },
|
|
{ 0x69, "Netware 5+" },
|
|
{ 0x7E, "Veritas VxVM public" },
|
|
{ 0x7F, "Veritas VxVM private" },
|
|
{ 0x80, "Minix" },
|
|
{ 0x81, "Linux or Minix" },
|
|
{ 0x82, "Linux swap or Solaris" },
|
|
{ 0x83, "Linux" },
|
|
{ 0x84, "Hibernation" },
|
|
{ 0x85, "Linux extended" },
|
|
{ 0x86, "HPFS or NTFS mirrored" },
|
|
{ 0x87, "HPFS or NTFS mirrored" },
|
|
{ 0x8E, "Linux LVM" },
|
|
{ 0x93, "Hidden Linux" },
|
|
{ 0x96, "CDFS/ISO-9660" },
|
|
{ 0x9F, "BSD/OS" },
|
|
{ 0xA0, "Laptop hibernation" },
|
|
{ 0xA1, "Laptop hibernation" },
|
|
{ 0xA5, "BSD, NetBSD, FreeBSD" },
|
|
{ 0xA6, "OpenBSD" },
|
|
{ 0xA7, "NeXTSTEP" },
|
|
{ 0xA8, "OS-X UFS" },
|
|
{ 0xA9, "NetBSD" },
|
|
{ 0xAB, "OS-X boot" },
|
|
{ 0xAF, "OS-X HFS" },
|
|
{ 0xB6, "NT corrupt mirror" },
|
|
{ 0xB7, "BSDI" },
|
|
{ 0xB8, "BSDI swap" },
|
|
{ 0xBE, "Solaris 8 boot" },
|
|
{ 0xBF, "Solaris x86" },
|
|
{ 0xC0, "NTFT" },
|
|
{ 0xC1, "DR-DOS FAT12" },
|
|
{ 0xC2, "Hidden Linux" },
|
|
{ 0xC3, "Hidden Linux swap" },
|
|
{ 0xC4, "DR-DOS FAT16 (small)" },
|
|
{ 0xC5, "DR-DOS Extended" },
|
|
{ 0xC6, "DR-DOS FAT16" },
|
|
{ 0xC7, "HPFS mirrored" },
|
|
{ 0xCB, "DR-DOS FAT32" },
|
|
{ 0xCC, "DR-DOS FAT32 (LBA)" },
|
|
{ 0xCE, "DR-DOS FAT16 (LBA)" },
|
|
{ 0xD0, "MDOS" },
|
|
{ 0xD1, "MDOS FAT12" },
|
|
{ 0xD4, "MDOS FAT16 (small)" },
|
|
{ 0xD5, "MDOS Extended" },
|
|
{ 0xD6, "MDOS FAT16" },
|
|
{ 0xD8, "CP/M-86" },
|
|
{ 0xDF, "BootIt EMBRM(FAT16/32)" },
|
|
{ 0xEB, "BeOS BFS" },
|
|
{ 0xEE, "EFI GPT protective" },
|
|
{ 0xEF, "EFI filesystem" },
|
|
{ 0xF0, "Linux/PA-RISC boot" },
|
|
{ 0xF2, "DOS 3.3+ second" },
|
|
{ 0xFA, "Bochs" },
|
|
{ 0xFB, "VmWare" },
|
|
{ 0xFC, "VmWare swap" },
|
|
{ 0xFD, "Linux RAID" },
|
|
{ 0xFE, "NT hidden" },
|
|
};
|
|
|
|
VOID
|
|
GetPartTypeStringFromPartitionType(
|
|
UCHAR partitionType,
|
|
PCHAR strPartType,
|
|
DWORD cchPartType)
|
|
{
|
|
/* Determine partition type */
|
|
|
|
if (IsContainerPartition(partitionType))
|
|
{
|
|
StringCchCopy(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
|
|
}
|
|
else if (partitionType == PARTITION_ENTRY_UNUSED)
|
|
{
|
|
StringCchCopy(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
|
|
}
|
|
else
|
|
{
|
|
UINT i;
|
|
|
|
/* Do the table lookup */
|
|
for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
|
|
{
|
|
if (partitionType == PartitionTypes[i].Type)
|
|
{
|
|
StringCchCopy(strPartType, cchPartType, PartitionTypes[i].Description);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* We are here because the partition type is unknown */
|
|
StringCchCopy(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
|
|
}
|
|
}
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
#ifdef DUMP_PARTITION_TABLE
|
|
static
|
|
VOID
|
|
DumpPartitionTable(
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
PPARTITION_INFORMATION PartitionInfo;
|
|
ULONG i;
|
|
|
|
DbgPrint("\n");
|
|
DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
|
|
DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
|
|
|
|
for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
|
|
{
|
|
PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
|
|
DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
|
|
i,
|
|
PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
|
|
PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
|
|
PartitionInfo->HiddenSectors,
|
|
PartitionInfo->PartitionNumber,
|
|
PartitionInfo->PartitionType,
|
|
PartitionInfo->BootIndicator ? '*': ' ',
|
|
PartitionInfo->RewritePartition ? 'Y': 'N');
|
|
}
|
|
|
|
DbgPrint("\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
ULONGLONG
|
|
AlignDown(
|
|
IN ULONGLONG Value,
|
|
IN ULONG Alignment)
|
|
{
|
|
ULONGLONG Temp;
|
|
|
|
Temp = Value / Alignment;
|
|
|
|
return Temp * Alignment;
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
AlignUp(
|
|
IN ULONGLONG Value,
|
|
IN ULONG Alignment)
|
|
{
|
|
ULONGLONG Temp, Result;
|
|
|
|
Temp = Value / Alignment;
|
|
|
|
Result = Temp * Alignment;
|
|
if (Value % Alignment)
|
|
Result += Alignment;
|
|
|
|
return Result;
|
|
}
|
|
|
|
ULONGLONG
|
|
RoundingDivide(
|
|
IN ULONGLONG Dividend,
|
|
IN ULONGLONG Divisor)
|
|
{
|
|
return (Dividend + Divisor / 2) / Divisor;
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
GetDriverName(
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
WCHAR KeyName[32];
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&DiskEntry->DriverName,
|
|
NULL);
|
|
|
|
swprintf(KeyName,
|
|
L"\\Scsi\\Scsi Port %hu",
|
|
DiskEntry->Port);
|
|
|
|
RtlZeroMemory(&QueryTable,
|
|
sizeof(QueryTable));
|
|
|
|
QueryTable[0].Name = L"Driver";
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[0].EntryContext = &DiskEntry->DriverName;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
|
|
KeyName,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
AssignDriveLetters(
|
|
PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
CHAR Letter;
|
|
|
|
Letter = 'C';
|
|
|
|
/* Assign drive letters to primary partitions */
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
|
|
|
|
Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
|
|
PartEntry->DriveLetter = 0;
|
|
|
|
if (PartEntry->IsPartitioned &&
|
|
!IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
if (IsRecognizedPartition(PartEntry->PartitionType) ||
|
|
(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
|
|
PartEntry->SectorCount.QuadPart != 0LL))
|
|
{
|
|
if (Letter <= 'Z')
|
|
{
|
|
PartEntry->DriveLetter = Letter;
|
|
Letter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
/* Assign drive letters to logical drives */
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
|
|
|
|
Entry2 = DiskEntry->LogicalPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
|
|
PartEntry->DriveLetter = 0;
|
|
|
|
if (PartEntry->IsPartitioned)
|
|
{
|
|
if (IsRecognizedPartition(PartEntry->PartitionType) ||
|
|
(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
|
|
PartEntry->SectorCount.QuadPart != 0LL))
|
|
{
|
|
if (Letter <= 'Z')
|
|
{
|
|
PartEntry->DriveLetter = Letter;
|
|
Letter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DiskIdentifierQueryRoutine(
|
|
PWSTR ValueName,
|
|
ULONG ValueType,
|
|
PVOID ValueData,
|
|
ULONG ValueLength,
|
|
PVOID Context,
|
|
PVOID EntryContext)
|
|
{
|
|
PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
|
|
UNICODE_STRING NameU;
|
|
|
|
if (ValueType == REG_SZ &&
|
|
ValueLength == 20 * sizeof(WCHAR))
|
|
{
|
|
NameU.Buffer = (PWCHAR)ValueData;
|
|
NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
|
|
RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
|
|
|
|
NameU.Buffer = (PWCHAR)ValueData + 9;
|
|
RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DiskConfigurationDataQueryRoutine(
|
|
PWSTR ValueName,
|
|
ULONG ValueType,
|
|
PVOID ValueData,
|
|
ULONG ValueLength,
|
|
PVOID Context,
|
|
PVOID EntryContext)
|
|
{
|
|
PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
|
|
PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
|
|
ULONG i;
|
|
|
|
if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
|
|
ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
|
|
|
|
/* Hm. Version and Revision are not set on Microsoft Windows XP... */
|
|
#if 0
|
|
if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
|
|
FullResourceDescriptor->PartialResourceList.Revision != 1)
|
|
return STATUS_UNSUCCESSFUL;
|
|
#endif
|
|
|
|
for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
|
|
{
|
|
if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
|
|
FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
|
|
continue;
|
|
|
|
DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
|
|
BiosDiskEntry->DiskGeometry = *DiskGeometry;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
SystemConfigurationDataQueryRoutine(
|
|
PWSTR ValueName,
|
|
ULONG ValueType,
|
|
PVOID ValueData,
|
|
ULONG ValueLength,
|
|
PVOID Context,
|
|
PVOID EntryContext)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
|
|
PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
|
|
ULONG i;
|
|
|
|
if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
|
|
ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
|
|
|
|
/* Hm. Version and Revision are not set on Microsoft Windows XP... */
|
|
#if 0
|
|
if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
|
|
FullResourceDescriptor->PartialResourceList.Revision != 1)
|
|
return STATUS_UNSUCCESSFUL;
|
|
#endif
|
|
|
|
for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
|
|
{
|
|
if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
|
|
FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
|
|
continue;
|
|
|
|
*Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0,
|
|
FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
|
|
if (*Int13Drives == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
memcpy(*Int13Drives,
|
|
&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
|
|
FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
#define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
|
|
|
|
static VOID
|
|
EnumerateBiosDiskEntries(
|
|
PPARTLIST PartList)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
|
|
WCHAR Name[120];
|
|
ULONG AdapterCount;
|
|
ULONG DiskCount;
|
|
NTSTATUS Status;
|
|
PCM_INT13_DRIVE_PARAMETER Int13Drives;
|
|
PBIOSDISKENTRY BiosDiskEntry;
|
|
|
|
memset(QueryTable, 0, sizeof(QueryTable));
|
|
|
|
QueryTable[1].Name = L"Configuration Data";
|
|
QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
|
|
Int13Drives = NULL;
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
|
|
&QueryTable[1],
|
|
(PVOID)&Int13Drives,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
AdapterCount = 0;
|
|
while (1)
|
|
{
|
|
swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
Name,
|
|
&QueryTable[2],
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
Name,
|
|
&QueryTable[2],
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
while (1)
|
|
{
|
|
swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
Name,
|
|
&QueryTable[2],
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlFreeHeap(ProcessHeap, 0, Int13Drives);
|
|
return;
|
|
}
|
|
|
|
swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
Name,
|
|
&QueryTable[2],
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
QueryTable[0].Name = L"Identifier";
|
|
QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
|
|
QueryTable[1].Name = L"Configuration Data";
|
|
QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
|
|
|
|
DiskCount = 0;
|
|
while (1)
|
|
{
|
|
BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
|
|
if (BiosDiskEntry == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
Name,
|
|
QueryTable,
|
|
(PVOID)BiosDiskEntry,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
|
|
break;
|
|
}
|
|
|
|
BiosDiskEntry->DiskNumber = DiskCount;
|
|
BiosDiskEntry->Recognized = FALSE;
|
|
|
|
if (DiskCount < Int13Drives[0].NumberDrives)
|
|
{
|
|
BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
|
|
}
|
|
|
|
InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
|
|
|
|
DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
|
|
DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
|
|
DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
|
|
DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
|
|
DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
|
|
DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
|
|
DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
|
|
DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
|
|
DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
|
|
DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
|
|
DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
|
|
|
|
DiskCount++;
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, Int13Drives);
|
|
return;
|
|
}
|
|
}
|
|
|
|
AdapterCount++;
|
|
}
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, Int13Drives);
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
AddPartitionToDisk(
|
|
ULONG DiskNumber,
|
|
PDISKENTRY DiskEntry,
|
|
ULONG PartitionIndex,
|
|
BOOLEAN LogicalPartition)
|
|
{
|
|
PPARTITION_INFORMATION PartitionInfo;
|
|
PPARTENTRY PartEntry;
|
|
|
|
PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
|
|
if (PartitionInfo->PartitionType == 0 ||
|
|
((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
|
|
return;
|
|
|
|
PartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (PartEntry == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PartEntry->DiskEntry = DiskEntry;
|
|
|
|
PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
|
|
PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
|
|
|
|
PartEntry->BootIndicator = PartitionInfo->BootIndicator;
|
|
PartEntry->PartitionType = PartitionInfo->PartitionType;
|
|
PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
|
|
|
|
PartEntry->LogicalPartition = LogicalPartition;
|
|
PartEntry->IsPartitioned = TRUE;
|
|
PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
|
|
PartEntry->PartitionIndex = PartitionIndex;
|
|
|
|
if (IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
|
|
if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
|
|
DiskEntry->ExtendedPartition = PartEntry;
|
|
}
|
|
else if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
|
|
(PartEntry->PartitionType == PARTITION_FAT_16) ||
|
|
(PartEntry->PartitionType == PARTITION_HUGE) ||
|
|
(PartEntry->PartitionType == PARTITION_XINT13) ||
|
|
(PartEntry->PartitionType == PARTITION_FAT32) ||
|
|
(PartEntry->PartitionType == PARTITION_FAT32_XINT13))
|
|
{
|
|
#if 0
|
|
if (CheckFatFormat())
|
|
{
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
}
|
|
#endif
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else if (PartEntry->PartitionType == PARTITION_EXT2)
|
|
{
|
|
#if 0
|
|
if (CheckExt2Format())
|
|
{
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
}
|
|
#endif
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else if (PartEntry->PartitionType == PARTITION_IFS)
|
|
{
|
|
#if 0
|
|
if (CheckNtfsFormat())
|
|
{
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else if (CheckHpfsFormat())
|
|
{
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
}
|
|
#endif
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->FormatState = UnknownFormat;
|
|
}
|
|
|
|
if (LogicalPartition)
|
|
InsertTailList(&DiskEntry->LogicalPartListHead,
|
|
&PartEntry->ListEntry);
|
|
else
|
|
InsertTailList(&DiskEntry->PrimaryPartListHead,
|
|
&PartEntry->ListEntry);
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
ScanForUnpartitionedDiskSpace(
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
ULONGLONG LastStartSector;
|
|
ULONGLONG LastSectorCount;
|
|
ULONGLONG LastUnusedSectorCount;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY NewPartEntry;
|
|
PLIST_ENTRY Entry;
|
|
|
|
DPRINT("ScanForUnpartitionedDiskSpace()\n");
|
|
|
|
if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
|
|
{
|
|
DPRINT1("No primary partition!\n");
|
|
|
|
/* Create a partition table that represents the empty disk */
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
InsertTailList(&DiskEntry->PrimaryPartListHead,
|
|
&NewPartEntry->ListEntry);
|
|
|
|
return;
|
|
}
|
|
|
|
/* Start partition at head 1, cylinder 0 */
|
|
LastStartSector = DiskEntry->SectorAlignment;
|
|
LastSectorCount = 0ULL;
|
|
LastUnusedSectorCount = 0ULL;
|
|
|
|
Entry = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
|
|
|
|
if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
|
|
PartEntry->SectorCount.QuadPart != 0ULL)
|
|
{
|
|
LastUnusedSectorCount =
|
|
PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
|
|
|
|
if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
|
|
LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
|
|
{
|
|
DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
|
|
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
/* Insert the table into the list */
|
|
InsertTailList(&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
|
|
LastStartSector = PartEntry->StartSector.QuadPart;
|
|
LastSectorCount = PartEntry->SectorCount.QuadPart;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
/* Check for trailing unpartitioned disk space */
|
|
if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
|
|
{
|
|
LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
|
|
|
|
if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
|
|
{
|
|
DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
|
|
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
|
|
DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
/* Append the table to the list */
|
|
InsertTailList(&DiskEntry->PrimaryPartListHead,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
}
|
|
|
|
if (DiskEntry->ExtendedPartition != NULL)
|
|
{
|
|
if (IsListEmpty(&DiskEntry->LogicalPartListHead))
|
|
{
|
|
DPRINT1("No logical partition!\n");
|
|
|
|
/* Create a partition table entry that represents the empty extended partition */
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
NewPartEntry->LogicalPartition = TRUE;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
|
|
NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
InsertTailList(&DiskEntry->LogicalPartListHead,
|
|
&NewPartEntry->ListEntry);
|
|
|
|
return;
|
|
}
|
|
|
|
/* Start partition at head 1, cylinder 0 */
|
|
LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
|
|
LastSectorCount = 0ULL;
|
|
LastUnusedSectorCount = 0ULL;
|
|
|
|
Entry = DiskEntry->LogicalPartListHead.Flink;
|
|
while (Entry != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
|
|
|
|
if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
|
|
PartEntry->SectorCount.QuadPart != 0ULL)
|
|
{
|
|
LastUnusedSectorCount =
|
|
PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
|
|
|
|
if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
|
|
LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
|
|
{
|
|
DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
|
|
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
NewPartEntry->LogicalPartition = TRUE;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
|
|
DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
/* Insert the table into the list */
|
|
InsertTailList(&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
|
|
LastStartSector = PartEntry->StartSector.QuadPart;
|
|
LastSectorCount = PartEntry->SectorCount.QuadPart;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
/* Check for trailing unpartitioned disk space */
|
|
if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
|
|
{
|
|
LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
|
|
|
|
if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
|
|
{
|
|
DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
|
|
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
NewPartEntry->LogicalPartition = TRUE;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
|
|
DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
/* Append the table to the list */
|
|
InsertTailList(&DiskEntry->LogicalPartListHead,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
DPRINT("ScanForUnpartitionedDiskSpace() done\n");
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
SetDiskSignature(
|
|
IN PPARTLIST List,
|
|
IN PDISKENTRY DiskEntry)
|
|
{
|
|
LARGE_INTEGER SystemTime;
|
|
TIME_FIELDS TimeFields;
|
|
PLIST_ENTRY Entry2;
|
|
PDISKENTRY DiskEntry2;
|
|
PUCHAR Buffer;
|
|
|
|
Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
|
|
|
|
while (1)
|
|
{
|
|
NtQuerySystemTime(&SystemTime);
|
|
RtlTimeToTimeFields(&SystemTime, &TimeFields);
|
|
|
|
Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
|
|
Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
|
|
Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
|
|
Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
|
|
|
|
if (DiskEntry->LayoutBuffer->Signature == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* check if the signature already exist */
|
|
/* FIXME:
|
|
* Check also signatures from disks, which are
|
|
* not visible (bootable) by the bios.
|
|
*/
|
|
Entry2 = List->DiskListHead.Flink;
|
|
while (Entry2 != &List->DiskListHead)
|
|
{
|
|
DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
|
|
|
|
if (DiskEntry != DiskEntry2 &&
|
|
DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
|
|
break;
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
if (Entry2 == &List->DiskListHead)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
UpdateDiskSignatures(
|
|
PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PDISKENTRY DiskEntry;
|
|
|
|
/* Print partition lines*/
|
|
Entry = List->DiskListHead.Flink;
|
|
while (Entry != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
if (DiskEntry->LayoutBuffer &&
|
|
DiskEntry->LayoutBuffer->Signature == 0)
|
|
{
|
|
SetDiskSignature(List, DiskEntry);
|
|
DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
AddDiskToList(
|
|
HANDLE FileHandle,
|
|
ULONG DiskNumber,
|
|
PPARTLIST List)
|
|
{
|
|
DISK_GEOMETRY DiskGeometry;
|
|
SCSI_ADDRESS ScsiAddress;
|
|
PDISKENTRY DiskEntry;
|
|
IO_STATUS_BLOCK Iosb;
|
|
NTSTATUS Status;
|
|
PPARTITION_SECTOR Mbr;
|
|
PULONG Buffer;
|
|
LARGE_INTEGER FileOffset;
|
|
WCHAR Identifier[20];
|
|
ULONG Checksum;
|
|
ULONG Signature;
|
|
ULONG i;
|
|
PLIST_ENTRY ListEntry;
|
|
PBIOSDISKENTRY BiosDiskEntry;
|
|
ULONG LayoutBufferSize;
|
|
PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
|
|
|
|
Status = NtDeviceIoControlFile(FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&DiskGeometry,
|
|
sizeof(DISK_GEOMETRY));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (DiskGeometry.MediaType != FixedMedia &&
|
|
DiskGeometry.MediaType != RemovableMedia)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Status = NtDeviceIoControlFile(FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_SCSI_GET_ADDRESS,
|
|
NULL,
|
|
0,
|
|
&ScsiAddress,
|
|
sizeof(SCSI_ADDRESS));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
|
|
0,
|
|
DiskGeometry.BytesPerSector);
|
|
if (Mbr == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FileOffset.QuadPart = 0;
|
|
Status = NtReadFile(FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
(PVOID)Mbr,
|
|
DiskGeometry.BytesPerSector,
|
|
&FileOffset,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlFreeHeap(ProcessHeap, 0, Mbr);
|
|
DPRINT1("NtReadFile failed, status=%x\n", Status);
|
|
return;
|
|
}
|
|
Signature = Mbr->Signature;
|
|
|
|
/* Calculate the MBR checksum */
|
|
Checksum = 0;
|
|
Buffer = (PULONG)Mbr;
|
|
for (i = 0; i < 128; i++)
|
|
{
|
|
Checksum += Buffer[i];
|
|
}
|
|
Checksum = ~Checksum + 1;
|
|
|
|
swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
|
|
DPRINT("Identifier: %S\n", Identifier);
|
|
|
|
DiskEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(DISKENTRY));
|
|
if (DiskEntry == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// DiskEntry->Checksum = Checksum;
|
|
// DiskEntry->Signature = Signature;
|
|
DiskEntry->BiosFound = FALSE;
|
|
|
|
/* Check if this disk has a valid MBR */
|
|
if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
|
|
DiskEntry->NoMbr = TRUE;
|
|
else
|
|
DiskEntry->NoMbr = FALSE;
|
|
|
|
/* Free Mbr sector buffer */
|
|
RtlFreeHeap(ProcessHeap, 0, Mbr);
|
|
|
|
ListEntry = List->BiosDiskListHead.Flink;
|
|
while (ListEntry != &List->BiosDiskListHead)
|
|
{
|
|
BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
|
|
/* FIXME:
|
|
* Compare the size from bios and the reported size from driver.
|
|
* If we have more than one disk with a zero or with the same signatur
|
|
* we must create new signatures and reboot. After the reboot,
|
|
* it is possible to identify the disks.
|
|
*/
|
|
if (BiosDiskEntry->Signature == Signature &&
|
|
BiosDiskEntry->Checksum == Checksum &&
|
|
!BiosDiskEntry->Recognized)
|
|
{
|
|
if (!DiskEntry->BiosFound)
|
|
{
|
|
DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
|
|
DiskEntry->BiosFound = TRUE;
|
|
BiosDiskEntry->Recognized = TRUE;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
if (!DiskEntry->BiosFound)
|
|
{
|
|
#if 0
|
|
RtlFreeHeap(ProcessHeap, 0, DiskEntry);
|
|
return;
|
|
#else
|
|
DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
|
|
#endif
|
|
}
|
|
|
|
InitializeListHead(&DiskEntry->PrimaryPartListHead);
|
|
InitializeListHead(&DiskEntry->LogicalPartListHead);
|
|
|
|
DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
|
|
DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
|
|
DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
|
|
DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
|
|
|
|
DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
|
|
DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
|
|
DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
|
|
DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
|
|
|
|
DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
|
|
(ULONGLONG)DiskGeometry.TracksPerCylinder *
|
|
(ULONGLONG)DiskGeometry.SectorsPerTrack;
|
|
|
|
DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
|
|
DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
|
|
DiskGeometry.SectorsPerTrack;
|
|
|
|
DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
|
|
DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
|
|
|
|
DiskEntry->DiskNumber = DiskNumber;
|
|
DiskEntry->Port = ScsiAddress.PortNumber;
|
|
DiskEntry->Bus = ScsiAddress.PathId;
|
|
DiskEntry->Id = ScsiAddress.TargetId;
|
|
|
|
GetDriverName(DiskEntry);
|
|
|
|
InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
|
|
|
|
/* Allocate a layout buffer with 4 partition entries first */
|
|
LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
|
|
((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
|
|
DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
LayoutBufferSize);
|
|
if (DiskEntry->LayoutBuffer == NULL)
|
|
{
|
|
DPRINT1("Failed to allocate the disk layout buffer!\n");
|
|
return;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
|
|
Status = NtDeviceIoControlFile(FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
NULL,
|
|
0,
|
|
DiskEntry->LayoutBuffer,
|
|
LayoutBufferSize);
|
|
if (NT_SUCCESS(Status))
|
|
break;
|
|
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
|
|
return;
|
|
}
|
|
|
|
LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
|
|
NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
DiskEntry->LayoutBuffer,
|
|
LayoutBufferSize);
|
|
if (NewLayoutBuffer == NULL)
|
|
{
|
|
DPRINT1("Failed to reallocate the disk layout buffer!\n");
|
|
return;
|
|
}
|
|
|
|
DiskEntry->LayoutBuffer = NewLayoutBuffer;
|
|
}
|
|
|
|
DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
|
|
|
|
#ifdef DUMP_PARTITION_TABLE
|
|
DumpPartitionTable(DiskEntry);
|
|
#endif
|
|
|
|
if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
|
|
DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
|
|
DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0)
|
|
{
|
|
if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
|
|
{
|
|
DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
|
|
}
|
|
else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
|
|
{
|
|
DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
|
|
}
|
|
|
|
|
|
if (DiskEntry->LayoutBuffer->PartitionCount == 0)
|
|
{
|
|
DiskEntry->NewDisk = TRUE;
|
|
DiskEntry->LayoutBuffer->PartitionCount = 4;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
|
|
}
|
|
|
|
for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
|
|
{
|
|
AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
|
|
}
|
|
}
|
|
|
|
ScanForUnpartitionedDiskSpace(DiskEntry);
|
|
}
|
|
|
|
|
|
PPARTLIST
|
|
CreatePartitionList(
|
|
SHORT Left,
|
|
SHORT Top,
|
|
SHORT Right,
|
|
SHORT Bottom)
|
|
{
|
|
PPARTLIST List;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
SYSTEM_DEVICE_INFORMATION Sdi;
|
|
IO_STATUS_BLOCK Iosb;
|
|
ULONG ReturnSize;
|
|
NTSTATUS Status;
|
|
ULONG DiskNumber;
|
|
WCHAR Buffer[MAX_PATH];
|
|
UNICODE_STRING Name;
|
|
HANDLE FileHandle;
|
|
|
|
List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
|
|
0,
|
|
sizeof (PARTLIST));
|
|
if (List == NULL)
|
|
return NULL;
|
|
|
|
List->Left = Left;
|
|
List->Top = Top;
|
|
List->Right = Right;
|
|
List->Bottom = Bottom;
|
|
|
|
List->Line = 0;
|
|
List->Offset = 0;
|
|
|
|
List->CurrentDisk = NULL;
|
|
List->CurrentPartition = NULL;
|
|
|
|
List->SystemDisk = NULL;
|
|
List->SystemPartition = NULL;
|
|
List->OriginalSystemDisk = NULL;
|
|
List->OriginalSystemPartition = NULL;
|
|
|
|
List->TempDisk = NULL;
|
|
List->TempPartition = NULL;
|
|
List->FormatState = Start;
|
|
|
|
InitializeListHead(&List->DiskListHead);
|
|
InitializeListHead(&List->BiosDiskListHead);
|
|
|
|
EnumerateBiosDiskEntries(List);
|
|
|
|
Status = NtQuerySystemInformation(SystemDeviceInformation,
|
|
&Sdi,
|
|
sizeof(SYSTEM_DEVICE_INFORMATION),
|
|
&ReturnSize);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlFreeHeap(ProcessHeap, 0, List);
|
|
return NULL;
|
|
}
|
|
|
|
for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
|
|
{
|
|
swprintf(Buffer,
|
|
L"\\Device\\Harddisk%d\\Partition0",
|
|
DiskNumber);
|
|
RtlInitUnicodeString(&Name,
|
|
Buffer);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Name,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
AddDiskToList(FileHandle, DiskNumber, List);
|
|
|
|
NtClose(FileHandle);
|
|
}
|
|
}
|
|
|
|
UpdateDiskSignatures(List);
|
|
|
|
AssignDriveLetters(List);
|
|
|
|
/* Search for first usable disk and partition */
|
|
if (IsListEmpty(&List->DiskListHead))
|
|
{
|
|
List->CurrentDisk = NULL;
|
|
List->CurrentPartition = NULL;
|
|
}
|
|
else
|
|
{
|
|
List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
|
|
{
|
|
List->CurrentPartition = 0;
|
|
}
|
|
else
|
|
{
|
|
List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
}
|
|
}
|
|
|
|
return List;
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyPartitionList(
|
|
PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PBIOSDISKENTRY BiosDiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry;
|
|
|
|
/* Release disk and partition info */
|
|
while (!IsListEmpty(&List->DiskListHead))
|
|
{
|
|
Entry = RemoveHeadList(&List->DiskListHead);
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
/* Release driver name */
|
|
RtlFreeUnicodeString(&DiskEntry->DriverName);
|
|
|
|
/* Release primary partition list */
|
|
while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
|
|
{
|
|
Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
|
|
PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, PartEntry);
|
|
}
|
|
|
|
/* Release logical partition list */
|
|
while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
|
|
{
|
|
Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
|
|
PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, PartEntry);
|
|
}
|
|
|
|
/* Release layout buffer */
|
|
if (DiskEntry->LayoutBuffer != NULL)
|
|
RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
|
|
|
|
|
|
/* Release disk entry */
|
|
RtlFreeHeap(ProcessHeap, 0, DiskEntry);
|
|
}
|
|
|
|
/* Release the bios disk info */
|
|
while (!IsListEmpty(&List->BiosDiskListHead))
|
|
{
|
|
Entry = RemoveHeadList(&List->BiosDiskListHead);
|
|
BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
|
|
}
|
|
|
|
/* Release list head */
|
|
RtlFreeHeap(ProcessHeap, 0, List);
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintEmptyLine(
|
|
PPARTLIST List)
|
|
{
|
|
COORD coPos;
|
|
DWORD Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
|
|
Width = List->Right - List->Left - 1;
|
|
Height = List->Bottom - List->Top - 2;
|
|
|
|
coPos.X = List->Left + 1;
|
|
coPos.Y = List->Top + 1 + List->Line;
|
|
|
|
if (List->Line >= 0 && List->Line <= Height)
|
|
{
|
|
FillConsoleOutputAttribute(StdOutput,
|
|
FOREGROUND_WHITE | BACKGROUND_BLUE,
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
' ',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
List->Line++;
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintPartitionData(
|
|
PPARTLIST List,
|
|
PDISKENTRY DiskEntry,
|
|
PPARTENTRY PartEntry)
|
|
{
|
|
CHAR LineBuffer[128];
|
|
COORD coPos;
|
|
DWORD Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
LARGE_INTEGER PartSize;
|
|
PCHAR Unit;
|
|
UCHAR Attribute;
|
|
CHAR PartTypeString[32];
|
|
PCHAR PartType;
|
|
PartType = PartTypeString;
|
|
|
|
Width = List->Right - List->Left - 1;
|
|
Height = List->Bottom - List->Top - 2;
|
|
|
|
coPos.X = List->Left + 1;
|
|
coPos.Y = List->Top + 1 + List->Line;
|
|
|
|
if (PartEntry->IsPartitioned == FALSE)
|
|
{
|
|
PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
|
|
#if 0
|
|
if (PartSize.QuadPart >= 10737418240) /* 10 GB */
|
|
{
|
|
PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
|
|
Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
#endif
|
|
if (PartSize.QuadPart >= 10485760) /* 10 MB */
|
|
{
|
|
PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
|
|
Unit = MUIGetString(STRING_MB);
|
|
}
|
|
else
|
|
{
|
|
PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
|
|
Unit = MUIGetString(STRING_KB);
|
|
}
|
|
|
|
sprintf(LineBuffer,
|
|
MUIGetString(STRING_UNPSPACE),
|
|
PartEntry->LogicalPartition ? " " : "",
|
|
PartEntry->LogicalPartition ? "" : " ",
|
|
PartSize.u.LowPart,
|
|
Unit);
|
|
}
|
|
else
|
|
{
|
|
/* Determine partition type */
|
|
PartTypeString[0] = '\0';
|
|
if (PartEntry->New != FALSE)
|
|
{
|
|
PartType = MUIGetString(STRING_UNFORMATTED);
|
|
}
|
|
else if (PartEntry->IsPartitioned != FALSE)
|
|
{
|
|
GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
|
|
PartTypeString,
|
|
ARRAYSIZE(PartTypeString));
|
|
PartType = PartTypeString;
|
|
}
|
|
|
|
PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
|
|
#if 0
|
|
if (PartSize.QuadPart >= 10737418240) /* 10 GB */
|
|
{
|
|
PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
|
|
Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
#endif
|
|
if (PartSize.QuadPart >= 10485760) /* 10 MB */
|
|
{
|
|
PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
|
|
Unit = MUIGetString(STRING_MB);
|
|
}
|
|
else
|
|
{
|
|
PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
|
|
Unit = MUIGetString(STRING_KB);
|
|
}
|
|
|
|
if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
|
|
{
|
|
sprintf(LineBuffer,
|
|
MUIGetString(STRING_HDDINFOUNK5),
|
|
(PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
|
|
(PartEntry->DriveLetter == 0) ? '-' : ':',
|
|
PartEntry->BootIndicator ? '*' : ' ',
|
|
PartEntry->LogicalPartition ? " " : "",
|
|
PartEntry->PartitionType,
|
|
PartEntry->LogicalPartition ? "" : " ",
|
|
PartSize.u.LowPart,
|
|
Unit);
|
|
}
|
|
else
|
|
{
|
|
sprintf(LineBuffer,
|
|
"%c%c %c %s%-24s%s %6lu %s",
|
|
(PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
|
|
(PartEntry->DriveLetter == 0) ? '-' : ':',
|
|
PartEntry->BootIndicator ? '*' : ' ',
|
|
PartEntry->LogicalPartition ? " " : "",
|
|
PartType,
|
|
PartEntry->LogicalPartition ? "" : " ",
|
|
PartSize.u.LowPart,
|
|
Unit);
|
|
}
|
|
}
|
|
|
|
Attribute = (List->CurrentDisk == DiskEntry &&
|
|
List->CurrentPartition == PartEntry) ?
|
|
FOREGROUND_BLUE | BACKGROUND_WHITE :
|
|
FOREGROUND_WHITE | BACKGROUND_BLUE;
|
|
|
|
if (List->Line >= 0 && List->Line <= Height)
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
' ',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
coPos.X += 4;
|
|
Width -= 8;
|
|
if (List->Line >= 0 && List->Line <= Height)
|
|
{
|
|
FillConsoleOutputAttribute(StdOutput,
|
|
Attribute,
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
coPos.X++;
|
|
Width -= 2;
|
|
if (List->Line >= 0 && List->Line <= Height)
|
|
{
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
LineBuffer,
|
|
min(strlen(LineBuffer), Width),
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
List->Line++;
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintDiskData(
|
|
PPARTLIST List,
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
|
|
PLIST_ENTRY PrimaryEntry, LogicalEntry;
|
|
CHAR LineBuffer[128];
|
|
COORD coPos;
|
|
DWORD Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
ULARGE_INTEGER DiskSize;
|
|
PCHAR Unit;
|
|
|
|
Width = List->Right - List->Left - 1;
|
|
Height = List->Bottom - List->Top - 2;
|
|
|
|
coPos.X = List->Left + 1;
|
|
coPos.Y = List->Top + 1 + List->Line;
|
|
|
|
DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
|
|
if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
|
|
{
|
|
DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
|
|
Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
{
|
|
DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
|
|
if (DiskSize.QuadPart == 0)
|
|
DiskSize.QuadPart = 1;
|
|
Unit = MUIGetString(STRING_MB);
|
|
}
|
|
|
|
if (DiskEntry->DriverName.Length > 0)
|
|
{
|
|
sprintf(LineBuffer,
|
|
MUIGetString(STRING_HDINFOPARTSELECT),
|
|
DiskSize.u.LowPart,
|
|
Unit,
|
|
DiskEntry->DiskNumber,
|
|
DiskEntry->Port,
|
|
DiskEntry->Bus,
|
|
DiskEntry->Id,
|
|
DiskEntry->DriverName.Buffer);
|
|
}
|
|
else
|
|
{
|
|
sprintf(LineBuffer,
|
|
MUIGetString(STRING_HDDINFOUNK6),
|
|
DiskSize.u.LowPart,
|
|
Unit,
|
|
DiskEntry->DiskNumber,
|
|
DiskEntry->Port,
|
|
DiskEntry->Bus,
|
|
DiskEntry->Id);
|
|
}
|
|
|
|
if (List->Line >= 0 && List->Line <= Height)
|
|
{
|
|
FillConsoleOutputAttribute(StdOutput,
|
|
FOREGROUND_WHITE | BACKGROUND_BLUE,
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
' ',
|
|
Width,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
coPos.X++;
|
|
if (List->Line >= 0 && List->Line <= Height)
|
|
{
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
LineBuffer,
|
|
min((USHORT)strlen(LineBuffer), Width - 2),
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
List->Line++;
|
|
|
|
/* Print separator line */
|
|
PrintEmptyLine(List);
|
|
|
|
/* Print partition lines */
|
|
PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
|
|
|
|
PrintPartitionData(List,
|
|
DiskEntry,
|
|
PrimaryPartEntry);
|
|
|
|
if (IsContainerPartition(PrimaryPartEntry->PartitionType))
|
|
{
|
|
LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
|
|
while (LogicalEntry != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
|
|
|
|
PrintPartitionData(List,
|
|
DiskEntry,
|
|
LogicalPartEntry);
|
|
|
|
LogicalEntry = LogicalEntry->Flink;
|
|
}
|
|
}
|
|
|
|
PrimaryEntry = PrimaryEntry->Flink;
|
|
}
|
|
|
|
/* Print separator line */
|
|
PrintEmptyLine(List);
|
|
}
|
|
|
|
|
|
VOID
|
|
DrawPartitionList(
|
|
PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY Entry, Entry2;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry = NULL;
|
|
COORD coPos;
|
|
DWORD Written;
|
|
SHORT i;
|
|
SHORT CurrentDiskLine;
|
|
SHORT CurrentPartLine;
|
|
SHORT LastLine;
|
|
BOOL CurrentPartLineFound = FALSE;
|
|
BOOL CurrentDiskLineFound = FALSE;
|
|
|
|
/* Calculate the line of the current disk and partition */
|
|
CurrentDiskLine = 0;
|
|
CurrentPartLine = 0;
|
|
LastLine = 0;
|
|
|
|
Entry = List->DiskListHead.Flink;
|
|
while (Entry != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
LastLine += 2;
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
CurrentPartLine += 2;
|
|
}
|
|
|
|
Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry == List->CurrentPartition)
|
|
{
|
|
CurrentPartLineFound = TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
CurrentPartLine++;
|
|
}
|
|
|
|
LastLine++;
|
|
}
|
|
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
Entry2 = DiskEntry->LogicalPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry == List->CurrentPartition)
|
|
{
|
|
CurrentPartLineFound = TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
if (CurrentPartLineFound == FALSE)
|
|
{
|
|
CurrentPartLine++;
|
|
}
|
|
|
|
LastLine++;
|
|
}
|
|
}
|
|
|
|
if (DiskEntry == List->CurrentDisk)
|
|
{
|
|
CurrentDiskLineFound = TRUE;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
if (Entry != &List->DiskListHead)
|
|
{
|
|
if (CurrentDiskLineFound == FALSE)
|
|
{
|
|
CurrentPartLine ++;
|
|
CurrentDiskLine = CurrentPartLine;
|
|
}
|
|
|
|
LastLine++;
|
|
}
|
|
else
|
|
{
|
|
LastLine--;
|
|
}
|
|
}
|
|
|
|
/* If it possible, make the disk name visible */
|
|
if (CurrentPartLine < List->Offset)
|
|
{
|
|
List->Offset = CurrentPartLine;
|
|
}
|
|
else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
|
|
{
|
|
List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
|
|
}
|
|
|
|
if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
|
|
{
|
|
List->Offset = CurrentDiskLine;
|
|
}
|
|
|
|
/* draw upper left corner */
|
|
coPos.X = List->Left;
|
|
coPos.Y = List->Top;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xDA, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* draw upper edge */
|
|
coPos.X = List->Left + 1;
|
|
coPos.Y = List->Top;
|
|
if (List->Offset == 0)
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC4, // '-',
|
|
List->Right - List->Left - 1,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
else
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC4, // '-',
|
|
List->Right - List->Left - 5,
|
|
coPos,
|
|
&Written);
|
|
coPos.X = List->Right - 5;
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
"(\x18)", // "(up)"
|
|
3,
|
|
coPos,
|
|
&Written);
|
|
coPos.X = List->Right - 2;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC4, // '-',
|
|
2,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
/* draw upper right corner */
|
|
coPos.X = List->Right;
|
|
coPos.Y = List->Top;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xBF, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* draw left and right edge */
|
|
for (i = List->Top + 1; i < List->Bottom; i++)
|
|
{
|
|
coPos.X = List->Left;
|
|
coPos.Y = i;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xB3, // '|',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
coPos.X = List->Right;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xB3, //'|',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
/* draw lower left corner */
|
|
coPos.X = List->Left;
|
|
coPos.Y = List->Bottom;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC0, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* draw lower edge */
|
|
coPos.X = List->Left + 1;
|
|
coPos.Y = List->Bottom;
|
|
if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC4, // '-',
|
|
List->Right - List->Left - 1,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
else
|
|
{
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC4, // '-',
|
|
List->Right - List->Left - 5,
|
|
coPos,
|
|
&Written);
|
|
coPos.X = List->Right - 5;
|
|
WriteConsoleOutputCharacterA(StdOutput,
|
|
"(\x19)", // "(down)"
|
|
3,
|
|
coPos,
|
|
&Written);
|
|
coPos.X = List->Right - 2;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xC4, // '-',
|
|
2,
|
|
coPos,
|
|
&Written);
|
|
}
|
|
|
|
/* draw lower right corner */
|
|
coPos.X = List->Right;
|
|
coPos.Y = List->Bottom;
|
|
FillConsoleOutputCharacterA(StdOutput,
|
|
0xD9, // '+',
|
|
1,
|
|
coPos,
|
|
&Written);
|
|
|
|
/* print list entries */
|
|
List->Line = - List->Offset;
|
|
|
|
Entry = List->DiskListHead.Flink;
|
|
while (Entry != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
/* Print disk entry */
|
|
PrintDiskData(List,
|
|
DiskEntry);
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
SelectPartition(
|
|
PPARTLIST List,
|
|
ULONG DiskNumber,
|
|
ULONG PartitionNumber)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
|
|
/* Check for empty disks */
|
|
if (IsListEmpty(&List->DiskListHead))
|
|
return FALSE;
|
|
|
|
/* Check for first usable entry on next disk */
|
|
Entry1 = List->CurrentDisk->ListEntry.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
|
|
|
|
if (DiskEntry->DiskNumber == DiskNumber)
|
|
{
|
|
Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
|
|
if (PartEntry->PartitionNumber == PartitionNumber)
|
|
{
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
DrawPartitionList(List);
|
|
return TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ScrollDownPartitionList(
|
|
PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY DiskListEntry;
|
|
PLIST_ENTRY PartListEntry;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
/* Fail, if no disks are available */
|
|
if (IsListEmpty(&List->DiskListHead))
|
|
return FALSE;
|
|
|
|
/* Check for next usable entry on current disk */
|
|
if (List->CurrentPartition != NULL)
|
|
{
|
|
if (List->CurrentPartition->LogicalPartition)
|
|
{
|
|
/* Logical partition */
|
|
|
|
PartListEntry = List->CurrentPartition->ListEntry.Flink;
|
|
if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
|
|
{
|
|
/* Next logical partition */
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
|
|
if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Primary or extended partition */
|
|
|
|
if ((List->CurrentPartition->IsPartitioned != FALSE) &&
|
|
IsContainerPartition(List->CurrentPartition->PartitionType))
|
|
{
|
|
/* First logical partition */
|
|
PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
|
|
if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Next primary partition */
|
|
PartListEntry = List->CurrentPartition->ListEntry.Flink;
|
|
if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Search for the first partition entry on the next disk */
|
|
DiskListEntry = List->CurrentDisk->ListEntry.Flink;
|
|
while (DiskListEntry != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
|
|
|
|
PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
|
|
if (PartListEntry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
DiskListEntry = DiskListEntry->Flink;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ScrollUpPartitionList(
|
|
PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY DiskListEntry;
|
|
PLIST_ENTRY PartListEntry;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
/* Fail, if no disks are available */
|
|
if (IsListEmpty(&List->DiskListHead))
|
|
return FALSE;
|
|
|
|
/* Check for previous usable entry on current disk */
|
|
if (List->CurrentPartition != NULL)
|
|
{
|
|
if (List->CurrentPartition->LogicalPartition)
|
|
{
|
|
/* Logical partition */
|
|
PartListEntry = List->CurrentPartition->ListEntry.Blink;
|
|
if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
|
|
{
|
|
/* Previous logical partition */
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
}
|
|
else
|
|
{
|
|
/* Extended partition*/
|
|
PartEntry = List->CurrentDisk->ExtendedPartition;
|
|
}
|
|
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Primary or extended partition */
|
|
|
|
PartListEntry = List->CurrentPartition->ListEntry.Blink;
|
|
if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
if ((PartEntry->IsPartitioned != FALSE) &&
|
|
IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
}
|
|
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* Search for the last partition entry on the previous disk */
|
|
DiskListEntry = List->CurrentDisk->ListEntry.Blink;
|
|
while (DiskListEntry != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
|
|
|
|
PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
|
|
if (PartListEntry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
if ((PartEntry->IsPartitioned != FALSE) &&
|
|
IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
PartListEntry = DiskEntry->LogicalPartListHead.Blink;
|
|
if (PartListEntry != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
|
|
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
DiskListEntry = DiskListEntry->Blink;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static
|
|
BOOLEAN
|
|
IsEmptyLayoutEntry(
|
|
PPARTITION_INFORMATION PartitionInfo)
|
|
{
|
|
if (PartitionInfo->StartingOffset.QuadPart == 0 &&
|
|
PartitionInfo->PartitionLength.QuadPart == 0)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static
|
|
BOOLEAN
|
|
IsSamePrimaryLayoutEntry(
|
|
IN PPARTITION_INFORMATION PartitionInfo,
|
|
IN PDISKENTRY DiskEntry,
|
|
IN PPARTENTRY PartEntry)
|
|
{
|
|
if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
|
|
PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
|
|
// PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
|
|
// PartitionInfo->PartitionType == PartEntry->PartitionType
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static
|
|
ULONG
|
|
GetPrimaryPartitionCount(
|
|
IN PDISKENTRY DiskEntry)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PPARTENTRY PartEntry;
|
|
ULONG Count = 0;
|
|
|
|
Entry = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
|
|
if (PartEntry->IsPartitioned == TRUE)
|
|
Count++;
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
static
|
|
ULONG
|
|
GetLogicalPartitionCount(
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
PLIST_ENTRY ListEntry;
|
|
PPARTENTRY PartEntry;
|
|
ULONG Count = 0;
|
|
|
|
ListEntry = DiskEntry->LogicalPartListHead.Flink;
|
|
while (ListEntry != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
|
|
if (PartEntry->IsPartitioned)
|
|
Count++;
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
ReAllocateLayoutBuffer(
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
|
|
ULONG NewPartitionCount;
|
|
ULONG CurrentPartitionCount = 0;
|
|
ULONG LayoutBufferSize;
|
|
ULONG i;
|
|
|
|
DPRINT1("ReAllocateLayoutBuffer()\n");
|
|
|
|
NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
|
|
|
|
if (DiskEntry->LayoutBuffer)
|
|
CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
|
|
|
|
DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
|
|
CurrentPartitionCount, NewPartitionCount);
|
|
|
|
if (CurrentPartitionCount == NewPartitionCount)
|
|
return TRUE;
|
|
|
|
LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
|
|
((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
|
|
NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
DiskEntry->LayoutBuffer,
|
|
LayoutBufferSize);
|
|
if (NewLayoutBuffer == NULL)
|
|
{
|
|
DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
|
|
return FALSE;
|
|
}
|
|
|
|
/* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
|
|
if (NewPartitionCount > CurrentPartitionCount)
|
|
{
|
|
for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
|
|
NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
|
|
}
|
|
|
|
DiskEntry->LayoutBuffer = NewLayoutBuffer;
|
|
DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
UpdateDiskLayout(
|
|
IN PDISKENTRY DiskEntry)
|
|
{
|
|
PPARTITION_INFORMATION PartitionInfo;
|
|
PPARTITION_INFORMATION LinkInfo = NULL;
|
|
PLIST_ENTRY ListEntry;
|
|
PPARTENTRY PartEntry;
|
|
LARGE_INTEGER HiddenSectors64;
|
|
ULONG Index;
|
|
ULONG PartitionNumber = 1;
|
|
|
|
DPRINT1("UpdateDiskLayout()\n");
|
|
|
|
/* Resize the layout buffer if necessary */
|
|
if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
|
|
{
|
|
DPRINT("ReAllocateLayoutBuffer() failed.\n");
|
|
return;
|
|
}
|
|
|
|
/* Update the primary partition table */
|
|
Index = 0;
|
|
ListEntry = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (ListEntry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
|
|
|
|
if (PartEntry->IsPartitioned != FALSE)
|
|
{
|
|
PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
|
|
|
|
if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
|
|
{
|
|
DPRINT1("Updating primary partition entry %lu\n", Index);
|
|
|
|
PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
|
|
PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
|
|
PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
|
|
PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
|
|
PartitionInfo->PartitionType = PartEntry->PartitionType;
|
|
PartitionInfo->BootIndicator = PartEntry->BootIndicator;
|
|
PartitionInfo->RecognizedPartition = FALSE;
|
|
PartitionInfo->RewritePartition = TRUE;
|
|
}
|
|
|
|
PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
|
|
PartEntry->PartitionIndex = Index;
|
|
|
|
if (!IsContainerPartition(PartEntry->PartitionType))
|
|
PartitionNumber++;
|
|
|
|
Index++;
|
|
}
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* Update the logical partition tables */
|
|
Index = 4;
|
|
ListEntry = DiskEntry->LogicalPartListHead.Flink;
|
|
while (ListEntry != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
|
|
|
|
if (PartEntry->IsPartitioned)
|
|
{
|
|
PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
|
|
|
|
DPRINT1("Updating logical partition entry %lu\n", Index);
|
|
|
|
PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
|
|
PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
|
|
PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
|
|
PartitionInfo->PartitionNumber = PartitionNumber;
|
|
PartitionInfo->PartitionType = PartEntry->PartitionType;
|
|
PartitionInfo->BootIndicator = FALSE;
|
|
PartitionInfo->RecognizedPartition = FALSE;
|
|
PartitionInfo->RewritePartition = TRUE;
|
|
|
|
PartEntry->PartitionNumber = PartitionNumber;
|
|
PartEntry->PartitionIndex = Index;
|
|
|
|
/* Fill the link entry of the previous partition table */
|
|
if (LinkInfo != NULL)
|
|
{
|
|
LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
|
|
LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
|
|
HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
|
|
LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
|
|
LinkInfo->PartitionNumber = 0;
|
|
LinkInfo->PartitionType = PARTITION_EXTENDED;
|
|
LinkInfo->BootIndicator = FALSE;
|
|
LinkInfo->RecognizedPartition = FALSE;
|
|
LinkInfo->RewritePartition = TRUE;
|
|
}
|
|
|
|
/* Save a pointer to the link entry of the current partition table */
|
|
LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
|
|
|
|
PartitionNumber++;
|
|
Index += 4;
|
|
}
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* Wipe unused primary partition table entries */
|
|
for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
|
|
{
|
|
DPRINT1("Primary partition entry %lu\n", Index);
|
|
|
|
PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
|
|
|
|
if (!IsEmptyLayoutEntry(PartitionInfo))
|
|
{
|
|
DPRINT1("Wiping primary partition entry %lu\n", Index);
|
|
|
|
PartitionInfo->StartingOffset.QuadPart = 0;
|
|
PartitionInfo->PartitionLength.QuadPart = 0;
|
|
PartitionInfo->HiddenSectors = 0;
|
|
PartitionInfo->PartitionNumber = 0;
|
|
PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
PartitionInfo->BootIndicator = FALSE;
|
|
PartitionInfo->RecognizedPartition = FALSE;
|
|
PartitionInfo->RewritePartition = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Wipe unused logical partition table entries */
|
|
for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
|
|
{
|
|
if (Index % 4 >= 2)
|
|
{
|
|
DPRINT1("Logical partition entry %lu\n", Index);
|
|
|
|
PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
|
|
|
|
if (!IsEmptyLayoutEntry(PartitionInfo))
|
|
{
|
|
DPRINT1("Wiping partition entry %lu\n", Index);
|
|
|
|
PartitionInfo->StartingOffset.QuadPart = 0;
|
|
PartitionInfo->PartitionLength.QuadPart = 0;
|
|
PartitionInfo->HiddenSectors = 0;
|
|
PartitionInfo->PartitionNumber = 0;
|
|
PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
PartitionInfo->BootIndicator = FALSE;
|
|
PartitionInfo->RecognizedPartition = FALSE;
|
|
PartitionInfo->RewritePartition = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DUMP_PARTITION_TABLE
|
|
DumpPartitionTable(DiskEntry);
|
|
#endif
|
|
}
|
|
|
|
|
|
static
|
|
PPARTENTRY
|
|
GetPrevUnpartitionedEntry(
|
|
PDISKENTRY DiskEntry,
|
|
PPARTENTRY PartEntry)
|
|
{
|
|
PPARTENTRY PrevPartEntry;
|
|
PLIST_ENTRY ListHead;
|
|
|
|
if (PartEntry->LogicalPartition)
|
|
ListHead = &DiskEntry->LogicalPartListHead;
|
|
else
|
|
ListHead = &DiskEntry->PrimaryPartListHead;
|
|
|
|
if (PartEntry->ListEntry.Blink != ListHead)
|
|
{
|
|
PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (PrevPartEntry->IsPartitioned == FALSE)
|
|
return PrevPartEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static
|
|
PPARTENTRY
|
|
GetNextUnpartitionedEntry(
|
|
PDISKENTRY DiskEntry,
|
|
PPARTENTRY PartEntry)
|
|
{
|
|
PPARTENTRY NextPartEntry;
|
|
PLIST_ENTRY ListHead;
|
|
|
|
if (PartEntry->LogicalPartition)
|
|
ListHead = &DiskEntry->LogicalPartListHead;
|
|
else
|
|
ListHead = &DiskEntry->PrimaryPartListHead;
|
|
|
|
if (PartEntry->ListEntry.Flink != ListHead)
|
|
{
|
|
NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (NextPartEntry->IsPartitioned == FALSE)
|
|
return NextPartEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
CreatePrimaryPartition(
|
|
PPARTLIST List,
|
|
ULONGLONG SectorCount,
|
|
BOOLEAN AutoCreate)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY NewPartEntry;
|
|
|
|
DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
|
|
|
|
if (List == NULL ||
|
|
List->CurrentDisk == NULL ||
|
|
List->CurrentPartition == NULL ||
|
|
List->CurrentPartition->IsPartitioned != FALSE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
|
|
|
|
if ((AutoCreate != FALSE) ||
|
|
(AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
|
|
{
|
|
DPRINT1("Convert existing partition entry\n");
|
|
|
|
/* Convert current entry to 'new (unformatted)' */
|
|
PartEntry->IsPartitioned = TRUE;
|
|
PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
PartEntry->FormatState = Unformatted;
|
|
PartEntry->AutoCreate = AutoCreate;
|
|
PartEntry->New = TRUE;
|
|
PartEntry->BootIndicator = FALSE;
|
|
|
|
DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Add new partition entry\n");
|
|
|
|
/* Insert and initialize a new partition entry */
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
/* Insert the new entry into the list */
|
|
InsertTailList(&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
|
|
NewPartEntry->IsPartitioned = TRUE;
|
|
NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->New = TRUE;
|
|
NewPartEntry->FormatState = Unformatted;
|
|
NewPartEntry->BootIndicator = FALSE;
|
|
|
|
PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
|
|
PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
|
|
}
|
|
|
|
UpdateDiskLayout(DiskEntry);
|
|
|
|
DiskEntry->Dirty = TRUE;
|
|
|
|
AssignDriveLetters(List);
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
AddLogicalDiskSpace(
|
|
PDISKENTRY DiskEntry)
|
|
{
|
|
PPARTENTRY NewPartEntry;
|
|
|
|
DPRINT1("AddLogicalDiskSpace()\n");
|
|
|
|
/* Create a partition table entry that represents the empty space in the container partition */
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
NewPartEntry->LogicalPartition = TRUE;
|
|
|
|
NewPartEntry->IsPartitioned = FALSE;
|
|
NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
|
|
NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
InsertTailList(&DiskEntry->LogicalPartListHead,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
|
|
|
|
VOID
|
|
CreateExtendedPartition(
|
|
PPARTLIST List,
|
|
ULONGLONG SectorCount)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY NewPartEntry;
|
|
|
|
DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
|
|
|
|
if (List == NULL ||
|
|
List->CurrentDisk == NULL ||
|
|
List->CurrentPartition == NULL ||
|
|
(List->CurrentPartition->IsPartitioned != FALSE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
|
|
|
|
if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
|
|
{
|
|
DPRINT1("Convert existing partition entry\n");
|
|
|
|
/* Convert current entry to 'new (unformatted)' */
|
|
PartEntry->IsPartitioned = TRUE;
|
|
PartEntry->FormatState = Formatted;
|
|
PartEntry->AutoCreate = FALSE;
|
|
PartEntry->New = FALSE;
|
|
PartEntry->BootIndicator = FALSE;
|
|
|
|
if (PartEntry->StartSector.QuadPart < 1450560)
|
|
{
|
|
/* Partition starts below the 8.4GB boundary ==> CHS partition */
|
|
PartEntry->PartitionType = PARTITION_EXTENDED;
|
|
}
|
|
else
|
|
{
|
|
/* Partition starts above the 8.4GB boundary ==> LBA partition */
|
|
PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
|
|
}
|
|
|
|
DiskEntry->ExtendedPartition = PartEntry;
|
|
|
|
DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Add new partition entry\n");
|
|
|
|
/* Insert and initialize a new partition entry */
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
/* Insert the new entry into the list */
|
|
InsertTailList(&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
|
|
NewPartEntry->IsPartitioned = TRUE;
|
|
NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
|
|
NewPartEntry->New = FALSE;
|
|
NewPartEntry->FormatState = Formatted;
|
|
NewPartEntry->BootIndicator = FALSE;
|
|
|
|
if (NewPartEntry->StartSector.QuadPart < 1450560)
|
|
{
|
|
/* Partition starts below the 8.4GB boundary ==> CHS partition */
|
|
NewPartEntry->PartitionType = PARTITION_EXTENDED;
|
|
}
|
|
else
|
|
{
|
|
/* Partition starts above the 8.4GB boundary ==> LBA partition */
|
|
NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
|
|
}
|
|
|
|
DiskEntry->ExtendedPartition = NewPartEntry;
|
|
|
|
PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
|
|
PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
}
|
|
|
|
AddLogicalDiskSpace(DiskEntry);
|
|
|
|
UpdateDiskLayout(DiskEntry);
|
|
|
|
DiskEntry->Dirty = TRUE;
|
|
|
|
AssignDriveLetters(List);
|
|
}
|
|
|
|
|
|
VOID
|
|
CreateLogicalPartition(
|
|
PPARTLIST List,
|
|
ULONGLONG SectorCount,
|
|
BOOLEAN AutoCreate)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY NewPartEntry;
|
|
|
|
DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
|
|
|
|
if (List == NULL ||
|
|
List->CurrentDisk == NULL ||
|
|
List->CurrentPartition == NULL ||
|
|
List->CurrentPartition->IsPartitioned != FALSE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
|
|
|
|
if (AutoCreate == TRUE ||
|
|
AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
|
|
{
|
|
DPRINT1("Convert existing partition entry\n");
|
|
|
|
/* Convert current entry to 'new (unformatted)' */
|
|
PartEntry->IsPartitioned = TRUE;
|
|
PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
PartEntry->FormatState = Unformatted;
|
|
PartEntry->AutoCreate = FALSE;
|
|
PartEntry->New = TRUE;
|
|
PartEntry->BootIndicator = FALSE;
|
|
PartEntry->LogicalPartition = TRUE;
|
|
|
|
DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Add new partition entry\n");
|
|
|
|
/* Insert and initialize a new partition entry */
|
|
NewPartEntry = RtlAllocateHeap(ProcessHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
/* Insert the new entry into the list */
|
|
InsertTailList(&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
|
|
NewPartEntry->DiskEntry = DiskEntry;
|
|
|
|
NewPartEntry->IsPartitioned = TRUE;
|
|
NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
|
|
NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
|
|
NewPartEntry->StartSector.QuadPart;
|
|
NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
|
|
DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
|
|
DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
|
|
DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
|
|
|
|
NewPartEntry->New = TRUE;
|
|
NewPartEntry->FormatState = Unformatted;
|
|
NewPartEntry->BootIndicator = FALSE;
|
|
NewPartEntry->LogicalPartition = TRUE;
|
|
|
|
PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
|
|
PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
|
|
}
|
|
|
|
UpdateDiskLayout(DiskEntry);
|
|
|
|
DiskEntry->Dirty = TRUE;
|
|
|
|
AssignDriveLetters(List);
|
|
}
|
|
|
|
|
|
VOID
|
|
DeleteCurrentPartition(
|
|
PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY PrevPartEntry;
|
|
PPARTENTRY NextPartEntry;
|
|
PPARTENTRY LogicalPartEntry;
|
|
PLIST_ENTRY Entry;
|
|
|
|
if (List == NULL ||
|
|
List->CurrentDisk == NULL ||
|
|
List->CurrentPartition == NULL ||
|
|
List->CurrentPartition->IsPartitioned == FALSE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Clear the system disk and partition pointers if the system partition will be deleted */
|
|
if (List->SystemPartition == List->CurrentPartition)
|
|
{
|
|
List->SystemDisk = NULL;
|
|
List->SystemPartition = NULL;
|
|
}
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
/* Delete all logical partition entries if an extended partition will be deleted */
|
|
if (DiskEntry->ExtendedPartition == PartEntry)
|
|
{
|
|
while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
|
|
{
|
|
Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
|
|
LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
|
|
}
|
|
|
|
DiskEntry->ExtendedPartition = NULL;
|
|
}
|
|
|
|
/* Adjust unpartitioned disk space entries */
|
|
|
|
/* Get pointer to previous and next unpartitioned entries */
|
|
PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
|
|
NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
|
|
|
|
if (PrevPartEntry != NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Merge previous, current and next unpartitioned entry */
|
|
|
|
/* Adjust the previous entries length */
|
|
PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
|
|
|
|
/* Remove the current entry */
|
|
RemoveEntryList(&PartEntry->ListEntry);
|
|
RtlFreeHeap(ProcessHeap, 0, PartEntry);
|
|
|
|
/* Remove the next entry */
|
|
RemoveEntryList (&NextPartEntry->ListEntry);
|
|
RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
|
|
|
|
/* Update current partition */
|
|
List->CurrentPartition = PrevPartEntry;
|
|
}
|
|
else if (PrevPartEntry != NULL && NextPartEntry == NULL)
|
|
{
|
|
/* Merge current and previous unpartitioned entry */
|
|
|
|
/* Adjust the previous entries length */
|
|
PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
|
|
|
|
/* Remove the current entry */
|
|
RemoveEntryList(&PartEntry->ListEntry);
|
|
RtlFreeHeap(ProcessHeap, 0, PartEntry);
|
|
|
|
/* Update current partition */
|
|
List->CurrentPartition = PrevPartEntry;
|
|
}
|
|
else if (PrevPartEntry == NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Merge current and next unpartitioned entry */
|
|
|
|
/* Adjust the next entries offset and length */
|
|
NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
|
|
NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
|
|
|
|
/* Remove the current entry */
|
|
RemoveEntryList(&PartEntry->ListEntry);
|
|
RtlFreeHeap(ProcessHeap, 0, PartEntry);
|
|
|
|
/* Update current partition */
|
|
List->CurrentPartition = NextPartEntry;
|
|
}
|
|
else
|
|
{
|
|
/* Nothing to merge but change current entry */
|
|
PartEntry->IsPartitioned = FALSE;
|
|
PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
PartEntry->FormatState = Unformatted;
|
|
PartEntry->DriveLetter = 0;
|
|
}
|
|
|
|
UpdateDiskLayout(DiskEntry);
|
|
|
|
DiskEntry->Dirty = TRUE;
|
|
|
|
AssignDriveLetters(List);
|
|
}
|
|
|
|
|
|
VOID
|
|
CheckActiveSystemPartition(
|
|
IN PPARTLIST List,
|
|
IN PFILE_SYSTEM_LIST FileSystemList /* Needed for checking the FS of the candidate system partition */
|
|
)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
PFILE_SYSTEM_ITEM FileSystem;
|
|
|
|
/* Check for empty disk list */
|
|
if (IsListEmpty(&List->DiskListHead))
|
|
{
|
|
List->SystemDisk = NULL;
|
|
List->SystemPartition = NULL;
|
|
List->OriginalSystemDisk = NULL;
|
|
List->OriginalSystemPartition = NULL;
|
|
return;
|
|
}
|
|
|
|
/* Choose the currently selected disk */
|
|
DiskEntry = List->CurrentDisk;
|
|
|
|
/* Check for empty partition list */
|
|
if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
|
|
{
|
|
List->SystemDisk = NULL;
|
|
List->SystemPartition = NULL;
|
|
List->OriginalSystemDisk = NULL;
|
|
List->OriginalSystemPartition = NULL;
|
|
return;
|
|
}
|
|
|
|
if (List->SystemDisk != NULL && List->SystemPartition != NULL)
|
|
{
|
|
/* We already have an active system partition */
|
|
DPRINT1("Use the current system partition %lu in disk %lu, drive letter %c\n",
|
|
List->SystemPartition->PartitionNumber,
|
|
List->SystemDisk->DiskNumber,
|
|
(List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
|
|
return;
|
|
}
|
|
|
|
DPRINT1("We are here (1)!\n");
|
|
|
|
List->SystemDisk = NULL;
|
|
List->SystemPartition = NULL;
|
|
List->OriginalSystemDisk = NULL;
|
|
List->OriginalSystemPartition = NULL;
|
|
|
|
/* Retrieve the first partition of the disk */
|
|
PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
List->SystemDisk = DiskEntry;
|
|
List->SystemPartition = PartEntry;
|
|
|
|
//
|
|
// See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
|
|
//
|
|
|
|
/* Check if the disk is new and if so, use its first partition as the active system partition */
|
|
if (DiskEntry->NewDisk)
|
|
{
|
|
if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
|
|
{
|
|
/* FIXME: Might be incorrect if partitions were created by Linux FDISK */
|
|
List->SystemDisk = DiskEntry;
|
|
List->SystemPartition = PartEntry;
|
|
|
|
List->OriginalSystemDisk = List->SystemDisk;
|
|
List->OriginalSystemPartition = List->SystemPartition;
|
|
|
|
DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %c\n",
|
|
List->SystemPartition->PartitionNumber,
|
|
List->SystemDisk->DiskNumber,
|
|
(List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
|
|
|
|
goto SetSystemPartition;
|
|
}
|
|
|
|
// FIXME: What to do??
|
|
DPRINT1("NewDisk TRUE but first partition is used?\n");
|
|
}
|
|
|
|
DPRINT1("We are here (2)!\n");
|
|
|
|
/*
|
|
* The disk is not new, check if any partition is initialized;
|
|
* if not, the first one becomes the system partition.
|
|
*/
|
|
ListEntry = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (ListEntry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
/* Retrieve the partition and go to the next one */
|
|
PartEntry = CONTAINING_RECORD(ListEntry,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
/* Check if the partition is partitioned and is used */
|
|
if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Go to the next one */
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
if (ListEntry == &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
/*
|
|
* OK we haven't encountered any used and active partition,
|
|
* so use the first one as the system partition.
|
|
*/
|
|
|
|
/* FIXME: Might be incorrect if partitions were created by Linux FDISK */
|
|
List->OriginalSystemDisk = List->SystemDisk; // DiskEntry
|
|
List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
|
|
|
|
DPRINT1("Use first active system partition %lu in disk %lu, drive letter %c\n",
|
|
List->SystemPartition->PartitionNumber,
|
|
List->SystemDisk->DiskNumber,
|
|
(List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
|
|
|
|
goto SetSystemPartition;
|
|
}
|
|
|
|
List->SystemDisk = NULL;
|
|
List->SystemPartition = NULL;
|
|
List->OriginalSystemDisk = NULL;
|
|
List->OriginalSystemPartition = NULL;
|
|
|
|
DPRINT1("We are here (3)!\n");
|
|
|
|
/* The disk is not new, scan all partitions to find the (active) system partition */
|
|
ListEntry = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (ListEntry != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
/* Retrieve the partition and go to the next one */
|
|
PartEntry = CONTAINING_RECORD(ListEntry,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
/* Check if the partition is partitioned and used */
|
|
if (PartEntry->IsPartitioned &&
|
|
PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
|
|
{
|
|
/* Check if the partition is active */
|
|
if (PartEntry->BootIndicator)
|
|
{
|
|
/* Yes, we found it */
|
|
List->SystemDisk = DiskEntry;
|
|
List->SystemPartition = PartEntry;
|
|
|
|
DPRINT1("Found active system partition %lu in disk %lu, drive letter %c\n",
|
|
PartEntry->PartitionNumber,
|
|
DiskEntry->DiskNumber,
|
|
(PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if we have found the system partition */
|
|
if (List->SystemDisk == NULL || List->SystemPartition == NULL)
|
|
{
|
|
/* Nothing, use the alternative system partition */
|
|
DPRINT1("No system partition found, use the alternative partition!\n");
|
|
goto UseAlternativeSystemPartition;
|
|
}
|
|
|
|
/* Save them */
|
|
List->OriginalSystemDisk = List->SystemDisk;
|
|
List->OriginalSystemPartition = List->SystemPartition;
|
|
|
|
/*
|
|
* ADDITIONAL CHECKS / BIG HACK:
|
|
*
|
|
* Retrieve its file system and check whether we have
|
|
* write support for it. If that is the case we are fine
|
|
* and we can use it directly. However if we don't have
|
|
* write support we will need to change the active system
|
|
* partition.
|
|
*
|
|
* NOTE that this is completely useless on architectures
|
|
* where a real system partition is required, as on these
|
|
* architectures the partition uses the FAT FS, for which
|
|
* we do have write support.
|
|
* NOTE also that for those architectures looking for a
|
|
* partition boot indicator is insufficient.
|
|
*/
|
|
FileSystem = GetFileSystem(FileSystemList, List->OriginalSystemPartition);
|
|
if (FileSystem == NULL)
|
|
{
|
|
DPRINT1("System partition %lu in disk %lu with no FS?!\n",
|
|
List->OriginalSystemPartition->PartitionNumber,
|
|
List->OriginalSystemDisk->DiskNumber);
|
|
goto FindAndUseAlternativeSystemPartition;
|
|
}
|
|
// HACK: WARNING: We cannot write on this FS yet!
|
|
// See fslist.c:GetFileSystem()
|
|
if (List->OriginalSystemPartition->PartitionType == PARTITION_EXT2 ||
|
|
List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
|
|
{
|
|
DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
|
|
FileSystem->FileSystemName);
|
|
goto FindAndUseAlternativeSystemPartition;
|
|
}
|
|
|
|
DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %c\n",
|
|
List->SystemPartition->PartitionNumber,
|
|
List->SystemDisk->DiskNumber,
|
|
(List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
|
|
|
|
return;
|
|
|
|
FindAndUseAlternativeSystemPartition:
|
|
/*
|
|
* We are here because we have not found any (active) candidate
|
|
* system partition that we know how to support. What we are going
|
|
* to do is to change the existing system partition and use the
|
|
* partition on which we install ReactOS as the new system partition,
|
|
* and then we will need to add in FreeLdr's entry a boot entry to boot
|
|
* from the original system partition.
|
|
*/
|
|
|
|
/* Unset the old system partition */
|
|
List->SystemPartition->BootIndicator = FALSE;
|
|
List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
|
|
List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
|
|
List->SystemDisk->Dirty = TRUE;
|
|
|
|
UseAlternativeSystemPartition:
|
|
List->SystemDisk = List->CurrentDisk;
|
|
List->SystemPartition = List->CurrentPartition;
|
|
|
|
DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %c\n",
|
|
List->SystemPartition->PartitionNumber,
|
|
List->SystemDisk->DiskNumber,
|
|
(List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
|
|
|
|
SetSystemPartition:
|
|
/* Set the new active system partition */
|
|
List->SystemPartition->BootIndicator = TRUE;
|
|
List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
|
|
List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
|
|
List->SystemDisk->Dirty = TRUE;
|
|
}
|
|
|
|
|
|
static
|
|
NTSTATUS
|
|
WritePartitions(
|
|
IN PPARTLIST List,
|
|
IN PDISKENTRY DiskEntry)
|
|
{
|
|
WCHAR DstPath[MAX_PATH];
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK Iosb;
|
|
UNICODE_STRING Name;
|
|
ULONG BufferSize;
|
|
HANDLE FileHandle = NULL;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
|
|
|
|
swprintf(DstPath,
|
|
L"\\Device\\Harddisk%d\\Partition0",
|
|
DiskEntry->DiskNumber);
|
|
RtlInitUnicodeString(&Name,
|
|
DstPath);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Name,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
#ifdef DUMP_PARTITION_TABLE
|
|
DumpPartitionTable(DiskEntry);
|
|
#endif
|
|
|
|
BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
|
|
((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
|
|
Status = NtDeviceIoControlFile(FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DISK_SET_DRIVE_LAYOUT,
|
|
DiskEntry->LayoutBuffer,
|
|
BufferSize,
|
|
NULL,
|
|
0);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
|
|
}
|
|
|
|
if (FileHandle != NULL)
|
|
NtClose(FileHandle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
WritePartitionsToDisk(
|
|
PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PDISKENTRY DiskEntry;
|
|
|
|
if (List == NULL)
|
|
return TRUE;
|
|
|
|
Entry = List->DiskListHead.Flink;
|
|
while (Entry != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
|
|
|
|
if (DiskEntry->Dirty != FALSE)
|
|
{
|
|
WritePartitions(List, DiskEntry);
|
|
DiskEntry->Dirty = FALSE;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetMountedDeviceValues(
|
|
PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY Entry1, Entry2;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
LARGE_INTEGER StartingOffset;
|
|
|
|
if (List == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry1,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry->IsPartitioned)
|
|
{
|
|
if (PartEntry->DriveLetter)
|
|
{
|
|
StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
|
|
if (!SetMountedDeviceValue(PartEntry->DriveLetter,
|
|
DiskEntry->LayoutBuffer->Signature,
|
|
StartingOffset))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
PrimaryPartitionCreationChecks(
|
|
IN PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
/* Fail if partition is already in use */
|
|
if (PartEntry->IsPartitioned != FALSE)
|
|
return ERROR_NEW_PARTITION;
|
|
|
|
/* Fail if there are already 4 primary partitions in the list */
|
|
if (GetPrimaryPartitionCount(DiskEntry) >= 4)
|
|
return ERROR_PARTITION_TABLE_FULL;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ExtendedPartitionCreationChecks(
|
|
IN PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
/* Fail if partition is already in use */
|
|
if (PartEntry->IsPartitioned != FALSE)
|
|
return ERROR_NEW_PARTITION;
|
|
|
|
/* Fail if there are already 4 primary partitions in the list */
|
|
if (GetPrimaryPartitionCount(DiskEntry) >= 4)
|
|
return ERROR_PARTITION_TABLE_FULL;
|
|
|
|
/* Fail if there is another extended partition in the list */
|
|
if (DiskEntry->ExtendedPartition != NULL)
|
|
return ERROR_ONLY_ONE_EXTENDED;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
ULONG
|
|
LogicalPartitionCreationChecks(
|
|
IN PPARTLIST List)
|
|
{
|
|
// PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
// DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
/* Fail if partition is already in use */
|
|
if (PartEntry->IsPartitioned != FALSE)
|
|
return ERROR_NEW_PARTITION;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetNextUnformattedPartition(
|
|
IN PPARTLIST List,
|
|
OUT PDISKENTRY *pDiskEntry,
|
|
OUT PPARTENTRY *pPartEntry)
|
|
{
|
|
PLIST_ENTRY Entry1, Entry2;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry1,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry->IsPartitioned && PartEntry->New)
|
|
{
|
|
*pDiskEntry = DiskEntry;
|
|
*pPartEntry = PartEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry2 = DiskEntry->LogicalPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry->IsPartitioned && PartEntry->New)
|
|
{
|
|
*pDiskEntry = DiskEntry;
|
|
*pPartEntry = PartEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
*pDiskEntry = NULL;
|
|
*pPartEntry = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetNextUncheckedPartition(
|
|
IN PPARTLIST List,
|
|
OUT PDISKENTRY *pDiskEntry,
|
|
OUT PPARTENTRY *pPartEntry)
|
|
{
|
|
PLIST_ENTRY Entry1, Entry2;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD(Entry1,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
Entry2 = DiskEntry->PrimaryPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PrimaryPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry->NeedsCheck == TRUE)
|
|
{
|
|
*pDiskEntry = DiskEntry;
|
|
*pPartEntry = PartEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry2 = DiskEntry->LogicalPartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->LogicalPartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (PartEntry->NeedsCheck == TRUE)
|
|
{
|
|
*pDiskEntry = DiskEntry;
|
|
*pPartEntry = PartEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
*pDiskEntry = NULL;
|
|
*pPartEntry = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* EOF */
|