mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 14:18:41 +00:00
2750 lines
78 KiB
C
2750 lines
78 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: subsys/system/usetup/partlist.c
|
|
* PURPOSE: Partition list functions
|
|
* PROGRAMMER: Eric Kohl
|
|
* Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
*/
|
|
|
|
#include "usetup.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
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 %lu",
|
|
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
|
|
AssignDriverLetters (PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
//PLIST_ENTRY Entry2;
|
|
CHAR Letter;
|
|
UCHAR i;
|
|
|
|
Letter = 'C';
|
|
|
|
/* Assign drive letters to primary partitions */
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
|
|
|
|
if (!IsListEmpty (&DiskEntry->PartListHead))
|
|
{
|
|
PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
for (i=0; i<3; i++)
|
|
PartEntry->DriveLetter[i] = 0;
|
|
|
|
if (PartEntry->Unpartitioned == FALSE)
|
|
{
|
|
for (i=0; i<3; i++)
|
|
{
|
|
if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
|
|
continue;
|
|
|
|
if (IsRecognizedPartition (PartEntry->PartInfo[i].PartitionType) ||
|
|
(PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
|
|
PartEntry->PartInfo[i].PartitionLength.QuadPart != 0LL))
|
|
{
|
|
if (Letter <= 'Z')
|
|
{
|
|
PartEntry->DriveLetter[i] = Letter;
|
|
Letter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
/* Assign drive letters to logical drives */
|
|
#if 0
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
|
|
|
|
Entry2 = DiskEntry->PartListHead.Flink;
|
|
if (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
Entry2 = Entry2->Flink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
PartEntry->DriveLetter = 0;
|
|
|
|
if (PartEntry->Unpartitioned == FALSE &&
|
|
!IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
|
|
{
|
|
if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
|
|
(PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
|
|
PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
|
|
{
|
|
if (Letter <= 'Z')
|
|
{
|
|
PartEntry->DriveLetter = Letter;
|
|
Letter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static VOID
|
|
UpdatePartitionNumbers (PDISKENTRY DiskEntry)
|
|
{
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry;
|
|
ULONG PartNumber;
|
|
ULONG i;
|
|
|
|
PartNumber = 1;
|
|
Entry = DiskEntry->PartListHead.Flink;
|
|
while (Entry != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
if (PartEntry->Unpartitioned == TRUE)
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
PartEntry->PartInfo[i].PartitionNumber = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
|
|
{
|
|
PartEntry->PartInfo[i].PartitionNumber = 0;
|
|
}
|
|
else if (PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
|
|
PartEntry->PartInfo[i].PartitionLength.QuadPart == 0ULL)
|
|
{
|
|
PartEntry->PartInfo[i].PartitionNumber = 0;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->PartInfo[i].PartitionNumber = PartNumber;
|
|
PartNumber++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
AddPartitionToList (ULONG DiskNumber,
|
|
PDISKENTRY DiskEntry,
|
|
DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
|
|
{
|
|
PPARTENTRY PartEntry;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
for (i = 0; i < LayoutBuffer->PartitionCount; i += 4)
|
|
{
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
if (LayoutBuffer->PartitionEntry[i+j].PartitionType != PARTITION_ENTRY_UNUSED ||
|
|
LayoutBuffer->PartitionEntry[i+j].PartitionLength.QuadPart != 0ULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (j >= 4)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
sizeof(PARTENTRY));
|
|
if (PartEntry == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory (PartEntry,
|
|
sizeof(PARTENTRY));
|
|
|
|
PartEntry->Unpartitioned = FALSE;
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
RtlCopyMemory (&PartEntry->PartInfo[j],
|
|
&LayoutBuffer->PartitionEntry[i+j],
|
|
sizeof(PARTITION_INFORMATION));
|
|
}
|
|
|
|
if (IsContainerPartition(PartEntry->PartInfo[0].PartitionType))
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
}
|
|
else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
|
|
(PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
|
|
(PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
|
|
(PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13) ||
|
|
(PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
|
|
(PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
|
|
{
|
|
#if 0
|
|
if (CheckFatFormat())
|
|
{
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
}
|
|
#endif
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2)
|
|
{
|
|
#if 0
|
|
if (CheckExt2Format())
|
|
{
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else
|
|
{
|
|
PartEntry->FormatState = Unformatted;
|
|
}
|
|
#endif
|
|
PartEntry->FormatState = Preformatted;
|
|
}
|
|
else if (PartEntry->PartInfo[0].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;
|
|
}
|
|
|
|
InsertTailList (&DiskEntry->PartListHead,
|
|
&PartEntry->ListEntry);
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry)
|
|
{
|
|
ULONGLONG LastStartingOffset;
|
|
ULONGLONG LastPartitionLength;
|
|
ULONGLONG LastUnusedPartitionLength;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY NewPartEntry;
|
|
PLIST_ENTRY Entry;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
if (IsListEmpty (&DiskEntry->PartListHead))
|
|
{
|
|
/* Create a partition table that represents the empty disk */
|
|
PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
sizeof(PARTENTRY));
|
|
if (PartEntry == NULL)
|
|
return;
|
|
|
|
RtlZeroMemory (PartEntry,
|
|
sizeof(PARTENTRY));
|
|
|
|
PartEntry->Unpartitioned = TRUE;
|
|
PartEntry->UnpartitionedOffset = 0ULL;
|
|
PartEntry->UnpartitionedLength = DiskEntry->DiskSize;
|
|
|
|
PartEntry->FormatState = Unformatted;
|
|
|
|
InsertTailList (&DiskEntry->PartListHead,
|
|
&PartEntry->ListEntry);
|
|
}
|
|
else
|
|
{
|
|
/* Start partition at head 1, cylinder 0 */
|
|
LastStartingOffset = DiskEntry->TrackSize;
|
|
LastPartitionLength = 0ULL;
|
|
LastUnusedPartitionLength = 0ULL;
|
|
|
|
i = 0;
|
|
Entry = DiskEntry->PartListHead.Flink;
|
|
while (Entry != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
if ((!IsContainerPartition (PartEntry->PartInfo[j].PartitionType)) &&
|
|
(PartEntry->PartInfo[j].PartitionType != PARTITION_ENTRY_UNUSED ||
|
|
PartEntry->PartInfo[j].PartitionLength.QuadPart != 0LL))
|
|
{
|
|
LastUnusedPartitionLength =
|
|
PartEntry->PartInfo[j].StartingOffset.QuadPart -
|
|
(LastStartingOffset + LastPartitionLength);
|
|
|
|
if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
|
|
{
|
|
DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
|
|
|
|
NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
RtlZeroMemory (NewPartEntry,
|
|
sizeof(PARTENTRY));
|
|
|
|
NewPartEntry->Unpartitioned = TRUE;
|
|
NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
|
|
NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
|
|
if (j == 0)
|
|
NewPartEntry->UnpartitionedLength -= DiskEntry->TrackSize;
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
|
|
/* Insert the table into the list */
|
|
InsertTailList (&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
|
|
LastStartingOffset = PartEntry->PartInfo[j].StartingOffset.QuadPart;
|
|
LastPartitionLength = PartEntry->PartInfo[j].PartitionLength.QuadPart;
|
|
}
|
|
}
|
|
|
|
i += 4;
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
/* Check for trailing unpartitioned disk space */
|
|
if (DiskEntry->DiskSize > (LastStartingOffset + LastPartitionLength))
|
|
{
|
|
/* Round-down to cylinder size */
|
|
LastUnusedPartitionLength =
|
|
(DiskEntry->DiskSize - (LastStartingOffset + LastPartitionLength))
|
|
& ~(DiskEntry->CylinderSize - 1);
|
|
|
|
if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
|
|
{
|
|
DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
|
|
|
|
NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
RtlZeroMemory (NewPartEntry,
|
|
sizeof(PARTENTRY));
|
|
|
|
NewPartEntry->Unpartitioned = TRUE;
|
|
NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
|
|
NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
|
|
|
|
/* Append the table to the list */
|
|
InsertTailList (&DiskEntry->PartListHead,
|
|
&NewPartEntry->ListEntry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 (FullResourceDescriptor->PartialResourceList.Version != 1 ||
|
|
FullResourceDescriptor->PartialResourceList.Revision != 1)
|
|
return STATUS_UNSUCCESSFUL;*/
|
|
|
|
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 (FullResourceDescriptor->PartialResourceList.Version != 1 ||
|
|
FullResourceDescriptor->PartialResourceList.Revision != 1)
|
|
return STATUS_UNSUCCESSFUL;*/
|
|
|
|
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
|
|
AddDiskToList (HANDLE FileHandle,
|
|
ULONG DiskNumber,
|
|
PPARTLIST List)
|
|
{
|
|
DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
|
|
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;
|
|
|
|
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)
|
|
{
|
|
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 = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
sizeof(DISKENTRY));
|
|
if (DiskEntry == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiskEntry->Checksum = Checksum;
|
|
DiskEntry->Signature = Signature;
|
|
if (Signature == 0)
|
|
{
|
|
/* If we have no signature, set the disk to dirty. WritePartitionsToDisk creates a new signature */
|
|
DiskEntry->Modified = TRUE;
|
|
}
|
|
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)
|
|
{
|
|
RtlFreeHeap(ProcessHeap, 0, DiskEntry);
|
|
return;
|
|
}
|
|
|
|
InitializeListHead (&DiskEntry->PartListHead);
|
|
|
|
DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
|
|
DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
|
|
DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
|
|
DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
|
|
|
|
DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
|
|
DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
|
|
DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
|
|
DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
|
|
|
|
DiskEntry->TrackSize =
|
|
(ULONGLONG)DiskGeometry.SectorsPerTrack *
|
|
(ULONGLONG)DiskGeometry.BytesPerSector;
|
|
DiskEntry->CylinderSize =
|
|
(ULONGLONG)DiskGeometry.TracksPerCylinder *
|
|
DiskEntry->TrackSize;
|
|
DiskEntry->DiskSize =
|
|
DiskGeometry.Cylinders.QuadPart *
|
|
DiskEntry->CylinderSize;
|
|
|
|
DiskEntry->DiskNumber = DiskNumber;
|
|
DiskEntry->Port = ScsiAddress.PortNumber;
|
|
DiskEntry->Bus = ScsiAddress.PathId;
|
|
DiskEntry->Id = ScsiAddress.TargetId;
|
|
|
|
GetDriverName (DiskEntry);
|
|
|
|
InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, BiosDiskNumber);
|
|
|
|
LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
8192);
|
|
if (LayoutBuffer == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Status = NtDeviceIoControlFile (FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
NULL,
|
|
0,
|
|
LayoutBuffer,
|
|
8192);
|
|
if (NT_SUCCESS (Status))
|
|
{
|
|
if (LayoutBuffer->PartitionCount == 0)
|
|
{
|
|
DiskEntry->NewDisk = TRUE;
|
|
}
|
|
|
|
AddPartitionToList (DiskNumber,
|
|
DiskEntry,
|
|
LayoutBuffer);
|
|
|
|
ScanForUnpartitionedDiskSpace (DiskEntry);
|
|
}
|
|
|
|
RtlFreeHeap (ProcessHeap,
|
|
0,
|
|
LayoutBuffer);
|
|
}
|
|
|
|
|
|
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->TopDisk = (ULONG)-1;
|
|
List->TopPartition = (ULONG)-1;
|
|
|
|
List->CurrentDisk = NULL;
|
|
List->CurrentPartition = NULL;
|
|
List->CurrentPartitionNumber = 0;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
AssignDriverLetters (List);
|
|
|
|
List->TopDisk = 0;
|
|
List->TopPartition = 0;
|
|
|
|
/* Search for first usable disk and partition */
|
|
if (IsListEmpty (&List->DiskListHead))
|
|
{
|
|
List->CurrentDisk = NULL;
|
|
List->CurrentPartition = NULL;
|
|
List->CurrentPartitionNumber = 0;
|
|
}
|
|
else
|
|
{
|
|
List->CurrentDisk =
|
|
CONTAINING_RECORD (List->DiskListHead.Flink,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
if (IsListEmpty (&List->CurrentDisk->PartListHead))
|
|
{
|
|
List->CurrentPartition = 0;
|
|
List->CurrentPartitionNumber = 0;
|
|
}
|
|
else
|
|
{
|
|
List->CurrentPartition =
|
|
CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
List->CurrentPartitionNumber = 0;
|
|
}
|
|
}
|
|
|
|
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 partition array */
|
|
while (!IsListEmpty (&DiskEntry->PartListHead))
|
|
{
|
|
Entry = RemoveHeadList (&DiskEntry->PartListHead);
|
|
PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
|
|
|
|
RtlFreeHeap (ProcessHeap,
|
|
0,
|
|
PartEntry);
|
|
}
|
|
|
|
/* 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,
|
|
ULONG PartNumber)
|
|
{
|
|
CHAR LineBuffer[128];
|
|
COORD coPos;
|
|
DWORD Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
|
|
LARGE_INTEGER PartSize;
|
|
PCHAR Unit;
|
|
UCHAR Attribute;
|
|
PCHAR PartType;
|
|
|
|
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->Unpartitioned == TRUE)
|
|
{
|
|
#if 0
|
|
if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
|
|
{
|
|
PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
|
|
Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
#endif
|
|
if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
|
|
{
|
|
PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
|
|
Unit = MUIGetString(STRING_MB);
|
|
}
|
|
else
|
|
{
|
|
PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
|
|
Unit = MUIGetString(STRING_KB);
|
|
}
|
|
|
|
sprintf (LineBuffer,
|
|
MUIGetString(STRING_UNPSPACE),
|
|
PartSize.u.LowPart,
|
|
Unit);
|
|
}
|
|
else
|
|
{
|
|
/* Determine partition type */
|
|
PartType = NULL;
|
|
if (PartEntry->New == TRUE)
|
|
{
|
|
PartType = MUIGetString(STRING_UNFORMATTED);
|
|
}
|
|
else if (PartEntry->Unpartitioned == FALSE)
|
|
{
|
|
if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_12) ||
|
|
(PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_16) ||
|
|
(PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_HUGE) ||
|
|
(PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_XINT13))
|
|
{
|
|
PartType = "FAT";
|
|
}
|
|
else if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32) ||
|
|
(PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32_XINT13))
|
|
{
|
|
PartType = "FAT32";
|
|
}
|
|
else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_EXT2)
|
|
{
|
|
PartType = "EXT2";
|
|
}
|
|
else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_IFS)
|
|
{
|
|
PartType = "NTFS"; /* FIXME: Not quite correct! */
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
|
|
{
|
|
PartSize.QuadPart = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 29)) >> 30;
|
|
Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
#endif
|
|
if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
|
|
{
|
|
PartSize.QuadPart = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 19)) >> 20;
|
|
Unit = MUIGetString(STRING_MB);
|
|
}
|
|
else
|
|
{
|
|
PartSize.QuadPart = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 9)) >> 10;
|
|
Unit = MUIGetString(STRING_KB);
|
|
}
|
|
|
|
if (PartType == NULL)
|
|
{
|
|
sprintf (LineBuffer,
|
|
MUIGetString(STRING_HDDINFOUNK5),
|
|
(PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
|
|
(PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
|
|
PartEntry->PartInfo[PartNumber].PartitionType,
|
|
PartSize.u.LowPart,
|
|
Unit);
|
|
}
|
|
else
|
|
{
|
|
sprintf (LineBuffer,
|
|
"%c%c %-24s %6lu %s",
|
|
(PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
|
|
(PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
|
|
PartType,
|
|
PartSize.u.LowPart,
|
|
Unit);
|
|
}
|
|
}
|
|
|
|
Attribute = (List->CurrentDisk == DiskEntry &&
|
|
List->CurrentPartition == PartEntry &&
|
|
List->CurrentPartitionNumber == PartNumber) ?
|
|
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 PartEntry;
|
|
CHAR LineBuffer[128];
|
|
COORD coPos;
|
|
DWORD Written;
|
|
USHORT Width;
|
|
USHORT Height;
|
|
ULARGE_INTEGER DiskSize;
|
|
PCHAR Unit;
|
|
ULONG i;
|
|
|
|
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 0
|
|
if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
|
|
{
|
|
DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 29)) >> 30;
|
|
Unit = MUIGetString(STRING_GB);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 19)) >> 20;
|
|
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*/
|
|
LIST_FOR_EACH(PartEntry, &DiskEntry->PartListHead, PARTENTRY, ListEntry)
|
|
{
|
|
/* Print disk entry */
|
|
for (i=0; i<4; i++)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED ||
|
|
PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
|
|
{
|
|
PrintPartitionData (List,
|
|
DiskEntry,
|
|
PartEntry,
|
|
i);
|
|
}
|
|
}
|
|
|
|
/* Print unpartitioned entry */
|
|
if (PartEntry->Unpartitioned)
|
|
{
|
|
PrintPartitionData (List,
|
|
DiskEntry,
|
|
PartEntry,
|
|
0);
|
|
}
|
|
|
|
}
|
|
|
|
/* 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->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
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;
|
|
|
|
LIST_FOR_EACH(DiskEntry, &List->DiskListHead, DISKENTRY, ListEntry)
|
|
{
|
|
/* Print disk entry */
|
|
PrintDiskData (List,
|
|
DiskEntry);
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
ULONG i;
|
|
|
|
/* 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->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
|
|
{
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
List->CurrentPartitionNumber = i;
|
|
DrawPartitionList (List);
|
|
return TRUE;
|
|
}
|
|
}
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
return FALSE;
|
|
}
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ScrollDownPartitionList (PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
UCHAR i;
|
|
|
|
/* Check for empty disks */
|
|
if (IsListEmpty (&List->DiskListHead))
|
|
return;
|
|
|
|
/* Check for next usable entry on current disk */
|
|
if (List->CurrentPartition != NULL)
|
|
{
|
|
Entry2 = &List->CurrentPartition->ListEntry;
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
/* Check if we can move inside primary partitions */
|
|
for (i = List->CurrentPartitionNumber + 1; i < 4; i++)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
|
|
break;
|
|
}
|
|
|
|
if (i == 4)
|
|
{
|
|
/* We're out of partitions in the current partition table.
|
|
Try to move to the next one if possible. */
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
else
|
|
{
|
|
/* Just advance to the next partition */
|
|
List->CurrentPartitionNumber = i;
|
|
DrawPartitionList (List);
|
|
return;
|
|
}
|
|
|
|
while (Entry2 != &List->CurrentDisk->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
// if (PartEntry->HidePartEntry == FALSE)
|
|
{
|
|
List->CurrentPartition = PartEntry;
|
|
List->CurrentPartitionNumber = 0;
|
|
DrawPartitionList (List);
|
|
return;
|
|
}
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
}
|
|
|
|
/* Check for first usable entry on next disk */
|
|
if (List->CurrentDisk != NULL)
|
|
{
|
|
Entry1 = List->CurrentDisk->ListEntry.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
|
|
|
|
Entry2 = DiskEntry->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
// if (PartEntry->HidePartEntry == FALSE)
|
|
{
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
List->CurrentPartitionNumber = 0;
|
|
DrawPartitionList (List);
|
|
return;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ScrollUpPartitionList (PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
UCHAR i;
|
|
|
|
/* Check for empty disks */
|
|
if (IsListEmpty (&List->DiskListHead))
|
|
return;
|
|
|
|
/* check for previous usable entry on current disk */
|
|
if (List->CurrentPartition != NULL)
|
|
{
|
|
Entry2 = &List->CurrentPartition->ListEntry;
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
/* Check if we can move inside primary partitions */
|
|
if (List->CurrentPartitionNumber > 0)
|
|
{
|
|
/* Find a previous partition */
|
|
for (i = List->CurrentPartitionNumber - 1; i > 0; i--)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
|
|
break;
|
|
}
|
|
|
|
/* Move to it and return */
|
|
List->CurrentPartitionNumber = i;
|
|
DrawPartitionList (List);
|
|
return;
|
|
}
|
|
|
|
/* Move to the previous entry */
|
|
Entry2 = Entry2->Blink;
|
|
|
|
while (Entry2 != &List->CurrentDisk->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
// if (PartEntry->HidePartEntry == FALSE)
|
|
{
|
|
List->CurrentPartition = PartEntry;
|
|
|
|
/* Find last existing partition in the table */
|
|
for (i = 3; i > 0; i--)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
|
|
break;
|
|
}
|
|
|
|
/* Move to it */
|
|
List->CurrentPartitionNumber = i;
|
|
|
|
/* Draw partition list and return */
|
|
DrawPartitionList (List);
|
|
return;
|
|
}
|
|
Entry2 = Entry2->Blink;
|
|
}
|
|
}
|
|
|
|
|
|
/* check for last usable entry on previous disk */
|
|
if (List->CurrentDisk != NULL)
|
|
{
|
|
Entry1 = List->CurrentDisk->ListEntry.Blink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
|
|
|
|
Entry2 = DiskEntry->PartListHead.Blink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
|
|
|
|
// if (PartEntry->HidePartEntry == FALSE)
|
|
{
|
|
List->CurrentDisk = DiskEntry;
|
|
List->CurrentPartition = PartEntry;
|
|
|
|
/* Find last existing partition in the table */
|
|
for (i = 3; i > 0; i--)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
|
|
break;
|
|
}
|
|
|
|
/* Move to it */
|
|
List->CurrentPartitionNumber = i;
|
|
|
|
/* Draw partition list and return */
|
|
DrawPartitionList (List);
|
|
return;
|
|
}
|
|
|
|
Entry2 = Entry2->Blink;
|
|
}
|
|
|
|
Entry1 = Entry1->Blink;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static PPARTENTRY
|
|
GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
|
|
PPARTENTRY CurrentEntry)
|
|
{
|
|
PPARTENTRY PrevEntry;
|
|
PLIST_ENTRY Entry;
|
|
|
|
if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
|
|
return NULL;
|
|
|
|
Entry = CurrentEntry->ListEntry.Blink;
|
|
while (Entry != &DiskEntry->PartListHead)
|
|
{
|
|
PrevEntry = CONTAINING_RECORD (Entry,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (PrevEntry->Unpartitioned == FALSE)
|
|
return PrevEntry;
|
|
|
|
Entry = Entry->Blink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static PPARTENTRY
|
|
GetNextPartitionedEntry (PDISKENTRY DiskEntry,
|
|
PPARTENTRY CurrentEntry)
|
|
{
|
|
PPARTENTRY NextEntry;
|
|
PLIST_ENTRY Entry;
|
|
|
|
if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
|
|
return NULL;
|
|
|
|
Entry = CurrentEntry->ListEntry.Flink;
|
|
while (Entry != &DiskEntry->PartListHead)
|
|
{
|
|
NextEntry = CONTAINING_RECORD (Entry,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (NextEntry->Unpartitioned == FALSE)
|
|
return NextEntry;
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static PPARTENTRY
|
|
GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
|
|
PPARTENTRY PartEntry)
|
|
{
|
|
PPARTENTRY PrevPartEntry;
|
|
|
|
if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
|
|
{
|
|
PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (PrevPartEntry->Unpartitioned == TRUE)
|
|
return PrevPartEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static PPARTENTRY
|
|
GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
|
|
PPARTENTRY PartEntry)
|
|
{
|
|
PPARTENTRY NextPartEntry;
|
|
|
|
if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
|
|
{
|
|
NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (NextPartEntry->Unpartitioned == TRUE)
|
|
return NextPartEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
CreateNewPartition (PPARTLIST List,
|
|
ULONGLONG PartitionSize,
|
|
BOOLEAN AutoCreate)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY PrevPartEntry;
|
|
PPARTENTRY NextPartEntry;
|
|
PPARTENTRY NewPartEntry;
|
|
|
|
if (List == NULL ||
|
|
List->CurrentDisk == NULL ||
|
|
List->CurrentPartition == NULL ||
|
|
List->CurrentPartition->Unpartitioned == FALSE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
if (AutoCreate == TRUE ||
|
|
PartitionSize == PartEntry->UnpartitionedLength)
|
|
{
|
|
/* Convert current entry to 'new (unformatted)' */
|
|
PartEntry->FormatState = Unformatted;
|
|
PartEntry->PartInfo[0].StartingOffset.QuadPart =
|
|
PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
|
|
PartEntry->PartInfo[0].PartitionLength.QuadPart =
|
|
PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
|
|
PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
|
|
PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
|
|
PartEntry->PartInfo[0].RewritePartition = TRUE;
|
|
PartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
PartEntry->PartInfo[2].RewritePartition = TRUE;
|
|
PartEntry->PartInfo[3].RewritePartition = TRUE;
|
|
|
|
/* Get previous and next partition entries */
|
|
PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
|
|
PartEntry);
|
|
NextPartEntry = GetNextPartitionedEntry (DiskEntry,
|
|
PartEntry);
|
|
|
|
if (PrevPartEntry != NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Current entry is in the middle of the list */
|
|
|
|
/* Copy previous container partition data to current entry */
|
|
RtlCopyMemory (&PartEntry->PartInfo[1],
|
|
&PrevPartEntry->PartInfo[1],
|
|
sizeof(PARTITION_INFORMATION));
|
|
PartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
|
|
/* Update previous container partition data */
|
|
|
|
PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
|
|
PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
|
|
|
|
if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
|
|
{
|
|
/* Special case - previous partition is first partition */
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
|
|
}
|
|
|
|
PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
}
|
|
else if (PrevPartEntry == NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Current entry is the first entry */
|
|
return;
|
|
}
|
|
else if (PrevPartEntry != NULL && NextPartEntry == NULL)
|
|
{
|
|
/* Current entry is the last entry */
|
|
|
|
PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
|
|
PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
|
|
|
|
if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
|
|
{
|
|
/* Special case - previous partition is first partition */
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
|
|
}
|
|
|
|
if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
|
|
PartEntry->PartInfo[1].PartitionLength.QuadPart) <
|
|
(1024LL * 255LL * 63LL * 512LL))
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
|
|
}
|
|
else
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
|
|
}
|
|
|
|
PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
|
|
PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
}
|
|
|
|
PartEntry->AutoCreate = AutoCreate;
|
|
PartEntry->New = TRUE;
|
|
PartEntry->Unpartitioned = FALSE;
|
|
PartEntry->UnpartitionedOffset = 0ULL;
|
|
PartEntry->UnpartitionedLength = 0ULL;
|
|
}
|
|
else
|
|
{
|
|
/* Insert an initialize a new partition entry */
|
|
NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
sizeof(PARTENTRY));
|
|
if (NewPartEntry == NULL)
|
|
return;
|
|
|
|
RtlZeroMemory (NewPartEntry,
|
|
sizeof(PARTENTRY));
|
|
|
|
/* Insert the new entry into the list */
|
|
InsertTailList (&PartEntry->ListEntry,
|
|
&NewPartEntry->ListEntry);
|
|
|
|
NewPartEntry->New = TRUE;
|
|
|
|
NewPartEntry->FormatState = Unformatted;
|
|
NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
|
|
PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
|
|
NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
|
|
PartitionSize - DiskEntry->TrackSize;
|
|
NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
|
|
NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
|
|
NewPartEntry->PartInfo[0].RewritePartition = TRUE;
|
|
NewPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
NewPartEntry->PartInfo[2].RewritePartition = TRUE;
|
|
NewPartEntry->PartInfo[3].RewritePartition = TRUE;
|
|
|
|
/* Get previous and next partition entries */
|
|
PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
|
|
NewPartEntry);
|
|
NextPartEntry = GetNextPartitionedEntry (DiskEntry,
|
|
NewPartEntry);
|
|
|
|
if (PrevPartEntry != NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Current entry is in the middle of the list */
|
|
|
|
/* Copy previous container partition data to current entry */
|
|
RtlCopyMemory (&NewPartEntry->PartInfo[1],
|
|
&PrevPartEntry->PartInfo[1],
|
|
sizeof(PARTITION_INFORMATION));
|
|
NewPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
|
|
/* Update previous container partition data */
|
|
|
|
PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
|
|
NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
|
|
|
|
if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
|
|
{
|
|
/* Special case - previous partition is first partition */
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
|
|
}
|
|
|
|
PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
}
|
|
else if (PrevPartEntry == NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Current entry is the first entry */
|
|
return;
|
|
}
|
|
else if (PrevPartEntry != NULL && NextPartEntry == NULL)
|
|
{
|
|
/* Current entry is the last entry */
|
|
|
|
PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
|
|
NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
|
|
|
|
if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
|
|
{
|
|
/* Special case - previous partition is first partition */
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
|
|
NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
|
|
}
|
|
|
|
if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
|
|
PartEntry->PartInfo[1].PartitionLength.QuadPart) <
|
|
(1024LL * 255LL * 63LL * 512LL))
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
|
|
}
|
|
else
|
|
{
|
|
PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
|
|
}
|
|
|
|
PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
|
|
PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
}
|
|
|
|
/* Update offset and size of the remaining unpartitioned disk space */
|
|
PartEntry->UnpartitionedOffset += PartitionSize;
|
|
PartEntry->UnpartitionedLength -= PartitionSize;
|
|
}
|
|
|
|
DiskEntry->Modified = TRUE;
|
|
|
|
UpdatePartitionNumbers (DiskEntry);
|
|
|
|
AssignDriverLetters (List);
|
|
}
|
|
|
|
|
|
VOID
|
|
DeleteCurrentPartition (PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PPARTENTRY PrevPartEntry;
|
|
PPARTENTRY NextPartEntry;
|
|
|
|
if (List == NULL ||
|
|
List->CurrentDisk == NULL ||
|
|
List->CurrentPartition == NULL ||
|
|
List->CurrentPartition->Unpartitioned == TRUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiskEntry = List->CurrentDisk;
|
|
PartEntry = List->CurrentPartition;
|
|
|
|
/* Adjust container partition entries */
|
|
|
|
/* Get previous and next partition entries */
|
|
PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
|
|
PartEntry);
|
|
NextPartEntry = GetNextPartitionedEntry (DiskEntry,
|
|
PartEntry);
|
|
|
|
if (PrevPartEntry != NULL && NextPartEntry != NULL)
|
|
{
|
|
/* Current entry is in the middle of the list */
|
|
|
|
/*
|
|
* The first extended partition can not be deleted
|
|
* as long as other extended partitions are present.
|
|
*/
|
|
if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
|
|
return;
|
|
|
|
/* Copy previous container partition data to current entry */
|
|
RtlCopyMemory (&PrevPartEntry->PartInfo[1],
|
|
&PartEntry->PartInfo[1],
|
|
sizeof(PARTITION_INFORMATION));
|
|
PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
}
|
|
else if (PrevPartEntry == NULL && NextPartEntry != NULL)
|
|
{
|
|
/*
|
|
* A primary partition can not be deleted as long as
|
|
* extended partitions are present.
|
|
*/
|
|
return;
|
|
}
|
|
else if (PrevPartEntry != NULL && NextPartEntry == NULL)
|
|
{
|
|
/* Current entry is the last entry */
|
|
RtlZeroMemory (&PrevPartEntry->PartInfo[1],
|
|
sizeof(PARTITION_INFORMATION));
|
|
PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
|
|
}
|
|
|
|
|
|
/* 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->UnpartitionedLength +=
|
|
(PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
|
|
NextPartEntry->UnpartitionedLength);
|
|
|
|
/* 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->UnpartitionedLength +=
|
|
(PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
|
|
|
|
/* 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->UnpartitionedOffset =
|
|
PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
|
|
NextPartEntry->UnpartitionedLength +=
|
|
(PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
|
|
|
|
/* 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->New = FALSE;
|
|
PartEntry->Unpartitioned = TRUE;
|
|
PartEntry->UnpartitionedOffset =
|
|
PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
|
|
PartEntry->UnpartitionedLength =
|
|
PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
|
|
|
|
/* Wipe the partition table */
|
|
RtlZeroMemory (&PartEntry->PartInfo,
|
|
sizeof(PartEntry->PartInfo));
|
|
}
|
|
|
|
DiskEntry->Modified = TRUE;
|
|
|
|
UpdatePartitionNumbers (DiskEntry);
|
|
|
|
AssignDriverLetters (List);
|
|
}
|
|
|
|
|
|
VOID
|
|
CheckActiveBootPartition (PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY ListEntry;
|
|
UCHAR i;
|
|
|
|
/* Check for empty disk list */
|
|
if (IsListEmpty (&List->DiskListHead))
|
|
{
|
|
List->ActiveBootDisk = NULL;
|
|
List->ActiveBootPartition = NULL;
|
|
List->ActiveBootPartitionNumber = 0;
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
if (List->ActiveBootDisk != NULL &&
|
|
List->ActiveBootPartition != NULL)
|
|
{
|
|
/* We already have an active boot partition */
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
/* Check for empty partition list */
|
|
if (IsListEmpty (&DiskEntry->PartListHead))
|
|
{
|
|
List->ActiveBootDisk = NULL;
|
|
List->ActiveBootPartition = NULL;
|
|
List->ActiveBootPartitionNumber = 0;
|
|
return;
|
|
}
|
|
|
|
PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
/* Set active boot partition */
|
|
if ((DiskEntry->NewDisk == TRUE) ||
|
|
(PartEntry->PartInfo[0].BootIndicator == FALSE &&
|
|
PartEntry->PartInfo[1].BootIndicator == FALSE &&
|
|
PartEntry->PartInfo[2].BootIndicator == FALSE &&
|
|
PartEntry->PartInfo[3].BootIndicator == FALSE))
|
|
{
|
|
PartEntry->PartInfo[0].BootIndicator = TRUE;
|
|
PartEntry->PartInfo[0].RewritePartition = TRUE;
|
|
DiskEntry->Modified = TRUE;
|
|
|
|
/* FIXME: Might be incorrect if partitions were created by Linux FDISK */
|
|
List->ActiveBootDisk = DiskEntry;
|
|
List->ActiveBootPartition = PartEntry;
|
|
List->ActiveBootPartitionNumber = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
/* Disk is not new, scan all partitions to find a bootable one */
|
|
List->ActiveBootDisk = NULL;
|
|
List->ActiveBootPartition = NULL;
|
|
List->ActiveBootPartitionNumber = 0;
|
|
|
|
ListEntry = DiskEntry->PartListHead.Flink;
|
|
while (ListEntry != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(ListEntry,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
/* Check if it's partitioned */
|
|
if (!PartEntry->Unpartitioned)
|
|
{
|
|
/* Go through all of its 4 partitions */
|
|
for (i=0; i<4; i++)
|
|
{
|
|
if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED &&
|
|
PartEntry->PartInfo[i].BootIndicator)
|
|
{
|
|
/* Yes, we found it */
|
|
List->ActiveBootDisk = DiskEntry;
|
|
List->ActiveBootPartition = PartEntry;
|
|
List->ActiveBootPartitionNumber = i;
|
|
|
|
DPRINT("Found bootable partition disk %d, drive letter %c\n",
|
|
DiskEntry->BiosDiskNumber, PartEntry->DriveLetter[i]);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* Go to the next one */
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CheckForLinuxFdiskPartitions (PPARTLIST List)
|
|
{
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
ULONG PartitionCount;
|
|
ULONG i;
|
|
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD (Entry1,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
Entry2 = DiskEntry->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
|
|
if (PartEntry->Unpartitioned == FALSE)
|
|
{
|
|
PartitionCount = 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
|
|
PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
|
|
{
|
|
PartitionCount++;
|
|
}
|
|
}
|
|
|
|
if (PartitionCount > 1)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
WritePartitionsToDisk (PPARTLIST List)
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION DriveLayout;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK Iosb;
|
|
WCHAR SrcPath[MAX_PATH];
|
|
WCHAR DstPath[MAX_PATH];
|
|
UNICODE_STRING Name;
|
|
HANDLE FileHandle;
|
|
PDISKENTRY DiskEntry1;
|
|
PDISKENTRY DiskEntry2;
|
|
PPARTENTRY PartEntry;
|
|
PLIST_ENTRY Entry1;
|
|
PLIST_ENTRY Entry2;
|
|
ULONG PartitionCount;
|
|
ULONG DriveLayoutSize;
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
if (List == NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry1 = CONTAINING_RECORD (Entry1,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
if (DiskEntry1->Modified == TRUE)
|
|
{
|
|
/* Count partitioned entries */
|
|
PartitionCount = 0;
|
|
Entry2 = DiskEntry1->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry1->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (PartEntry->Unpartitioned == FALSE)
|
|
{
|
|
PartitionCount += 4;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
if (PartitionCount == 0)
|
|
{
|
|
DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
|
|
((4 - 1) * sizeof (PARTITION_INFORMATION));
|
|
}
|
|
else
|
|
{
|
|
DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
|
|
((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
|
|
}
|
|
DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
|
|
0,
|
|
DriveLayoutSize);
|
|
if (DriveLayout == NULL)
|
|
{
|
|
DPRINT1 ("RtlAllocateHeap() failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory (DriveLayout,
|
|
DriveLayoutSize);
|
|
|
|
if (PartitionCount == 0)
|
|
{
|
|
/* delete all partitions in the mbr */
|
|
DriveLayout->PartitionCount = 4;
|
|
for (Index = 0; Index < 4; Index++)
|
|
{
|
|
DriveLayout->PartitionEntry[Index].RewritePartition = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DriveLayout->PartitionCount = PartitionCount;
|
|
|
|
Index = 0;
|
|
Entry2 = DiskEntry1->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry1->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD (Entry2,
|
|
PARTENTRY,
|
|
ListEntry);
|
|
if (PartEntry->Unpartitioned == FALSE)
|
|
{
|
|
RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
|
|
&PartEntry->PartInfo[0],
|
|
4 * sizeof (PARTITION_INFORMATION));
|
|
Index += 4;
|
|
}
|
|
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
}
|
|
if (DiskEntry1->Signature == 0)
|
|
{
|
|
LARGE_INTEGER SystemTime;
|
|
TIME_FIELDS TimeFields;
|
|
PUCHAR Buffer;
|
|
Buffer = (PUCHAR)&DiskEntry1->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 (DiskEntry1->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 (DiskEntry1 != DiskEntry2 &&
|
|
DiskEntry1->Signature == DiskEntry2->Signature)
|
|
{
|
|
break;
|
|
}
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
if (Entry2 == &List->DiskListHead)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* set one partition entry to dirty, this will update the signature */
|
|
DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
|
|
|
|
}
|
|
|
|
DriveLayout->Signature = DiskEntry1->Signature;
|
|
|
|
|
|
swprintf (DstPath,
|
|
L"\\Device\\Harddisk%d\\Partition0",
|
|
DiskEntry1->DiskNumber);
|
|
RtlInitUnicodeString (&Name,
|
|
DstPath);
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
&Name,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenFile (&FileHandle,
|
|
FILE_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
if (!NT_SUCCESS (Status))
|
|
{
|
|
DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtDeviceIoControlFile (FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DISK_SET_DRIVE_LAYOUT,
|
|
DriveLayout,
|
|
DriveLayoutSize,
|
|
NULL,
|
|
0);
|
|
if (!NT_SUCCESS (Status))
|
|
{
|
|
DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
|
|
NtClose (FileHandle);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlFreeHeap (ProcessHeap,
|
|
0,
|
|
DriveLayout);
|
|
|
|
NtClose (FileHandle);
|
|
|
|
/* Install MBR code if the disk is new */
|
|
if (DiskEntry1->NewDisk == TRUE &&
|
|
DiskEntry1->BiosDiskNumber == 0)
|
|
{
|
|
wcscpy (SrcPath, SourceRootPath.Buffer);
|
|
wcscat (SrcPath, L"\\loader\\dosmbr.bin");
|
|
|
|
DPRINT ("Install MBR bootcode: %S ==> %S\n",
|
|
SrcPath, DstPath);
|
|
|
|
/* Install MBR bootcode */
|
|
Status = InstallMbrBootCodeToDisk (SrcPath,
|
|
DstPath);
|
|
if (!NT_SUCCESS (Status))
|
|
{
|
|
DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
|
|
Status);
|
|
return FALSE;
|
|
}
|
|
|
|
DiskEntry1->NewDisk = FALSE;
|
|
DiskEntry1->NoMbr = FALSE;
|
|
}
|
|
}
|
|
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SetMountedDeviceValues(PPARTLIST List)
|
|
{
|
|
PLIST_ENTRY Entry1, Entry2;
|
|
PDISKENTRY DiskEntry;
|
|
PPARTENTRY PartEntry;
|
|
UCHAR i;
|
|
|
|
if (List == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Entry1 = List->DiskListHead.Flink;
|
|
while (Entry1 != &List->DiskListHead)
|
|
{
|
|
DiskEntry = CONTAINING_RECORD (Entry1,
|
|
DISKENTRY,
|
|
ListEntry);
|
|
|
|
Entry2 = DiskEntry->PartListHead.Flink;
|
|
while (Entry2 != &DiskEntry->PartListHead)
|
|
{
|
|
PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
|
|
if (!PartEntry->Unpartitioned)
|
|
{
|
|
for (i=0; i<4; i++)
|
|
{
|
|
if (PartEntry->DriveLetter[i])
|
|
{
|
|
if (!SetMountedDeviceValue(PartEntry->DriveLetter[i], DiskEntry->Signature, PartEntry->PartInfo[i].StartingOffset))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Entry2 = Entry2->Flink;
|
|
}
|
|
Entry1 = Entry1->Flink;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|