You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
641 lines
19 KiB
641 lines
19 KiB
#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)
|