windows-nt/Source/XPSP1/NT/base/subsys/sm/server/smpartit.c

642 lines
18 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#if defined(REMOTE_BOOT)
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
sminit.c
Abstract:
Session Manager Initialization
Author:
Mark Lucovsky (markl) 04-Oct-1989
Revision History:
--*/
#include "smsrvp.h"
#include <stdio.h>
#include <string.h>
#include <safeboot.h>
#include <ntdddisk.h>
VOID
SmpGetHarddiskBootPartition(
OUT PULONG DiskNumber,
OUT PULONG PartitionNumber
)
/*++
Routine Description:
This routine searches the each partition on each hard disk for
one which has the active bit set, returning the first one encountered.
Arguments:
DiskNumber - The harddisk number.
PartitionNumber - The partition number.
Return Value:
None
--*/
{
PARTITION_INFORMATION PartitionInfo;
WCHAR NameBuffer[80];
HANDLE Handle;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
*DiskNumber = 0;
while (TRUE) {
//
// First check if there is any disk there at all by opening partition 0
//
*PartitionNumber = 0;
swprintf(NameBuffer, L"\\Device\\Harddisk%d\\Partition%d", *DiskNumber, *PartitionNumber);
RtlInitUnicodeString(&UnicodeString, NameBuffer);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile( &Handle,
(ACCESS_MASK)FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
KdPrint(("SMSS: GetBootPartition: Harddisk%d\\Partition0 for read failed (Status 0x%x).\n", *DiskNumber, Status));
*PartitionNumber = 1;
*DiskNumber = 0;
return;
}
NtClose(Handle);
//
// Now, for each partition, check if it is marked 'active'
//
while (TRUE) {
*PartitionNumber = *PartitionNumber + 1;
swprintf(NameBuffer, L"\\Device\\Harddisk%d\\Partition%d", *DiskNumber, *PartitionNumber);
RtlInitUnicodeString(&UnicodeString, NameBuffer);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile( &Handle,
(ACCESS_MASK)FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
break;
}
Status = NtDeviceIoControlFile(Handle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_PARTITION_INFO,
NULL,
0,
&PartitionInfo,
sizeof(PARTITION_INFORMATION)
);
NtClose(Handle);
if (!NT_SUCCESS(Status)) {
break;
}
if (PartitionInfo.BootIndicator) {
return;
}
}
*DiskNumber = *DiskNumber + 1;
}
}
VOID
SmpPartitionDisk(
IN ULONG DiskNumber,
OUT PULONG PartitionNumber
)
/*++
Routine Description:
This routine
Arguments:
DiskNumber - The harddisk number.
PartitionNumber - The partition number.
Return Value:
None
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
PUCHAR AlignedBuffer;
ULONG Length;
PDRIVE_LAYOUT_INFORMATION DriveLayout;
PDRIVE_LAYOUT_INFORMATION OrigDriveLayout;
PPARTITION_INFORMATION Pte;
PPARTITION_INFORMATION StartPte;
ULONG LargestPart;
ULONG StartPart;
ULONG Part;
LARGE_INTEGER LargestBlock;
LARGE_INTEGER OffsetEnd;
UCHAR TmpBuffer[80];
NTSTATUS Status;
BOOLEAN MadeChanges;
BOOLEAN WasEnabled;
//
// Get the layout of the drive.
//
swprintf((PWSTR)TmpBuffer, L"\\Device\\Harddisk%d\\Partition0", DiskNumber);
RtlInitUnicodeString(&UnicodeString, (PWSTR)TmpBuffer);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile( &Handle,
(ACCESS_MASK)FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
KdPrint(("SMSS: Could not open Harddisk%d\\Partition0 for read (Status 0x%x).\n", DiskNumber, Status));
return;
}
//
// We really only need 4 partition numbers worth, but for debugging
// purposes I want to see more than just the first 4, so get the first 20.
//
Length = sizeof(DRIVE_LAYOUT_INFORMATION) + 20 * sizeof(PARTITION_INFORMATION);
DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( INIT_TAG ),
Length
);
if (DriveLayout == NULL) {
KdPrint(("SMSS: Could not allocate memory for drive layout (Status 0x%x).\n", Status));
NtClose(Handle);
return;
}
OrigDriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( INIT_TAG ),
Length
);
if (OrigDriveLayout == NULL) {
KdPrint(("SMSS: Could not allocate memory for drive layout 2 (Status 0x%x).\n", Status));
RtlFreeHeap( RtlProcessHeap(), 0, DriveLayout );
NtClose(Handle);
return;
}
Status = NtDeviceIoControlFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_DRIVE_LAYOUT,
NULL,
0,
(PUCHAR)DriveLayout,
Length
);
if (!NT_SUCCESS(Status)) {
KdPrint(("SMSS: Could not get drive layout (Status 0x%x).\n", Status));
RtlFreeHeap( RtlProcessHeap(), 0, OrigDriveLayout );
RtlFreeHeap( RtlProcessHeap(), 0, DriveLayout );
NtClose(Handle);
return;
}
memcpy(OrigDriveLayout, DriveLayout, Length);
#if DBG
KdPrint(("SMSS:Starting drive layout\n"));
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
Pte = &(DriveLayout->PartitionEntry[Part]);
KdPrint(("SMSS: Partition: %d\n", Part + 1));
KdPrint(("SMSS: Pte->PartitionType = 0x%x\n", Pte->PartitionType));
KdPrint(("SMSS: Pte->StartingOffset = 0x%x\n", Pte->StartingOffset));
KdPrint(("SMSS: Pte->PartitionLength = 0x%x\n", Pte->PartitionLength));
KdPrint(("SMSS: Pte->HiddenSectors = 0x%x\n", Pte->HiddenSectors));
KdPrint(("SMSS: Pte->PartitionNumber = 0x%x\n", Pte->PartitionNumber));
KdPrint(("SMSS: Pte->BootIndicator = 0x%x\n", Pte->BootIndicator));
KdPrint(("SMSS: Pte->RecognizedPartition = 0x%x\n\n", Pte->RecognizedPartition));
}
#endif
//
// Just ignore extended partitions
//
DriveLayout->PartitionCount = 4;
//
// Go thru the partitions, and for any recognized type, label it as unused.
//
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
Pte = &(DriveLayout->PartitionEntry[Part]);
if (!IsRecognizedPartition(Pte->PartitionType) &&
!IsContainerPartition(Pte->PartitionType)) {
continue;
}
Pte->PartitionType = PARTITION_ENTRY_UNUSED;
Pte->BootIndicator = FALSE;
}
#if DBG
KdPrint(("SMSS: Layout after clearing known partitions.\n"));
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
Pte = &(DriveLayout->PartitionEntry[Part]);
KdPrint(("SMSS: Partition: %d\n", Part + 1));
KdPrint(("SMSS: Pte->PartitionType = 0x%x\n", Pte->PartitionType));
KdPrint(("SMSS: Pte->StartingOffset = 0x%x\n", Pte->StartingOffset));
KdPrint(("SMSS: Pte->PartitionLength = 0x%x\n", Pte->PartitionLength));
KdPrint(("SMSS: Pte->HiddenSectors = 0x%x\n", Pte->HiddenSectors));
KdPrint(("SMSS: Pte->PartitionNumber = 0x%x\n", Pte->PartitionNumber));
KdPrint(("SMSS: Pte->BootIndicator = 0x%x\n", Pte->BootIndicator));
KdPrint(("SMSS: Pte->RecognizedPartition = 0x%x\n\n", Pte->RecognizedPartition));
}
#endif
//
// Merge unused partitions that are adjacent.
//
for (StartPart = 0; StartPart < DriveLayout->PartitionCount; StartPart++) {
StartPte = &(DriveLayout->PartitionEntry[StartPart]);
if ((StartPte->PartitionType != PARTITION_ENTRY_UNUSED) ||
RtlLargeIntegerEqualTo(StartPte->PartitionLength, RtlConvertUlongToLargeInteger(0))) {
continue;
}
OffsetEnd = RtlLargeIntegerAdd(StartPte->StartingOffset, StartPte->PartitionLength);
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
if (Part == StartPart) {
continue;
}
Pte = &(DriveLayout->PartitionEntry[Part]);
if (RtlLargeIntegerEqualTo(OffsetEnd, Pte->StartingOffset)) {
//
// Merge the blocks
//
StartPte->PartitionLength = RtlLargeIntegerAdd(StartPte->PartitionLength,
Pte->PartitionLength
);
OffsetEnd = RtlLargeIntegerAdd(OffsetEnd, Pte->PartitionLength);
Pte->PartitionType = PARTITION_ENTRY_UNUSED;
Pte->StartingOffset = RtlConvertUlongToLargeInteger(0);
Pte->PartitionLength = RtlConvertUlongToLargeInteger(0);
Pte->HiddenSectors = 0;
Pte->PartitionNumber = 0;
Pte->BootIndicator = FALSE;
Pte->RecognizedPartition = FALSE;
Part = (ULONG)-1; // will get ++'d to 0 at the bottom of the loop.
}
}
}
//
// Find the largest block that is unused.
//
LargestPart = 0;
LargestBlock = RtlConvertUlongToLargeInteger(0);
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
Pte = &(DriveLayout->PartitionEntry[Part]);
if ((Pte->PartitionType == PARTITION_ENTRY_UNUSED) &&
RtlLargeIntegerGreaterThan(Pte->PartitionLength, LargestBlock)) {
LargestPart = Part;
LargestBlock = Pte->PartitionLength;
}
}
#if DBG
KdPrint(("SMSS: Layout after merging largest block.\n"));
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
Pte = &(DriveLayout->PartitionEntry[Part]);
KdPrint(("SMSS: Partition: %d\n", Part + 1));
KdPrint(("SMSS: Pte->PartitionType = 0x%x\n", Pte->PartitionType));
KdPrint(("SMSS: Pte->StartingOffset = 0x%x\n", Pte->StartingOffset));
KdPrint(("SMSS: Pte->PartitionLength = 0x%x\n", Pte->PartitionLength));
KdPrint(("SMSS: Pte->HiddenSectors = 0x%x\n", Pte->HiddenSectors));
KdPrint(("SMSS: Pte->PartitionNumber = 0x%x\n", Pte->PartitionNumber));
KdPrint(("SMSS: Pte->BootIndicator = 0x%x\n", Pte->BootIndicator));
KdPrint(("SMSS: Pte->RecognizedPartition = 0x%x\n\n", Pte->RecognizedPartition));
}
#endif
//
// Set the partition type for the new partition
//
DriveLayout->PartitionEntry[LargestPart].PartitionType = PARTITION_IFS;
DriveLayout->PartitionEntry[LargestPart].BootIndicator = TRUE;
#if DBG
KdPrint(("SMSS: Final Layout\n"));
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
Pte = &(DriveLayout->PartitionEntry[Part]);
KdPrint(("SMSS: Partition: %d\n", Part + 1));
KdPrint(("SMSS: Pte->PartitionType = 0x%x\n", Pte->PartitionType));
KdPrint(("SMSS: Pte->StartingOffset = 0x%x\n", Pte->StartingOffset));
KdPrint(("SMSS: Pte->PartitionLength = 0x%x\n", Pte->PartitionLength));
KdPrint(("SMSS: Pte->HiddenSectors = 0x%x\n", Pte->HiddenSectors));
KdPrint(("SMSS: Pte->PartitionNumber = 0x%x\n", Pte->PartitionNumber));
KdPrint(("SMSS: Pte->BootIndicator = 0x%x\n", Pte->BootIndicator));
KdPrint(("SMSS: Pte->RecognizedPartition = 0x%x\n\n", Pte->RecognizedPartition));
}
#endif
MadeChanges = FALSE;
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
if (memcmp(&(DriveLayout->PartitionEntry[Part]),
&(OrigDriveLayout->PartitionEntry[Part]),
sizeof(PARTITION_INFORMATION))) {
MadeChanges = TRUE;
break;
}
}
if (MadeChanges) {
KdPrint(("SMSS: Repartitioning disk.\n"));
//
// Mark partitions for rewrite.
//
for (Part = 0; Part < DriveLayout->PartitionCount; Part++) {
DriveLayout->PartitionEntry[Part].RewritePartition = TRUE;
}
//
// Submit IOCTL to set new partition information
//
Status = NtDeviceIoControlFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_SET_DRIVE_LAYOUT,
DriveLayout,
Length,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
RtlFreeHeap( RtlProcessHeap(), 0, OrigDriveLayout );
RtlFreeHeap( RtlProcessHeap(), 0, DriveLayout );
NtClose(Handle);
KdPrint(("SMSS: Could not set drive layout (Status 0x%x).\n", Status));
return;
}
}
*PartitionNumber = DriveLayout->PartitionEntry[LargestPart].PartitionNumber;
RtlFreeHeap( RtlProcessHeap(), 0, OrigDriveLayout );
RtlFreeHeap( RtlProcessHeap(), 0, DriveLayout );
NtClose(Handle);
return;
}
VOID
SmpFindCSCPartition(
IN ULONG DiskNumber,
OUT PULONG PartitionNumber
)
/*++
Routine Description:
This routine searches the each partition on each hard disk for
one which has the CSC directory.
Arguments:
DiskNumber - The harddisk number.
PartitionNumber - The partition number. Will be 0 if no CSC directory is found on the disk.
Return Value:
None
--*/
{
WCHAR NameBuffer[80];
HANDLE Handle;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
ULONG Part;
Part = 0;
*PartitionNumber = 0;
while (TRUE) {
Part++;
//
// First see if the partition exists by opening it.
//
swprintf(NameBuffer,
L"\\Device\\Harddisk%d\\Partition%d",
DiskNumber,
Part
);
RtlInitUnicodeString(&UnicodeString, NameBuffer);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateFile( &Handle,
(ACCESS_MASK)FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
return;
}
NtClose(Handle);
wcscat(NameBuffer, REMOTE_BOOT_IMIRROR_PATH_W REMOTE_BOOT_CSC_SUBDIR_W);
RtlInitUnicodeString(&UnicodeString, NameBuffer);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(&Handle,
FILE_READ_DATA | SYNCHRONIZE,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ,
FILE_DIRECTORY_FILE
);
if (NT_SUCCESS(Status)) {
NtClose(Handle);
*PartitionNumber = Part;
return;
}
}
}
#endif // defined(REMOTE_BOOT)