reactos/base/setup/usetup/partlist.c
Timo Kreuzer 9ea495ba33 Create a branch for header work.
svn path=/branches/header-work/; revision=45691
2010-02-26 22:57:55 +00:00

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 */