reactos/ntoskrnl/fstub/disksup.c
2018-12-30 15:26:43 +01:00

2365 lines
82 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/fstub/disksup.c
* PURPOSE: I/O HAL Routines for Disk Access
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
* Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#include <internal/hal.h>
/* DEPRECATED FUNCTIONS ******************************************************/
#if 1
const WCHAR DiskMountString[] = L"\\DosDevices\\%C:";
#define AUTO_DRIVE MAXULONG
#define PARTITION_MAGIC 0xaa55
#define EFI_PMBR_OSTYPE_EFI 0xEE
#include <pshpack1.h>
typedef struct _REG_DISK_MOUNT_INFO
{
ULONG Signature;
LARGE_INTEGER StartingOffset;
} REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
#include <poppack.h>
typedef enum _DISK_MANAGER
{
NoDiskManager,
OntrackDiskManager,
EZ_Drive
} DISK_MANAGER;
static BOOLEAN
HalpAssignDrive(IN PUNICODE_STRING PartitionName,
IN ULONG DriveNumber,
IN UCHAR DriveType,
IN ULONG Signature,
IN LARGE_INTEGER StartingOffset,
IN HANDLE hKey,
IN PUNICODE_STRING BootDevice,
OUT PUCHAR NtSystemPath)
{
WCHAR DriveNameBuffer[16];
UNICODE_STRING DriveName;
ULONG i;
NTSTATUS Status;
REG_DISK_MOUNT_INFO DiskMountInfo;
DPRINT("HalpAssignDrive()\n");
if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 26))
{
/* Force assignment */
KeAcquireGuardedMutex(&ObpDeviceMapLock);
if ((ObSystemDeviceMap->DriveMap & (1 << DriveNumber)) != 0)
{
DbgPrint("Drive letter already used!\n");
KeReleaseGuardedMutex(&ObpDeviceMapLock);
return FALSE;
}
KeReleaseGuardedMutex(&ObpDeviceMapLock);
}
else
{
/* Automatic assignment */
DriveNumber = AUTO_DRIVE;
KeAcquireGuardedMutex(&ObpDeviceMapLock);
for (i = 2; i < 26; i++)
{
if ((ObSystemDeviceMap->DriveMap & (1 << i)) == 0)
{
DriveNumber = i;
break;
}
}
KeReleaseGuardedMutex(&ObpDeviceMapLock);
if (DriveNumber == AUTO_DRIVE)
{
DbgPrint("No drive letter available!\n");
return FALSE;
}
}
DPRINT("DriveNumber %lu\n", DriveNumber);
/* Build drive name */
swprintf(DriveNameBuffer,
L"\\??\\%C:",
'A' + DriveNumber);
RtlInitUnicodeString(&DriveName,
DriveNameBuffer);
DPRINT(" %wZ ==> %wZ\n",
&DriveName,
PartitionName);
/* Create symbolic link */
Status = IoCreateSymbolicLink(&DriveName,
PartitionName);
if (hKey &&
DriveType == DOSDEVICE_DRIVE_FIXED &&
Signature)
{
DiskMountInfo.Signature = Signature;
DiskMountInfo.StartingOffset = StartingOffset;
swprintf(DriveNameBuffer, DiskMountString, L'A' + DriveNumber);
RtlInitUnicodeString(&DriveName, DriveNameBuffer);
Status = ZwSetValueKey(hKey,
&DriveName,
0,
REG_BINARY,
&DiskMountInfo,
sizeof(DiskMountInfo));
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName, Status);
}
}
/* Check if this is a boot partition */
if (RtlCompareUnicodeString(PartitionName, BootDevice, FALSE) == 0)
{
/* Set NtSystemPath to that partition's disk letter */
*NtSystemPath = (UCHAR)('A' + DriveNumber);
}
return TRUE;
}
ULONG
xHalpGetRDiskCount(VOID)
{
NTSTATUS Status;
UNICODE_STRING ArcName;
PWCHAR ArcNameBuffer;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE DirectoryHandle;
POBJECT_DIRECTORY_INFORMATION DirectoryInfo;
ULONG Skip;
ULONG ResultLength;
ULONG CurrentRDisk;
ULONG RDiskCount;
BOOLEAN First = TRUE;
ULONG Count;
DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 2 * PAGE_SIZE, TAG_FILE_SYSTEM);
if (DirectoryInfo == NULL)
{
return 0;
}
RtlInitUnicodeString(&ArcName, L"\\ArcName");
InitializeObjectAttributes(&ObjectAttributes,
&ArcName,
0,
NULL,
NULL);
Status = ZwOpenDirectoryObject (&DirectoryHandle,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName, Status);
ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
return 0;
}
RDiskCount = 0;
Skip = 0;
while (NT_SUCCESS(Status))
{
Status = ZwQueryDirectoryObject (DirectoryHandle,
DirectoryInfo,
2 * PAGE_SIZE,
FALSE,
First,
&Skip,
&ResultLength);
First = FALSE;
if (NT_SUCCESS(Status))
{
Count = 0;
while (DirectoryInfo[Count].Name.Buffer)
{
DPRINT("Count %x\n", Count);
DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0;
ArcNameBuffer = DirectoryInfo[Count].Name.Buffer;
if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) &&
!_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR)))
{
DPRINT("%S\n", ArcNameBuffer);
ArcNameBuffer += (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR);
CurrentRDisk = 0;
while (iswdigit(*ArcNameBuffer))
{
CurrentRDisk = CurrentRDisk * 10 + *ArcNameBuffer - L'0';
ArcNameBuffer++;
}
if (!_wcsicmp(ArcNameBuffer, L")") &&
CurrentRDisk >= RDiskCount)
{
RDiskCount = CurrentRDisk + 1;
}
}
Count++;
}
}
}
ZwClose(DirectoryHandle);
ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
return RDiskCount;
}
NTSTATUS
xHalpGetDiskNumberFromRDisk(ULONG RDisk, PULONG DiskNumber)
{
WCHAR NameBuffer[80];
UNICODE_STRING ArcName;
UNICODE_STRING LinkName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE LinkHandle;
NTSTATUS Status;
swprintf(NameBuffer,
L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
RDisk);
RtlInitUnicodeString(&ArcName, NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&ArcName,
0,
NULL,
NULL);
Status = ZwOpenSymbolicLinkObject(&LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName, Status);
return Status;
}
LinkName.Buffer = NameBuffer;
LinkName.Length = 0;
LinkName.MaximumLength = sizeof(NameBuffer);
Status = ZwQuerySymbolicLinkObject(LinkHandle,
&LinkName,
NULL);
ZwClose(LinkHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status);
return Status;
}
if (LinkName.Length < sizeof(L"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR) ||
LinkName.Length >= sizeof(NameBuffer))
{
return STATUS_UNSUCCESSFUL;
}
NameBuffer[LinkName.Length / sizeof(WCHAR)] = 0;
if (_wcsnicmp(NameBuffer, L"\\Device\\Harddisk", (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR)))
{
return STATUS_UNSUCCESSFUL;
}
LinkName.Buffer += (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR);
if (!iswdigit(*LinkName.Buffer))
{
return STATUS_UNSUCCESSFUL;
}
*DiskNumber = 0;
while (iswdigit(*LinkName.Buffer))
{
*DiskNumber = *DiskNumber * 10 + *LinkName.Buffer - L'0';
LinkName.Buffer++;
}
if (_wcsicmp(LinkName.Buffer, L"\\Partition0"))
{
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
NTSTATUS
FASTCALL
xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
{
IO_STATUS_BLOCK StatusBlock;
DISK_GEOMETRY DiskGeometry;
PDEVICE_OBJECT DeviceObject = NULL;
PFILE_OBJECT FileObject;
KEVENT Event;
PIRP Irp;
NTSTATUS Status;
DPRINT("xHalpQueryDriveLayout %wZ %p\n",
DeviceName,
LayoutInfo);
/* Get the drives sector size */
Status = IoGetDeviceObjectPointer(DeviceName,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT("Status %x\n", Status);
return(Status);
}
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
DeviceObject,
NULL,
0,
&DiskGeometry,
sizeof(DISK_GEOMETRY),
FALSE,
&Event,
&StatusBlock);
if (Irp == NULL)
{
ObDereferenceObject(FileObject);
return(STATUS_INSUFFICIENT_RESOURCES);
}
Status = IoCallDriver(DeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = StatusBlock.Status;
}
if (!NT_SUCCESS(Status))
{
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
{
DiskGeometry.BytesPerSector = 512;
}
else
{
ObDereferenceObject(FileObject);
return(Status);
}
}
DPRINT("DiskGeometry.BytesPerSector: %lu\n",
DiskGeometry.BytesPerSector);
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
{
PDRIVE_LAYOUT_INFORMATION Buffer;
/* Allocate a partition list for a single entry. */
Buffer = ExAllocatePoolWithTag(NonPagedPool,
sizeof(DRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
if (Buffer != NULL)
{
RtlZeroMemory(Buffer,
sizeof(DRIVE_LAYOUT_INFORMATION));
Buffer->PartitionCount = 1;
*LayoutInfo = Buffer;
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
}
else
{
/* Read the partition table */
Status = IoReadPartitionTable(DeviceObject,
DiskGeometry.BytesPerSector,
TRUE,
LayoutInfo);
}
ObDereferenceObject(FileObject);
return(Status);
}
VOID
FASTCALL
xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PSTRING NtDeviceName,
OUT PUCHAR NtSystemPath,
OUT PSTRING NtSystemPathString)
{
PDRIVE_LAYOUT_INFORMATION *LayoutArray;
PCONFIGURATION_INFORMATION ConfigInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK StatusBlock;
UNICODE_STRING UnicodeString1;
UNICODE_STRING UnicodeString2;
HANDLE FileHandle;
PWSTR Buffer1;
PWSTR Buffer2;
ULONG i, j, k;
ULONG DiskNumber;
ULONG RDisk;
NTSTATUS Status;
HANDLE hKey;
ULONG Length;
PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
PREG_DISK_MOUNT_INFO DiskMountInfo;
ULONG RDiskCount;
UNICODE_STRING BootDevice;
Status = RtlAnsiStringToUnicodeString(&BootDevice,
NtDeviceName,
TRUE);
DPRINT("xHalIoAssignDriveLetters()\n");
ConfigInfo = IoGetConfigurationInformation();
RDiskCount = xHalpGetRDiskCount();
DPRINT("RDiskCount %lu\n", RDiskCount);
Buffer1 = ExAllocatePoolWithTag(PagedPool,
64 * sizeof(WCHAR),
TAG_FILE_SYSTEM);
if (!Buffer1) return;
Buffer2 = ExAllocatePoolWithTag(PagedPool,
32 * sizeof(WCHAR),
TAG_FILE_SYSTEM);
if (!Buffer2)
{
ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
return;
}
PartialInformation = ExAllocatePoolWithTag(PagedPool,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
TAG_FILE_SYSTEM);
if (!PartialInformation)
{
ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
return;
}
DiskMountInfo = (PREG_DISK_MOUNT_INFO) PartialInformation->Data;
/* Create or open the 'MountedDevices' key */
RtlInitUnicodeString(&UnicodeString1, L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString1,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwCreateKey(&hKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (!NT_SUCCESS(Status))
{
hKey = NULL;
DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1, Status);
}
/* Create PhysicalDrive links */
DPRINT("Physical disk drives: %lu\n", ConfigInfo->DiskCount);
for (i = 0; i < ConfigInfo->DiskCount; i++)
{
swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i);
RtlInitUnicodeString(&UnicodeString1, Buffer1);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString1,
0,
NULL,
NULL);
Status = ZwOpenFile(&FileHandle,
FILE_READ_DATA | SYNCHRONIZE,
&ObjectAttributes,
&StatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
if (NT_SUCCESS(Status))
{
ZwClose(FileHandle);
swprintf(Buffer2, L"\\??\\PhysicalDrive%lu", i);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
DPRINT("Creating link: %S ==> %S\n",
Buffer2,
Buffer1);
IoCreateSymbolicLink(&UnicodeString2,
&UnicodeString1);
}
}
/* Initialize layout array */
if (ConfigInfo->DiskCount == 0)
goto end_assign_disks;
LayoutArray = ExAllocatePoolWithTag(NonPagedPool,
ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
if (!LayoutArray)
{
ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
if (hKey) ObCloseHandle(hKey, KernelMode);
return;
}
RtlZeroMemory(LayoutArray,
ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
for (i = 0; i < ConfigInfo->DiskCount; i++)
{
swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i);
RtlInitUnicodeString(&UnicodeString1, Buffer1);
Status = xHalQueryDriveLayout(&UnicodeString1, &LayoutArray[i]);
if (!NT_SUCCESS(Status))
{
DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
Status);
LayoutArray[i] = NULL;
continue;
}
/* We don't use the RewritePartition value while mounting the disks.
* We use this value for marking pre-assigned (registry) partitions.
*/
for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
{
LayoutArray[i]->PartitionEntry[j].RewritePartition = FALSE;
}
}
#ifndef NDEBUG
/* Dump layout array */
for (i = 0; i < ConfigInfo->DiskCount; i++)
{
DPRINT("Harddisk %d:\n",
i);
if (LayoutArray[i] == NULL)
continue;
DPRINT("Logical partitions: %d\n",
LayoutArray[i]->PartitionCount);
for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
{
DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
j,
LayoutArray[i]->PartitionEntry[j].PartitionNumber,
LayoutArray[i]->PartitionEntry[j].BootIndicator,
LayoutArray[i]->PartitionEntry[j].PartitionType,
LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
}
}
#endif
/* Assign pre-assigned (registry) partitions */
if (hKey)
{
for (k = 2; k < 26; k++)
{
swprintf(Buffer1, DiskMountString, L'A' + k);
RtlInitUnicodeString(&UnicodeString1, Buffer1);
Status = ZwQueryValueKey(hKey,
&UnicodeString1,
KeyValuePartialInformation,
PartialInformation,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
&Length);
if (NT_SUCCESS(Status) &&
PartialInformation->Type == REG_BINARY &&
PartialInformation->DataLength == sizeof(REG_DISK_MOUNT_INFO))
{
DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1, DiskMountInfo->Signature,
DiskMountInfo->StartingOffset.u.HighPart, DiskMountInfo->StartingOffset.u.LowPart);
{
BOOLEAN Found = FALSE;
for (i = 0; i < ConfigInfo->DiskCount; i++)
{
DPRINT("%x\n", LayoutArray[i]->Signature);
if (LayoutArray[i] &&
LayoutArray[i]->Signature &&
LayoutArray[i]->Signature == DiskMountInfo->Signature)
{
for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
{
if (LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart == DiskMountInfo->StartingOffset.QuadPart)
{
if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
LayoutArray[i]->PartitionEntry[j].RewritePartition == FALSE)
{
swprintf(Buffer2,
L"\\Device\\Harddisk%lu\\Partition%lu",
i,
LayoutArray[i]->PartitionEntry[j].PartitionNumber);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n", &UnicodeString2);
Found = HalpAssignDrive(&UnicodeString2,
k,
DOSDEVICE_DRIVE_FIXED,
DiskMountInfo->Signature,
DiskMountInfo->StartingOffset,
NULL,
&BootDevice,
NtSystemPath);
/* Mark the partition as assigned */
LayoutArray[i]->PartitionEntry[j].RewritePartition = TRUE;
}
break;
}
}
}
}
if (Found == FALSE)
{
/* We didn't find a partition for this entry, remove them. */
Status = ZwDeleteValueKey(hKey, &UnicodeString1);
}
}
}
}
}
/* Assign bootable partition on first harddisk */
DPRINT("Assigning bootable primary partition on first harddisk:\n");
if (RDiskCount > 0)
{
Status = xHalpGetDiskNumberFromRDisk(0, &DiskNumber);
if (NT_SUCCESS(Status) &&
DiskNumber < ConfigInfo->DiskCount &&
LayoutArray[DiskNumber])
{
/* Search for bootable partition */
for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES && j < LayoutArray[DiskNumber]->PartitionCount; j++)
{
if ((LayoutArray[DiskNumber]->PartitionEntry[j].BootIndicator != FALSE) &&
IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
{
if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE)
{
swprintf(Buffer2,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n", &UnicodeString2);
HalpAssignDrive(&UnicodeString2,
AUTO_DRIVE,
DOSDEVICE_DRIVE_FIXED,
LayoutArray[DiskNumber]->Signature,
LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
hKey,
&BootDevice,
NtSystemPath);
/* Mark the partition as assigned */
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
}
break;
}
}
}
}
/* Assign remaining primary partitions */
DPRINT("Assigning remaining primary partitions:\n");
for (RDisk = 0; RDisk < RDiskCount; RDisk++)
{
Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
if (NT_SUCCESS(Status) &&
DiskNumber < ConfigInfo->DiskCount &&
LayoutArray[DiskNumber])
{
/* Search for primary partitions */
for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
{
if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
{
swprintf(Buffer2,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n",
&UnicodeString2);
HalpAssignDrive(&UnicodeString2,
AUTO_DRIVE,
DOSDEVICE_DRIVE_FIXED,
LayoutArray[DiskNumber]->Signature,
LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
hKey,
&BootDevice,
NtSystemPath);
/* Mark the partition as assigned */
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
}
}
}
}
/* Assign extended (logical) partitions */
DPRINT("Assigning extended (logical) partitions:\n");
for (RDisk = 0; RDisk < RDiskCount; RDisk++)
{
Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
if (NT_SUCCESS(Status) &&
DiskNumber < ConfigInfo->DiskCount &&
LayoutArray[DiskNumber])
{
/* Search for extended partitions */
for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
{
if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
{
swprintf(Buffer2,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n",
&UnicodeString2);
HalpAssignDrive(&UnicodeString2,
AUTO_DRIVE,
DOSDEVICE_DRIVE_FIXED,
LayoutArray[DiskNumber]->Signature,
LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
hKey,
&BootDevice,
NtSystemPath);
/* Mark the partition as assigned */
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
}
}
}
}
/* Assign remaining primary partitions without an arc-name */
DPRINT("Assigning remaining primary partitions:\n");
for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
{
if (LayoutArray[DiskNumber])
{
/* Search for primary partitions */
for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
{
if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
{
swprintf(Buffer2,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n",
&UnicodeString2);
HalpAssignDrive(&UnicodeString2,
AUTO_DRIVE,
DOSDEVICE_DRIVE_FIXED,
LayoutArray[DiskNumber]->Signature,
LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
hKey,
&BootDevice,
NtSystemPath);
/* Mark the partition as assigned */
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
}
}
}
}
/* Assign extended (logical) partitions without an arc-name */
DPRINT("Assigning extended (logical) partitions:\n");
for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
{
if (LayoutArray[DiskNumber])
{
/* Search for extended partitions */
for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
{
if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
{
swprintf(Buffer2,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n",
&UnicodeString2);
HalpAssignDrive(&UnicodeString2,
AUTO_DRIVE,
DOSDEVICE_DRIVE_FIXED,
LayoutArray[DiskNumber]->Signature,
LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
hKey,
&BootDevice,
NtSystemPath);
/* Mark the partition as assigned */
LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
}
}
}
}
/* Assign removable disk drives */
DPRINT("Assigning removable disk drives:\n");
for (i = 0; i < ConfigInfo->DiskCount; i++)
{
if (LayoutArray[i])
{
/* Search for virtual partitions */
if (LayoutArray[i]->PartitionCount == 1 &&
LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
{
swprintf(Buffer2, L"\\Device\\Harddisk%lu\\Partition1", i);
RtlInitUnicodeString(&UnicodeString2, Buffer2);
/* Assign drive */
DPRINT(" %wZ\n",
&UnicodeString2);
HalpAssignDrive(&UnicodeString2,
AUTO_DRIVE,
DOSDEVICE_DRIVE_REMOVABLE,
0,
RtlConvertLongToLargeInteger(0),
hKey,
&BootDevice,
NtSystemPath);
}
}
}
/* Free layout array */
for (i = 0; i < ConfigInfo->DiskCount; i++)
{
if (LayoutArray[i] != NULL)
ExFreePoolWithTag(LayoutArray[i], TAG_FILE_SYSTEM);
}
ExFreePoolWithTag(LayoutArray, TAG_FILE_SYSTEM);
end_assign_disks:
/* Assign floppy drives */
DPRINT("Floppy drives: %lu\n", ConfigInfo->FloppyCount);
for (i = 0; i < ConfigInfo->FloppyCount; i++)
{
swprintf(Buffer1, L"\\Device\\Floppy%lu", i);
RtlInitUnicodeString(&UnicodeString1, Buffer1);
/* Assign drive letters A: or B: or first free drive letter */
DPRINT(" %wZ\n",
&UnicodeString1);
HalpAssignDrive(&UnicodeString1,
(i < 2) ? i : AUTO_DRIVE,
DOSDEVICE_DRIVE_REMOVABLE,
0,
RtlConvertLongToLargeInteger(0),
hKey,
&BootDevice,
NtSystemPath);
}
/* Assign cdrom drives */
DPRINT("CD-Rom drives: %lu\n", ConfigInfo->CdRomCount);
for (i = 0; i < ConfigInfo->CdRomCount; i++)
{
swprintf(Buffer1, L"\\Device\\CdRom%lu", i);
RtlInitUnicodeString(&UnicodeString1, Buffer1);
/* Assign first free drive letter */
DPRINT(" %wZ\n", &UnicodeString1);
HalpAssignDrive(&UnicodeString1,
AUTO_DRIVE,
DOSDEVICE_DRIVE_CDROM,
0,
RtlConvertLongToLargeInteger(0),
hKey,
&BootDevice,
NtSystemPath);
}
/* Anything else to do? */
ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
if (hKey) ObCloseHandle(hKey, KernelMode);
}
#endif
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
NTAPI
HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject,
IN PDISK_GEOMETRY Geometry,
OUT PULONGLONG RealSectorCount)
{
PIRP Irp;
IO_STATUS_BLOCK IoStatusBlock;
PKEVENT Event;
NTSTATUS Status;
PARTITION_INFORMATION PartitionInfo;
PAGED_CODE();
/* Allocate a non-paged event */
Event = ExAllocatePoolWithTag(NonPagedPool,
sizeof(KEVENT),
TAG_FILE_SYSTEM);
if (!Event) return STATUS_INSUFFICIENT_RESOURCES;
/* Initialize it */
KeInitializeEvent(Event, NotificationEvent, FALSE);
/* Build the IRP */
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
DeviceObject,
NULL,
0UL,
Geometry,
sizeof(DISK_GEOMETRY),
FALSE,
Event,
&IoStatusBlock);
if (!Irp)
{
/* Fail, free the event */
ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Call the driver and check if it's pending */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on the driver */
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Check if the driver returned success */
if(NT_SUCCESS(Status))
{
/* Build another IRP */
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
DeviceObject,
NULL,
0UL,
&PartitionInfo,
sizeof(PARTITION_INFORMATION),
FALSE,
Event,
&IoStatusBlock);
if (!Irp)
{
/* Fail, free the event */
ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Reset event */
KeClearEvent(Event);
/* Call the driver and check if it's pending */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on the driver */
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Check if the driver returned success */
if(NT_SUCCESS(Status))
{
/* Get the number of sectors */
*RealSectorCount = (PartitionInfo.PartitionLength.QuadPart /
Geometry->BytesPerSector);
}
}
/* Free the event and return the Status */
ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
return Status;
}
BOOLEAN
NTAPI
HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry,
IN ULONGLONG MaxOffset,
IN ULONGLONG MaxSector)
{
ULONGLONG EndingSector;
PAGED_CODE();
/* Unused partitions are considered valid */
if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE;
/* Get the last sector of the partition */
EndingSector = GET_STARTING_SECTOR(Entry) + GET_PARTITION_LENGTH(Entry);
/* Check if it's more then the maximum sector */
if (EndingSector > MaxSector)
{
/* Invalid partition */
DPRINT1("FSTUB: entry is invalid\n");
DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
DPRINT1("FSTUB: end %#I64x\n", EndingSector);
DPRINT1("FSTUB: max %#I64x\n", MaxSector);
return FALSE;
}
else if(GET_STARTING_SECTOR(Entry) > MaxOffset)
{
/* Invalid partition */
DPRINT1("FSTUB: entry is invalid\n");
DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
DPRINT1("FSTUB: end %#I64x\n", EndingSector);
DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset);
return FALSE;
}
/* It's fine, return success */
return TRUE;
}
VOID
NTAPI
HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset,
IN PLARGE_INTEGER PartitionLength,
IN CCHAR ShiftCount,
IN ULONG SectorsPerTrack,
IN ULONG NumberOfTracks,
IN ULONG ConventionalCylinders,
OUT PPARTITION_DESCRIPTOR PartitionDescriptor)
{
LARGE_INTEGER FirstSector, SectorCount;
ULONG LastSector, Remainder, SectorsPerCylinder;
ULONG StartingCylinder, EndingCylinder;
ULONG StartingTrack, EndingTrack;
ULONG StartingSector, EndingSector;
PAGED_CODE();
/* Calculate the number of sectors for each cylinder */
SectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
/* Calculate the first sector, and the sector count */
FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount;
/* Now calculate the last sector */
LastSector = FirstSector.LowPart + SectorCount.LowPart - 1;
/* Calculate the first and last cylinders */
StartingCylinder = FirstSector.LowPart / SectorsPerCylinder;
EndingCylinder = LastSector / SectorsPerCylinder;
/* Set the default number of cylinders */
if (!ConventionalCylinders) ConventionalCylinders = 1024;
/* Normalize the values */
if (StartingCylinder >= ConventionalCylinders)
{
/* Set the maximum to 1023 */
StartingCylinder = ConventionalCylinders - 1;
}
if (EndingCylinder >= ConventionalCylinders)
{
/* Set the maximum to 1023 */
EndingCylinder = ConventionalCylinders - 1;
}
/* Calculate the starting head and sector that still remain */
Remainder = FirstSector.LowPart % SectorsPerCylinder;
StartingTrack = Remainder / SectorsPerTrack;
StartingSector = Remainder % SectorsPerTrack;
/* Calculate the ending head and sector that still remain */
Remainder = LastSector % SectorsPerCylinder;
EndingTrack = Remainder / SectorsPerTrack;
EndingSector = Remainder % SectorsPerTrack;
/* Set cylinder data for the MSB */
PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder;
PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder;
/* Set the track data */
PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack;
PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack;
/* Update cylinder data for the LSB */
StartingCylinder = ((StartingSector + 1) & 0x3F) |
((StartingCylinder >> 2) & 0xC0);
EndingCylinder = ((EndingSector + 1) & 0x3F) |
((EndingCylinder >> 2) & 0xC0);
/* Set the cylinder data for the LSB */
PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder;
PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder;
}
VOID
FASTCALL
xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,
IN PULONG ConventionalCylinders,
IN PLONGLONG DiskSize)
{
PDISK_GEOMETRY DiskGeometry = NULL;
PIO_STATUS_BLOCK IoStatusBlock = NULL;
PKEVENT Event = NULL;
PIRP Irp;
NTSTATUS Status;
/* Set defaults */
*ConventionalCylinders = 0;
*DiskSize = 0;
/* Allocate the structure in nonpaged pool */
DiskGeometry = ExAllocatePoolWithTag(NonPagedPool,
sizeof(DISK_GEOMETRY),
TAG_FILE_SYSTEM);
if (!DiskGeometry) goto Cleanup;
/* Allocate the status block in nonpaged pool */
IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool,
sizeof(IO_STATUS_BLOCK),
TAG_FILE_SYSTEM);
if (!IoStatusBlock) goto Cleanup;
/* Allocate the event in nonpaged pool too */
Event = ExAllocatePoolWithTag(NonPagedPool,
sizeof(KEVENT),
TAG_FILE_SYSTEM);
if (!Event) goto Cleanup;
/* Initialize the event */
KeInitializeEvent(Event, NotificationEvent, FALSE);
/* Build the IRP */
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
DeviceObject,
NULL,
0,
DiskGeometry,
sizeof(DISK_GEOMETRY),
FALSE,
Event,
IoStatusBlock);
if (!Irp) goto Cleanup;
/* Now call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for it to complete */
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock->Status;
}
/* Check driver status */
if (NT_SUCCESS(Status))
{
/* Return the cylinder count */
*ConventionalCylinders = DiskGeometry->Cylinders.LowPart;
/* Make sure it's not larger then 1024 */
if (DiskGeometry->Cylinders.LowPart >= 1024)
{
/* Otherwise, normalize the value */
*ConventionalCylinders = 1024;
}
/* Calculate the disk size */
*DiskSize = DiskGeometry->Cylinders.QuadPart *
DiskGeometry->TracksPerCylinder *
DiskGeometry->SectorsPerTrack *
DiskGeometry->BytesPerSector;
}
Cleanup:
/* Free all the pointers */
if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM);
if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM);
return;
}
VOID
FASTCALL
xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN ULONG MbrTypeIdentifier,
OUT PVOID *MbrBuffer)
{
LARGE_INTEGER Offset;
PUCHAR Buffer;
ULONG BufferSize;
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PPARTITION_DESCRIPTOR PartitionDescriptor;
NTSTATUS Status;
PIO_STACK_LOCATION IoStackLocation;
Offset.QuadPart = 0;
/* Assume failure */
*MbrBuffer = NULL;
/* Normalize the buffer size */
BufferSize = max(SectorSize, 512);
/* Allocate the buffer */
Buffer = ExAllocatePoolWithTag(NonPagedPool,
PAGE_SIZE > BufferSize ?
PAGE_SIZE : BufferSize,
TAG_FILE_SYSTEM);
if (!Buffer) return;
/* Initialize the Event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Build the IRP */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceObject,
Buffer,
BufferSize,
&Offset,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* Failed */
ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
return;
}
/* Make sure to override volume verification */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Check driver Status */
if (NT_SUCCESS(Status))
{
/* Validate the MBR Signature */
if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
{
/* Failed */
ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
return;
}
/* Get the partition entry */
PartitionDescriptor = (PPARTITION_DESCRIPTOR)
&(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
/* Make sure it's what the caller wanted */
if (PartitionDescriptor->PartitionType != MbrTypeIdentifier)
{
/* It's not, free our buffer */
ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
}
else
{
/* Check if this is a secondary entry */
if (PartitionDescriptor->PartitionType == 0x54)
{
/* Return our buffer, but at sector 63 */
*(PULONG)Buffer = 63;
*MbrBuffer = Buffer;
}
else if (PartitionDescriptor->PartitionType == 0x55)
{
/* EZ Drive, return the buffer directly */
*MbrBuffer = Buffer;
}
else
{
/* Otherwise crash on debug builds */
ASSERT(PartitionDescriptor->PartitionType == 0x55);
}
}
}
}
VOID
NTAPI
FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor,
IN ULONGLONG MaxOffset)
{
ULONG PartitionMaxOffset, PartitionLength;
PAGED_CODE();
/* Compute partition length (according to MBR entry) */
PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor);
/* In case the partition length goes beyond disk size... */
if (PartitionMaxOffset > MaxOffset)
{
/* Resize partition to its maximum real length */
PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor));
SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength);
}
}
NTSTATUS
FASTCALL
xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN BOOLEAN ReturnRecognizedPartitions,
IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
{
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PPARTITION_DESCRIPTOR PartitionDescriptor;
CCHAR Entry;
NTSTATUS Status;
PPARTITION_INFORMATION PartitionInfo;
PUCHAR Buffer = NULL;
ULONG BufferSize = 2048, InputSize;
PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;
LONG j = -1, i = -1, k;
DISK_GEOMETRY DiskGeometry;
LONGLONG EndSector, MaxSector, StartOffset;
ULONGLONG MaxOffset;
LARGE_INTEGER Offset, VolumeOffset;
BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE;
BOOLEAN IsValid, IsEmpty = TRUE;
PVOID MbrBuffer;
PIO_STACK_LOCATION IoStackLocation;
UCHAR PartitionType;
LARGE_INTEGER HiddenSectors64;
VolumeOffset.QuadPart = Offset.QuadPart = 0;
PAGED_CODE();
/* Allocate the buffer */
*PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
BufferSize,
TAG_FILE_SYSTEM);
if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;
/* Normalize the buffer size */
InputSize = max(512, SectorSize);
/* Check for EZ Drive */
HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer);
if (MbrBuffer)
{
/* EZ Drive found, bias the offset */
IsEzDrive = TRUE;
ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
Offset.QuadPart = 512;
}
/* Get drive geometry */
Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
*PartitionBuffer = NULL;
return Status;
}
/* Get the end and maximum sector */
EndSector = MaxOffset;
MaxSector = MaxOffset << 1;
DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
MaxOffset, MaxSector);
/* Allocate our buffer */
Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM);
if (!Buffer)
{
/* Fail, free the input buffer */
ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
*PartitionBuffer = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Start partition loop */
do
{
/* Assume the partition is valid */
IsValid = TRUE;
/* Initialize the event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Clear the buffer and build the IRP */
RtlZeroMemory(Buffer, InputSize);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceObject,
Buffer,
InputSize,
&Offset,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* Failed */
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Make sure to disable volume verification */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Normalize status code and check for failure */
if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;
if (!NT_SUCCESS(Status)) break;
/* If we biased for EZ-Drive, unbias now */
if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
/* Make sure this is a valid MBR */
if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
{
/* It's not, fail */
DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
"partition table %d\n", j + 1);
break;
}
/* At this point we have a valid MBR */
MbrFound = TRUE;
/* Check if we weren't given an offset */
if (!Offset.QuadPart)
{
/* Then read the signature off the disk */
(*PartitionBuffer)->Signature = ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1];
}
/* Get the partition descriptor array */
PartitionDescriptor = (PPARTITION_DESCRIPTOR)
&(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
/* Start looping partitions */
j++;
DPRINT("FSTUB: Partition Table %d:\n", j);
for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++)
{
/* Get the partition type */
PartitionType = PartitionDescriptor->PartitionType;
/* Print debug messages */
DPRINT("Partition Entry %d,%d: type %#x %s\n",
j,
Entry,
PartitionType,
(PartitionDescriptor->ActiveFlag) ? "Active" : "");
DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
GET_STARTING_SECTOR(PartitionDescriptor),
GET_PARTITION_LENGTH(PartitionDescriptor));
/* Check whether we're facing a protective MBR */
if (PartitionType == EFI_PMBR_OSTYPE_EFI)
{
/* Partition length might be bigger than disk size */
FstubFixupEfiPartition(PartitionDescriptor,
MaxOffset);
}
/* Make sure that the partition is valid, unless it's the first */
if (!(HalpIsValidPartitionEntry(PartitionDescriptor,
MaxOffset,
MaxSector)) && (j == 0))
{
/* It's invalid, so fail */
IsValid = FALSE;
break;
}
/* Check if it's a container */
if (IsContainerPartition(PartitionType))
{
/* Increase the count of containers */
if (++k != 1)
{
/* More then one table is invalid */
DPRINT1("FSTUB: Multiple container partitions found in "
"partition table %d\n - table is invalid\n",
j);
IsValid = FALSE;
break;
}
}
/* Check if the partition is supposedly empty */
if (IsEmpty)
{
/* But check if it actually has a start and/or length */
if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||
(GET_PARTITION_LENGTH(PartitionDescriptor)))
{
/* So then it's not really empty */
IsEmpty = FALSE;
}
}
/* Check if the caller wanted only recognized partitions */
if (ReturnRecognizedPartitions)
{
/* Then check if this one is unused, or a container */
if ((PartitionType == PARTITION_ENTRY_UNUSED) ||
IsContainerPartition(PartitionType))
{
/* Skip it, since the caller doesn't want it */
continue;
}
}
/* Increase the structure count and check if they can fit */
if ((sizeof(DRIVE_LAYOUT_INFORMATION) +
(++i * sizeof(PARTITION_INFORMATION))) >
BufferSize)
{
/* Allocate a new buffer that's twice as big */
DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,
BufferSize << 1,
TAG_FILE_SYSTEM);
if (!DriveLayoutInfo)
{
/* Out of memory, unto this extra structure */
--i;
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Copy the contents of the old buffer */
RtlMoveMemory(DriveLayoutInfo,
*PartitionBuffer,
BufferSize);
/* Free the old buffer and set this one as the new one */
ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
*PartitionBuffer = DriveLayoutInfo;
/* Double the size */
BufferSize <<= 1;
}
/* Now get the current structure being filled and initialize it */
PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];
PartitionInfo->PartitionType = PartitionType;
PartitionInfo->RewritePartition = FALSE;
/* Check if we're dealing with a partition that's in use */
if (PartitionType != PARTITION_ENTRY_UNUSED)
{
/* Check if it's bootable */
PartitionInfo->BootIndicator = PartitionDescriptor->
ActiveFlag & 0x80 ?
TRUE : FALSE;
/* Check if its' a container */
if (IsContainerPartition(PartitionType))
{
/* Then don't recognize it and use the volume offset */
PartitionInfo->RecognizedPartition = FALSE;
StartOffset = VolumeOffset.QuadPart;
}
else
{
/* Then recognize it and use the partition offset */
PartitionInfo->RecognizedPartition = TRUE;
StartOffset = Offset.QuadPart;
}
/* Get the starting offset */
PartitionInfo->StartingOffset.QuadPart =
StartOffset +
UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),
SectorSize);
/* Calculate the number of hidden sectors */
HiddenSectors64.QuadPart = (PartitionInfo->
StartingOffset.QuadPart -
StartOffset) /
SectorSize;
PartitionInfo->HiddenSectors = HiddenSectors64.LowPart;
/* Get the partition length */
PartitionInfo->PartitionLength.QuadPart =
UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),
SectorSize);
/* Get the partition number */
PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0;
}
else
{
/* Otherwise, clear all the relevant fields */
PartitionInfo->BootIndicator = FALSE;
PartitionInfo->RecognizedPartition = FALSE;
PartitionInfo->StartingOffset.QuadPart = 0;
PartitionInfo->PartitionLength.QuadPart = 0;
PartitionInfo->HiddenSectors = 0;
PartitionInfo->PartitionNumber = 0;
}
}
/* Finish debug log, and check for failure */
DPRINT("\n");
if (!NT_SUCCESS(Status)) break;
/* Also check if we hit an invalid entry here */
if (!IsValid)
{
/* We did, so break out of the loop minus one entry */
j--;
break;
}
/* Reset the offset */
Offset.QuadPart = 0;
/* Go back to the descriptor array and loop it */
PartitionDescriptor = (PPARTITION_DESCRIPTOR)
&(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
{
/* Check if this is a container partition, since we skipped them */
if (IsContainerPartition(PartitionDescriptor->PartitionType))
{
/* Get its offset */
Offset.QuadPart = VolumeOffset.QuadPart +
UInt32x32To64(
GET_STARTING_SECTOR(PartitionDescriptor),
SectorSize);
/* If this is a primary partition, this is the volume offset */
if (IsPrimary) VolumeOffset = Offset;
/* Also update the maximum sector */
MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);
DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector);
break;
}
}
/* Loop the next partitions, which are not primary anymore */
IsPrimary = FALSE;
} while (Offset.HighPart | Offset.LowPart);
/* Check if this is a removable device that's probably a super-floppy */
if ((DiskGeometry.MediaType == RemovableMedia) &&
(j == 0) && (MbrFound) && (IsEmpty))
{
PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;
/* Read the jump bytes to detect super-floppy */
if ((BootSectorInfo->JumpByte[0] == 0xeb) ||
(BootSectorInfo->JumpByte[0] == 0xe9))
{
/* Super floppes don't have typical MBRs, so skip them */
DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
"table - disk is a super floppy and has no valid MBR\n",
BootSectorInfo->JumpByte);
j = -1;
}
}
/* Check if we're still at partition -1 */
if (j == -1)
{
/* The likely cause is the super floppy detection above */
if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia))
{
/* Print out debugging information */
DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
"super-floppy\n",
DeviceObject);
DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x "
"bytes large\n",
EndSector, EndSector * DiskGeometry.BytesPerSector);
/* We should at least have some sectors */
if (EndSector > 0)
{
/* Get the entry we'll use */
PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
/* Fill it out with data for a super-floppy */
PartitionInfo->RewritePartition = FALSE;
PartitionInfo->RecognizedPartition = TRUE;
PartitionInfo->PartitionType = PARTITION_FAT_16;
PartitionInfo->BootIndicator = FALSE;
PartitionInfo->HiddenSectors = 0;
PartitionInfo->StartingOffset.QuadPart = 0;
PartitionInfo->PartitionLength.QuadPart = (EndSector *
DiskGeometry.
BytesPerSector);
/* FIXME: REACTOS HACK */
PartitionInfo->PartitionNumber = 0;
/* Set the signature and set the count back to 0 */
(*PartitionBuffer)->Signature = 1;
i = 0;
}
}
else
{
/* Otherwise, this isn't a super floppy, so set an invalid count */
i = -1;
}
}
/* Set the partition count */
(*PartitionBuffer)->PartitionCount = ++i;
/* If we have no count, delete the signature */
if (!i) (*PartitionBuffer)->Signature = 0;
/* Free the buffer and check for success */
if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
*PartitionBuffer = NULL;
}
/* Return status */
return Status;
}
NTSTATUS
FASTCALL
xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN ULONG PartitionNumber,
IN ULONG PartitionType)
{
PIRP Irp;
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
LARGE_INTEGER Offset, VolumeOffset;
PUCHAR Buffer = NULL;
ULONG BufferSize;
ULONG i = 0;
ULONG Entry;
PPARTITION_DESCRIPTOR PartitionDescriptor;
BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE;
PVOID MbrBuffer;
PIO_STACK_LOCATION IoStackLocation;
VolumeOffset.QuadPart = Offset.QuadPart = 0;
PAGED_CODE();
/* Normalize the buffer size */
BufferSize = max(512, SectorSize);
/* Check for EZ Drive */
HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
if (MbrBuffer)
{
/* EZ Drive found, bias the offset */
IsEzDrive = TRUE;
ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
Offset.QuadPart = 512;
}
/* Allocate our partition buffer */
Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
/* Initialize the event we'll use and loop partitions */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
do
{
/* Reset the event since we reuse it */
KeClearEvent(&Event);
/* Build the read IRP */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceObject,
Buffer,
BufferSize,
&Offset,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* Fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Make sure to disable volume verification */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Check for failure */
if (!NT_SUCCESS(Status)) break;
/* If we biased for EZ-Drive, unbias now */
if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
/* Make sure this is a valid MBR */
if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
{
/* It's not, fail */
Status = STATUS_BAD_MASTER_BOOT_RECORD;
break;
}
/* Get the partition descriptors and loop them */
PartitionDescriptor = (PPARTITION_DESCRIPTOR)
&(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
{
/* Check if it's unused or a container partition */
if ((PartitionDescriptor->PartitionType ==
PARTITION_ENTRY_UNUSED) ||
(IsContainerPartition(PartitionDescriptor->PartitionType)))
{
/* Go to the next one */
continue;
}
/* It's a valid partition, so increase the partition count */
if (++i == PartitionNumber)
{
/* We found a match, set the type */
PartitionDescriptor->PartitionType = (UCHAR)PartitionType;
/* Reset the reusable event */
KeClearEvent(&Event);
/* Build the write IRP */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
DeviceObject,
Buffer,
BufferSize,
&Offset,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* Fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Disable volume verification */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
/* We're done, break out of the loop */
break;
}
}
/* If we looped all the partitions, break out */
if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break;
/* Nothing found yet, get the partition array again */
PartitionDescriptor = (PPARTITION_DESCRIPTOR)
&(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
{
/* Check if this was a container partition (we skipped these) */
if (IsContainerPartition(PartitionDescriptor->PartitionType))
{
/* Update the partition offset */
Offset.QuadPart = VolumeOffset.QuadPart +
GET_STARTING_SECTOR(PartitionDescriptor) *
SectorSize;
/* If this was the primary partition, update the volume too */
if (IsPrimary) VolumeOffset = Offset;
break;
}
}
/* Check if we already searched all the partitions */
if (Entry > NUM_PARTITION_TABLE_ENTRIES)
{
/* Then we failed to find a good MBR */
Status = STATUS_BAD_MASTER_BOOT_RECORD;
break;
}
/* Loop the next partitions, which are not primary anymore */
IsPrimary = FALSE;
} while (i < PartitionNumber);
/* Everything done, cleanup */
if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
return Status;
}
NTSTATUS
FASTCALL
xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN ULONG SectorsPerTrack,
IN ULONG NumberOfHeads,
IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
{
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
NTSTATUS Status = STATUS_SUCCESS;
ULONG BufferSize;
PUSHORT Buffer;
PPTE Entry;
PPARTITION_TABLE PartitionTable;
LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset;
LARGE_INTEGER StartOffset, PartitionLength;
ULONG i, j;
CCHAR k;
BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr;
ULONG ConventionalCylinders;
LONGLONG DiskSize;
PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer;
PVOID MbrBuffer;
UCHAR PartitionType;
PIO_STACK_LOCATION IoStackLocation;
PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry;
PPARTITION_INFORMATION TableEntry;
ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0;
PAGED_CODE();
/* Normalize the buffer size */
BufferSize = max(512, SectorSize);
/* Get the partial drive geometry */
xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize);
/* Check for EZ Drive */
HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
if (MbrBuffer)
{
/* EZ Drive found, bias the offset */
IsEzDrive = TRUE;
ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
Offset.QuadPart = 512;
}
/* Get the number of bits to shift to multiply by the sector size */
for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break;
/* Check if there's only one partition */
if (PartitionBuffer->PartitionCount == 1)
{
/* Check if it has no starting offset or hidden sectors */
if (!(PartitionInfo->StartingOffset.QuadPart) &&
!(PartitionInfo->HiddenSectors))
{
/* Then it's a super floppy */
IsSuperFloppy = TRUE;
/* Which also means it must be non-bootable FAT-16 */
if ((PartitionInfo->PartitionNumber) ||
(PartitionInfo->PartitionType != PARTITION_FAT_16) ||
(PartitionInfo->BootIndicator))
{
/* It's not, so we fail */
return STATUS_INVALID_PARAMETER;
}
/* Check if it needs a rewrite, and disable EZ drive for sure */
if (PartitionInfo->RewritePartition) DoRewrite = TRUE;
IsEzDrive = FALSE;
}
}
/* Count the number of partition tables */
DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4;
/* Allocate our partition buffer */
Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
/* Loop the entries */
Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET];
for (i = 0; i < DiskLayout->TableCount; i++)
{
/* Set if this is the MBR partition */
IsMbr= (BOOLEAN)!i;
/* Initialize th event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Build the read IRP */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceObject,
Buffer,
BufferSize,
&Offset,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* Fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Make sure to disable volume verification */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Check for failure */
if (!NT_SUCCESS(Status)) break;
/* If we biased for EZ-Drive, unbias now */
if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
/* Check if this is a normal disk */
if (!IsSuperFloppy)
{
/* Set the boot record signature */
Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
/* By default, don't require a rewrite */
DoRewrite = FALSE;
/* Check if we don't have an offset */
if (!Offset.QuadPart)
{
/* Check if the signature doesn't match */
if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] !=
PartitionBuffer->Signature)
{
/* Then write the signature and now we need a rewrite */
((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] =
PartitionBuffer->Signature;
DoRewrite = TRUE;
}
}
/* Loop the partition table entries */
PartitionTable = &DiskLayout->PartitionTable[i];
for (j = 0; j < 4; j++)
{
/* Get the current entry and type */
TableEntry = &PartitionTable->PartitionEntry[j];
PartitionType = TableEntry->PartitionType;
/* Check if the entry needs a rewrite */
if (TableEntry->RewritePartition)
{
/* Then we need one too */
DoRewrite = TRUE;
/* Save the type and if it's a bootable partition */
Entry[j].PartitionType = TableEntry->PartitionType;
Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0;
/* Make sure it's used */
if (PartitionType != PARTITION_ENTRY_UNUSED)
{
/* Make sure it's not a container (unless primary) */
if ((IsMbr) || !(IsContainerPartition(PartitionType)))
{
/* Use the partition offset */
StartOffset.QuadPart = Offset.QuadPart;
}
else
{
/* Use the extended logical partition offset */
StartOffset.QuadPart = ExtendedOffset.QuadPart;
}
/* Set the sector offset */
SectorOffset.QuadPart = TableEntry->
StartingOffset.QuadPart -
StartOffset.QuadPart;
/* Now calculate the starting sector */
StartOffset.QuadPart = SectorOffset.QuadPart >> k;
Entry[j].StartingSector = StartOffset.LowPart;
/* As well as the length */
PartitionLength.QuadPart = TableEntry->PartitionLength.
QuadPart >> k;
Entry[j].PartitionLength = PartitionLength.LowPart;
/* Calculate the CHS values */
HalpCalculateChsValues(&TableEntry->StartingOffset,
&TableEntry->PartitionLength,
k,
SectorsPerTrack,
NumberOfHeads,
ConventionalCylinders,
(PPARTITION_DESCRIPTOR)
&Entry[j]);
}
else
{
/* Otherwise set up an empty entry */
Entry[j].StartingSector = 0;
Entry[j].PartitionLength = 0;
Entry[j].StartingTrack = 0;
Entry[j].EndingTrack = 0;
Entry[j].StartingCylinder = 0;
Entry[j].EndingCylinder = 0;
}
}
/* Check if this is a container partition */
if (IsContainerPartition(PartitionType))
{
/* Then update the offset to use */
NextOffset = TableEntry->StartingOffset;
}
}
}
/* Check if we need to write back the buffer */
if (DoRewrite)
{
/* We don't need to do this again */
DoRewrite = FALSE;
/* Initialize the event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* If we unbiased for EZ-Drive, rebias now */
if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512;
/* Build the write IRP */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
DeviceObject,
Buffer,
BufferSize,
&Offset,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* Fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Make sure to disable volume verification */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
/* Check for failure */
if (!NT_SUCCESS(Status)) break;
/* If we biased for EZ-Drive, unbias now */
if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
}
/* Update the partition offset and set the extended offset if needed */
Offset = NextOffset;
if (IsMbr) ExtendedOffset = NextOffset;
}
/* If we had a buffer, free it, then return status */
if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
return Status;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
VOID
FASTCALL
HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN ULONG MbrTypeIdentifier,
OUT PVOID *MbrBuffer)
{
HALDISPATCH->HalExamineMBR(DeviceObject,
SectorSize,
MbrTypeIdentifier,
MbrBuffer);
}
/*
* @implemented
*/
NTSTATUS
FASTCALL
IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN BOOLEAN ReturnRecognizedPartitions,
IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
{
return HALDISPATCH->HalIoReadPartitionTable(DeviceObject,
SectorSize,
ReturnRecognizedPartitions,
PartitionBuffer);
}
/*
* @implemented
*/
NTSTATUS
FASTCALL
IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN ULONG PartitionNumber,
IN ULONG PartitionType)
{
return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject,
SectorSize,
PartitionNumber,
PartitionType);
}
/*
* @implemented
*/
NTSTATUS
FASTCALL
IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
IN ULONG SectorSize,
IN ULONG SectorsPerTrack,
IN ULONG NumberOfHeads,
IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
{
return HALDISPATCH->HalIoWritePartitionTable(DeviceObject,
SectorSize,
SectorsPerTrack,
NumberOfHeads,
PartitionBuffer);
}
/*
* @implemented
*/
VOID
FASTCALL
IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PSTRING NtDeviceName,
OUT PUCHAR NtSystemPath,
OUT PSTRING NtSystemPathString)
{
HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock,
NtDeviceName,
NtSystemPath,
NtSystemPathString);
}
/* EOF */