mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
[SETUPLIB] Add a new module "bldrsup.c" (WIP) where I place all the NT boot loaders (i.e. ntldr, freeldr, and possibly bootmgr in the future) management functions.
So far we only have: - a function FindNTOSBootLoader() that detects the existence of a given boot loader; - a function EnumerateNTOSBootEntries() (and corresponding helpers) that enumerate the different boot entries in the configuration file(s) for a given boot loader, and for each entry, calls a user-provided callback. Only supported at the moment: ntldr and freeldr. Doing that allows me to simplify large portions of the NT-OS detection code so that it becomes more bootloader-agnostic, and this will help me for simplifying some parts of usetup/bootsup.c too, later... svn path=/branches/setup_improvements/; revision=74661
This commit is contained in:
parent
b53b7b11e3
commit
6681fb8af5
4 changed files with 566 additions and 389 deletions
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
list(APPEND SOURCE
|
list(APPEND SOURCE
|
||||||
arcname.c
|
arcname.c
|
||||||
|
bldrsup.c
|
||||||
filesup.c
|
filesup.c
|
||||||
fsutil.c
|
fsutil.c
|
||||||
genlist.c
|
genlist.c
|
||||||
|
|
352
base/setup/lib/bldrsup.c
Normal file
352
base/setup/lib/bldrsup.c
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Setup Library
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: NT 5.x family (MS Windows <= 2003, and ReactOS)
|
||||||
|
* boot loaders management.
|
||||||
|
* COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: Add support for NT 6.x family! (detection + BCD manipulation).
|
||||||
|
|
||||||
|
/* INCLUDES *****************************************************************/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
#include "bldrsup.h"
|
||||||
|
#include "filesup.h"
|
||||||
|
#include "inicache.h"
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* GLOBALS ******************************************************************/
|
||||||
|
|
||||||
|
typedef struct _NTOS_BOOT_LOADER_FILES
|
||||||
|
{
|
||||||
|
NTOS_BOOT_LOADER_TYPE Type;
|
||||||
|
PCWSTR LoaderExecutable;
|
||||||
|
PCWSTR LoaderConfigurationFile;
|
||||||
|
// EnumerateInstallations;
|
||||||
|
} NTOS_BOOT_LOADER_FILES, *PNTOS_BOOT_LOADER_FILES;
|
||||||
|
|
||||||
|
// Question 1: What if config file is optional?
|
||||||
|
// Question 2: What if many config files are possible?
|
||||||
|
NTOS_BOOT_LOADER_FILES NtosBootLoaders[] =
|
||||||
|
{
|
||||||
|
{FreeLdr, L"freeldr.sys", L"freeldr.ini"},
|
||||||
|
{NtLdr , L"ntldr" , L"boot.ini"}, // FIXME: What about osloader.exe, etc...?
|
||||||
|
// {NtLdr , L"setupldr" , L"txtsetup.sif"}, // FIXME
|
||||||
|
// {BootMgr, L"bootmgr" , L"BCD"}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* FUNCTIONS ****************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// We need, for each type of bootloader (FreeLdr, NtLdr, Bootmgr):
|
||||||
|
// 1. A function that detects its presence and its version;
|
||||||
|
// 2. A function that opens/closes its corresponding configuration file;
|
||||||
|
// 3. A function that adds a new boot entry. Note that for the first two BLDRs
|
||||||
|
// this is a .INI file, while in the latter case this is a registry hive...
|
||||||
|
//
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FindNTOSBootLoader( // By handle
|
||||||
|
IN HANDLE PartitionHandle, // OPTIONAL
|
||||||
|
IN NTOS_BOOT_LOADER_TYPE Type,
|
||||||
|
OUT PULONG Version OPTIONAL)
|
||||||
|
// OUT PHANDLE ConfigFileHande OPTIONAL ????
|
||||||
|
{
|
||||||
|
// UINT i;
|
||||||
|
|
||||||
|
if (Type >= BldrTypeMax)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
// FIXME: Unused for now, but should be used later!!
|
||||||
|
*Version = 0;
|
||||||
|
// TODO: Check for BLDR version ONLY if Version != NULL
|
||||||
|
|
||||||
|
/* Check whether the loader executable exists */
|
||||||
|
if (!DoesFileExist(PartitionHandle, NtosBootLoaders[Type].LoaderExecutable))
|
||||||
|
{
|
||||||
|
/* The loader does not exist, continue with another one */
|
||||||
|
// DPRINT1("Loader executable '%S' does not exist, continue with another one...\n", NtosBootLoaders[Type].LoaderExecutable);
|
||||||
|
DPRINT1("Loader executable '%S' does not exist\n", NtosBootLoaders[Type].LoaderExecutable);
|
||||||
|
return STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether the loader configuration file exists */
|
||||||
|
if (!DoesFileExist(PartitionHandle, NtosBootLoaders[Type].LoaderConfigurationFile))
|
||||||
|
{
|
||||||
|
/* The loader does not exist, continue with another one */
|
||||||
|
// FIXME: Consider it might be optional??
|
||||||
|
// DPRINT1("Loader configuration file '%S' does not exist, continue with another one...\n", NtosBootLoaders[Type].LoaderConfigurationFile);
|
||||||
|
DPRINT1("Loader configuration file '%S' does not exist\n", NtosBootLoaders[Type].LoaderConfigurationFile);
|
||||||
|
return STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Check whether the loader configuration file exists */
|
||||||
|
Status = OpenAndMapFile(PartitionHandle, NtosBootLoaders[Type].LoaderConfigurationFile,
|
||||||
|
&FileHandle, &SectionHandle, &ViewBase, &FileSize);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* The loader does not exist, continue with another one */
|
||||||
|
// FIXME: Consider it might be optional??
|
||||||
|
DPRINT1("Loader configuration file '%S' does not exist, continue with another one...\n", NtosBootLoaders[Type].LoaderConfigurationFile);
|
||||||
|
return STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
FreeLdrEnumerateBootEntries(
|
||||||
|
IN PCHAR FileBuffer,
|
||||||
|
IN ULONG FileLength,
|
||||||
|
// IN ULONG Flags, // Determine which data to retrieve
|
||||||
|
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
|
||||||
|
IN PVOID Parameter OPTIONAL)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PINICACHE IniCache;
|
||||||
|
PINICACHEITERATOR Iterator;
|
||||||
|
PINICACHESECTION IniSection, OsIniSection;
|
||||||
|
PWCHAR SectionName, KeyData;
|
||||||
|
/**/NTOS_BOOT_ENTRY xxBootEntry;/**/
|
||||||
|
PNTOS_BOOT_ENTRY BootEntry = &xxBootEntry;
|
||||||
|
UNICODE_STRING InstallName;
|
||||||
|
|
||||||
|
/* Open an *existing* FreeLdr.ini configuration file */
|
||||||
|
Status = IniCacheLoadFromMemory(&IniCache, FileBuffer, FileLength, FALSE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
/* Get the "Operating Systems" section */
|
||||||
|
IniSection = IniCacheGetSection(IniCache, L"Operating Systems");
|
||||||
|
if (IniSection == NULL)
|
||||||
|
{
|
||||||
|
IniCacheDestroy(IniCache);
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enumerate all the valid installations */
|
||||||
|
Iterator = IniCacheFindFirstValue(IniSection, &SectionName, &KeyData);
|
||||||
|
if (!Iterator) goto Quit;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// FIXME: Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni).
|
||||||
|
if (KeyData[0] == L'"')
|
||||||
|
{
|
||||||
|
/* Quoted name, copy up to the closing quote */
|
||||||
|
PWCHAR Begin = &KeyData[1];
|
||||||
|
PWCHAR End = wcschr(Begin, L'"');
|
||||||
|
if (!End)
|
||||||
|
End = Begin + wcslen(Begin);
|
||||||
|
RtlInitEmptyUnicodeString(&InstallName, Begin, (ULONG_PTR)End - (ULONG_PTR)Begin);
|
||||||
|
InstallName.Length = InstallName.MaximumLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Non-quoted name, copy everything */
|
||||||
|
RtlInitUnicodeString(&InstallName, KeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("Boot entry '%wZ' in OS section '%S'\n", &InstallName, SectionName);
|
||||||
|
|
||||||
|
/* Search for an existing ReactOS entry */
|
||||||
|
OsIniSection = IniCacheGetSection(IniCache, SectionName);
|
||||||
|
if (!OsIniSection)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check for supported boot type "Windows2003" */
|
||||||
|
Status = IniCacheGetKey(OsIniSection, L"BootType", &KeyData);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
// TODO: What to do with "Windows" ; "WindowsNT40" ; "ReactOSSetup" ?
|
||||||
|
if ((KeyData == NULL) ||
|
||||||
|
( (_wcsicmp(KeyData, L"Windows2003") != 0) &&
|
||||||
|
(_wcsicmp(KeyData, L"\"Windows2003\"") != 0) ))
|
||||||
|
{
|
||||||
|
/* This is not a ReactOS entry */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Certainly not a ReactOS installation */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BootType is Windows2003. Now check its SystemPath. */
|
||||||
|
Status = IniCacheGetKey(OsIniSection, L"SystemPath", &KeyData);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1(" A Win2k3 install '%wZ' without an ARC path?!\n", &InstallName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1(" Found a candidate Win2k3 install '%wZ' with ARC path '%S'\n", &InstallName, KeyData);
|
||||||
|
// KeyData == SystemRoot;
|
||||||
|
|
||||||
|
BootEntry->FriendlyName = &InstallName;
|
||||||
|
BootEntry->OsLoadPath = KeyData;
|
||||||
|
/* Unused stuff (for now...) */
|
||||||
|
BootEntry->BootFilePath = NULL;
|
||||||
|
BootEntry->OsOptions = NULL;
|
||||||
|
BootEntry->OsLoadOptions = NULL;
|
||||||
|
|
||||||
|
Status = EnumBootEntriesRoutine(FreeLdr, BootEntry, Parameter);
|
||||||
|
// TODO: Stop enumeration if !NT_SUCCESS(Status);
|
||||||
|
}
|
||||||
|
while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
|
||||||
|
|
||||||
|
IniCacheFindClose(Iterator);
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
IniCacheDestroy(IniCache);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
NtLdrEnumerateBootEntries(
|
||||||
|
IN PCHAR FileBuffer,
|
||||||
|
IN ULONG FileLength,
|
||||||
|
// IN ULONG Flags, // Determine which data to retrieve
|
||||||
|
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
|
||||||
|
IN PVOID Parameter OPTIONAL)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PINICACHE IniCache;
|
||||||
|
PINICACHEITERATOR Iterator;
|
||||||
|
PINICACHESECTION IniSection;
|
||||||
|
PWCHAR SectionName, KeyData;
|
||||||
|
/**/NTOS_BOOT_ENTRY xxBootEntry;/**/
|
||||||
|
PNTOS_BOOT_ENTRY BootEntry = &xxBootEntry;
|
||||||
|
UNICODE_STRING InstallName;
|
||||||
|
|
||||||
|
/* Open an *existing* boot.ini configuration file */
|
||||||
|
Status = IniCacheLoadFromMemory(&IniCache, FileBuffer, FileLength, FALSE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
/* Get the "Operating Systems" section */
|
||||||
|
IniSection = IniCacheGetSection(IniCache, L"operating systems");
|
||||||
|
if (IniSection == NULL)
|
||||||
|
{
|
||||||
|
IniCacheDestroy(IniCache);
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enumerate all the valid installations */
|
||||||
|
Iterator = IniCacheFindFirstValue(IniSection, &SectionName, &KeyData);
|
||||||
|
if (!Iterator) goto Quit;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// FIXME: Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni).
|
||||||
|
if (KeyData[0] == L'"')
|
||||||
|
{
|
||||||
|
/* Quoted name, copy up to the closing quote */
|
||||||
|
PWCHAR Begin = &KeyData[1];
|
||||||
|
PWCHAR End = wcschr(Begin, L'"');
|
||||||
|
if (!End)
|
||||||
|
End = Begin + wcslen(Begin);
|
||||||
|
RtlInitEmptyUnicodeString(&InstallName, Begin, (ULONG_PTR)End - (ULONG_PTR)Begin);
|
||||||
|
InstallName.Length = InstallName.MaximumLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Non-quoted name, copy everything */
|
||||||
|
RtlInitUnicodeString(&InstallName, KeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("Boot entry '%wZ' in OS section '%S'\n", &InstallName, SectionName);
|
||||||
|
|
||||||
|
DPRINT1(" Found a Win2k3 install '%wZ' with ARC path '%S'\n", &InstallName, SectionName);
|
||||||
|
// SectionName == SystemRoot;
|
||||||
|
|
||||||
|
BootEntry->FriendlyName = &InstallName;
|
||||||
|
BootEntry->OsLoadPath = SectionName;
|
||||||
|
/* Unused stuff (for now...) */
|
||||||
|
BootEntry->BootFilePath = NULL;
|
||||||
|
BootEntry->OsOptions = NULL;
|
||||||
|
BootEntry->OsLoadOptions = NULL;
|
||||||
|
|
||||||
|
Status = EnumBootEntriesRoutine(NtLdr, BootEntry, Parameter);
|
||||||
|
// TODO: Stop enumeration if !NT_SUCCESS(Status);
|
||||||
|
}
|
||||||
|
while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
|
||||||
|
|
||||||
|
IniCacheFindClose(Iterator);
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
IniCacheDestroy(IniCache);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function may be viewed as being similar to ntos:NtEnumerateBootEntries().
|
||||||
|
NTSTATUS
|
||||||
|
EnumerateNTOSBootEntries(
|
||||||
|
IN HANDLE PartitionHandle, // OPTIONAL
|
||||||
|
IN NTOS_BOOT_LOADER_TYPE Type,
|
||||||
|
// IN ULONG Flags, // Determine which data to retrieve
|
||||||
|
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
|
||||||
|
IN PVOID Parameter OPTIONAL)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE FileHandle;
|
||||||
|
HANDLE SectionHandle;
|
||||||
|
// SIZE_T ViewSize;
|
||||||
|
ULONG FileSize;
|
||||||
|
PVOID ViewBase;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: Currently we open & map the loader configuration file without
|
||||||
|
* further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
|
||||||
|
* and NTLDR's boot.ini files. But as soon as we'll implement support for
|
||||||
|
* BOOTMGR detection, the "configuration file" will be the BCD registry
|
||||||
|
* hive and then, we'll have instead to mount the hive & open it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Check whether the loader configuration file exists */
|
||||||
|
Status = OpenAndMapFile(PartitionHandle, NtosBootLoaders[Type].LoaderConfigurationFile,
|
||||||
|
&FileHandle, &SectionHandle, &ViewBase, &FileSize);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* The loader does not exist, continue with another one */
|
||||||
|
// FIXME: Consider it might be optional??
|
||||||
|
// DPRINT1("Loader configuration file '%S' does not exist, continue with another one...\n", NtosBootLoaders[Type].LoaderConfigurationFile);
|
||||||
|
DPRINT1("Loader configuration file '%S' does not exist\n", NtosBootLoaders[Type].LoaderConfigurationFile);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The loader configuration file exists, interpret it to find valid installations */
|
||||||
|
switch (NtosBootLoaders[Type].Type)
|
||||||
|
{
|
||||||
|
case FreeLdr:
|
||||||
|
Status = FreeLdrEnumerateBootEntries(ViewBase, FileSize, /* Flags, */
|
||||||
|
EnumBootEntriesRoutine, Parameter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NtLdr:
|
||||||
|
Status = NtLdrEnumerateBootEntries(ViewBase, FileSize, /* Flags, */
|
||||||
|
EnumBootEntriesRoutine, Parameter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[Type].Type);
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, unmap and close the file */
|
||||||
|
UnMapFile(SectionHandle, ViewBase);
|
||||||
|
NtClose(FileHandle);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EOF */
|
59
base/setup/lib/bldrsup.h
Normal file
59
base/setup/lib/bldrsup.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Setup Library
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: NT 5.x family (MS Windows <= 2003, and ReactOS)
|
||||||
|
* boot loaders management.
|
||||||
|
* COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: Add support for NT 6.x family! (detection + BCD manipulation).
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum _NTOS_BOOT_LOADER_TYPE
|
||||||
|
{
|
||||||
|
FreeLdr, // ReactOS' FreeLoader
|
||||||
|
NtLdr, // Windows <= 2k3 NT "FlexBoot" OS Loader NTLDR
|
||||||
|
// BootMgr, // Vista+ BCD-oriented BOOTMGR
|
||||||
|
BldrTypeMax
|
||||||
|
} NTOS_BOOT_LOADER_TYPE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This structure is inspired from the EFI boot entry structures
|
||||||
|
* BOOT_ENTRY, BOOT_OPTIONS and FILE_PATH that are defined in ndk/iotypes.h .
|
||||||
|
*/
|
||||||
|
typedef struct _NTOS_BOOT_ENTRY
|
||||||
|
{
|
||||||
|
// ULONG Version; // We might use the ntldr version here?? Or the "BootType" as in freeldr?
|
||||||
|
// ULONG Length;
|
||||||
|
// ULONG Id; // Boot entry number (position) in the list
|
||||||
|
/** PCWSTR FriendlyName; // Human-readable boot entry description **/
|
||||||
|
PUNICODE_STRING FriendlyName;
|
||||||
|
PCWSTR BootFilePath; // Path to e.g. osloader.exe, or winload.efi
|
||||||
|
PCWSTR OsLoadPath; // The OS SystemRoot path
|
||||||
|
PCWSTR OsOptions;
|
||||||
|
PCWSTR OsLoadOptions;
|
||||||
|
} NTOS_BOOT_ENTRY, *PNTOS_BOOT_ENTRY;
|
||||||
|
|
||||||
|
|
||||||
|
typedef NTSTATUS
|
||||||
|
(NTAPI *PENUM_BOOT_ENTRIES_ROUTINE)(
|
||||||
|
IN NTOS_BOOT_LOADER_TYPE Type,
|
||||||
|
IN PNTOS_BOOT_ENTRY BootEntry,
|
||||||
|
IN PVOID Parameter OPTIONAL);
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FindNTOSBootLoader( // By handle
|
||||||
|
IN HANDLE PartitionHandle, // OPTIONAL
|
||||||
|
IN NTOS_BOOT_LOADER_TYPE Type,
|
||||||
|
OUT PULONG Version);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
EnumerateNTOSBootEntries(
|
||||||
|
IN HANDLE PartitionHandle, // OPTIONAL
|
||||||
|
IN NTOS_BOOT_LOADER_TYPE Type,
|
||||||
|
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
|
||||||
|
IN PVOID Parameter OPTIONAL);
|
||||||
|
|
||||||
|
/* EOF */
|
|
@ -12,9 +12,9 @@
|
||||||
|
|
||||||
#include "ntverrsrc.h"
|
#include "ntverrsrc.h"
|
||||||
// #include "arcname.h"
|
// #include "arcname.h"
|
||||||
|
#include "bldrsup.h"
|
||||||
#include "filesup.h"
|
#include "filesup.h"
|
||||||
#include "genlist.h"
|
#include "genlist.h"
|
||||||
#include "inicache.h"
|
|
||||||
#include "partlist.h"
|
#include "partlist.h"
|
||||||
#include "arcname.h"
|
#include "arcname.h"
|
||||||
#include "osdetect.h"
|
#include "osdetect.h"
|
||||||
|
@ -78,31 +78,6 @@ BOOL IsWindowsOS(VOID)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum _NTOS_BOOT_LOADER_TYPE
|
|
||||||
{
|
|
||||||
FreeLdr, // ReactOS' FreeLDR
|
|
||||||
NtLdr, // Windows <= 2k3 NTLDR
|
|
||||||
// BootMgr, // Vista+ BCD-oriented BOOTMGR
|
|
||||||
} NTOS_BOOT_LOADER_TYPE;
|
|
||||||
|
|
||||||
typedef struct _NTOS_BOOT_LOADER_FILES
|
|
||||||
{
|
|
||||||
NTOS_BOOT_LOADER_TYPE Type;
|
|
||||||
PCWSTR LoaderExecutable;
|
|
||||||
PCWSTR LoaderConfigurationFile;
|
|
||||||
// EnumerateInstallations;
|
|
||||||
} NTOS_BOOT_LOADER_FILES, *PNTOS_BOOT_LOADER_FILES;
|
|
||||||
|
|
||||||
// Question 1: What if config file is optional?
|
|
||||||
// Question 2: What if many config files are possible?
|
|
||||||
NTOS_BOOT_LOADER_FILES NtosBootLoaders[] =
|
|
||||||
{
|
|
||||||
{FreeLdr, L"freeldr.sys", L"freeldr.ini"},
|
|
||||||
{NtLdr , L"ntldr" , L"boot.ini"},
|
|
||||||
{NtLdr , L"setupldr" , L"txtsetup.sif"},
|
|
||||||
// {BootMgr, L"bootmgr" , ???}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static BOOLEAN
|
static BOOLEAN
|
||||||
IsValidNTOSInstallation_UStr(
|
IsValidNTOSInstallation_UStr(
|
||||||
|
@ -130,96 +105,60 @@ AddNTOSInstallation(
|
||||||
IN PPARTENTRY PartEntry OPTIONAL,
|
IN PPARTENTRY PartEntry OPTIONAL,
|
||||||
IN PCWSTR InstallationName);
|
IN PCWSTR InstallationName);
|
||||||
|
|
||||||
static NTSTATUS
|
typedef struct _ENUM_INSTALLS_DATA
|
||||||
FreeLdrEnumerateInstallations(
|
|
||||||
IN OUT PGENERIC_LIST List,
|
|
||||||
IN PPARTLIST PartList,
|
|
||||||
// IN PPARTENTRY PartEntry,
|
|
||||||
IN PCHAR FileBuffer,
|
|
||||||
IN ULONG FileLength)
|
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
IN OUT PGENERIC_LIST List;
|
||||||
PINICACHE IniCache;
|
IN PPARTLIST PartList;
|
||||||
PINICACHEITERATOR Iterator;
|
// IN PPARTENTRY PartEntry;
|
||||||
PINICACHESECTION IniSection, OsIniSection;
|
} ENUM_INSTALLS_DATA, *PENUM_INSTALLS_DATA;
|
||||||
PWCHAR SectionName, KeyData;
|
|
||||||
UNICODE_STRING InstallName;
|
// PENUM_BOOT_ENTRIES_ROUTINE
|
||||||
|
static NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
EnumerateInstallations(
|
||||||
|
IN NTOS_BOOT_LOADER_TYPE Type,
|
||||||
|
IN PNTOS_BOOT_ENTRY BootEntry,
|
||||||
|
IN PVOID Parameter OPTIONAL)
|
||||||
|
{
|
||||||
|
PENUM_INSTALLS_DATA Data = (PENUM_INSTALLS_DATA)Parameter;
|
||||||
|
|
||||||
PNTOS_INSTALLATION NtOsInstall;
|
PNTOS_INSTALLATION NtOsInstall;
|
||||||
UNICODE_STRING SystemRootPath;
|
UNICODE_STRING SystemRootPath;
|
||||||
WCHAR SystemRoot[MAX_PATH];
|
WCHAR SystemRoot[MAX_PATH];
|
||||||
WCHAR InstallNameW[MAX_PATH];
|
WCHAR InstallNameW[MAX_PATH];
|
||||||
|
|
||||||
/* Open an *existing* FreeLdr.ini configuration file */
|
ULONG DiskNumber = 0, PartitionNumber = 0;
|
||||||
Status = IniCacheLoadFromMemory(&IniCache, FileBuffer, FileLength, FALSE);
|
PCWSTR PathComponent = NULL;
|
||||||
if (!NT_SUCCESS(Status))
|
PDISKENTRY DiskEntry = NULL;
|
||||||
return Status;
|
PPARTENTRY PartEntry = NULL;
|
||||||
|
|
||||||
/* Get the "Operating Systems" section */
|
/* We have a boot entry */
|
||||||
IniSection = IniCacheGetSection(IniCache, L"Operating Systems");
|
|
||||||
if (IniSection == NULL)
|
UNICODE_STRING InstallName;
|
||||||
|
// /**/RtlInitUnicodeString(&InstallName, BootEntry->FriendlyName);/**/
|
||||||
|
InstallName = *BootEntry->FriendlyName;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (Type == FreeLdr)
|
||||||
{
|
{
|
||||||
IniCacheDestroy(IniCache);
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enumerate all the valid installations */
|
|
||||||
Iterator = IniCacheFindFirstValue(IniSection, &SectionName, &KeyData);
|
|
||||||
if (!Iterator) goto Quit;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// FIXME: Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni).
|
|
||||||
if (KeyData[0] == L'"')
|
|
||||||
{
|
|
||||||
/* Quoted name, copy up to the closing quote */
|
|
||||||
PWCHAR Begin = &KeyData[1];
|
|
||||||
PWCHAR End = wcschr(Begin, L'"');
|
|
||||||
if (!End)
|
|
||||||
End = Begin + wcslen(Begin);
|
|
||||||
RtlInitEmptyUnicodeString(&InstallName, Begin, (ULONG_PTR)End - (ULONG_PTR)Begin);
|
|
||||||
InstallName.Length = InstallName.MaximumLength;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Non-quoted name, copy everything */
|
|
||||||
RtlInitUnicodeString(&InstallName, KeyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT1("Possible installation '%wZ' in OS section '%S'\n", &InstallName, SectionName);
|
|
||||||
|
|
||||||
/* Search for an existing ReactOS entry */
|
|
||||||
OsIniSection = IniCacheGetSection(IniCache, SectionName);
|
|
||||||
if (!OsIniSection)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Check for supported boot type "Windows2003" */
|
/* Check for supported boot type "Windows2003" */
|
||||||
Status = IniCacheGetKey(OsIniSection, L"BootType", &KeyData);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
// TODO: What to do with "Windows" ; "WindowsNT40" ; "ReactOSSetup" ?
|
// TODO: What to do with "Windows" ; "WindowsNT40" ; "ReactOSSetup" ?
|
||||||
if ((KeyData == NULL) ||
|
if ((BootType == NULL) ||
|
||||||
( (_wcsicmp(KeyData, L"Windows2003") != 0) &&
|
( (_wcsicmp(BootType, L"Windows2003") != 0) &&
|
||||||
(_wcsicmp(KeyData, L"\"Windows2003\"") != 0) ))
|
(_wcsicmp(BootType, L"\"Windows2003\"") != 0) ))
|
||||||
{
|
{
|
||||||
/* This is not a ReactOS entry */
|
/* This is not a ReactOS entry */
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Certainly not a ReactOS installation */
|
/* Certainly not a ReactOS installation */
|
||||||
continue;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BootType is Windows2003. Now check SystemPath. */
|
|
||||||
Status = IniCacheGetKey(OsIniSection, L"SystemPath", &KeyData);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1(" A Win2k3 install '%wZ' without an ARC path?!\n", &InstallName);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
DPRINT1(" Found a candidate Win2k3 install '%wZ' with ARC path '%S'\n", &InstallName, KeyData);
|
DPRINT1(" Found a candidate Win2k3 install '%wZ' with ARC path '%S'\n",
|
||||||
|
&InstallName, BootEntry->OsLoadPath);
|
||||||
|
// DPRINT1(" Found a Win2k3 install '%wZ' with ARC path '%S'\n",
|
||||||
|
// &InstallName, BootEntry->OsLoadPath);
|
||||||
|
|
||||||
// TODO: Normalize the ARC path.
|
// TODO: Normalize the ARC path.
|
||||||
|
|
||||||
|
@ -227,203 +166,49 @@ FreeLdrEnumerateInstallations(
|
||||||
* Check whether we already have an installation with this ARC path.
|
* Check whether we already have an installation with this ARC path.
|
||||||
* If this is the case, stop there.
|
* If this is the case, stop there.
|
||||||
*/
|
*/
|
||||||
NtOsInstall = FindExistingNTOSInstall(List, KeyData, NULL);
|
NtOsInstall = FindExistingNTOSInstall(Data->List, BootEntry->OsLoadPath, NULL);
|
||||||
if (NtOsInstall)
|
if (NtOsInstall)
|
||||||
{
|
{
|
||||||
DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
|
DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
|
||||||
NtOsInstall->InstallationName, &NtOsInstall->SystemArcPath);
|
NtOsInstall->InstallationName, &NtOsInstall->SystemArcPath);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert the ARC path into an NT path, from which we will deduce
|
|
||||||
* the real disk drive & partition on which the candidate installation
|
|
||||||
* resides, as well verifying whether it is indeed an NTOS installation.
|
|
||||||
*/
|
|
||||||
RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
|
|
||||||
if (!ArcPathToNtPath(&SystemRootPath, KeyData, PartList))
|
|
||||||
{
|
|
||||||
DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", KeyData);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT1("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n", KeyData, &SystemRootPath);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether we already have an installation with this NT path.
|
|
||||||
* If this is the case, stop there.
|
|
||||||
*/
|
|
||||||
NtOsInstall = FindExistingNTOSInstall(List, NULL /*KeyData*/, &SystemRootPath);
|
|
||||||
if (NtOsInstall)
|
|
||||||
{
|
|
||||||
DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
|
|
||||||
NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set SystemRootPath */
|
|
||||||
DPRINT1("FreeLdrEnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
|
|
||||||
|
|
||||||
if (IsValidNTOSInstallation_UStr(&SystemRootPath))
|
|
||||||
{
|
|
||||||
ULONG DiskNumber = 0, PartitionNumber = 0;
|
|
||||||
PCWSTR PathComponent = NULL;
|
|
||||||
PDISKENTRY DiskEntry = NULL;
|
|
||||||
PPARTENTRY PartEntry = NULL;
|
|
||||||
|
|
||||||
DPRINT1("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n", KeyData, &SystemRootPath);
|
|
||||||
|
|
||||||
/* From the NT path, compute the disk, partition and path components */
|
|
||||||
if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
|
|
||||||
{
|
|
||||||
DPRINT1("SystemRootPath = '%wZ' points to disk #%d, partition #%d, path '%S'\n",
|
|
||||||
&SystemRootPath, DiskNumber, PartitionNumber, PathComponent);
|
|
||||||
|
|
||||||
/* Retrieve the corresponding disk and partition */
|
|
||||||
if (!GetDiskOrPartition(PartList, DiskNumber, PartitionNumber, &DiskEntry, &PartEntry))
|
|
||||||
DPRINT1("GetDiskOrPartition(disk #%d, partition #%d) failed\n", DiskNumber, PartitionNumber);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINT1("NtPathToDiskPartComponents(%wZ) failed\n", &SystemRootPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PartEntry && PartEntry->DriveLetter)
|
|
||||||
{
|
|
||||||
/* We have retrieved a partition that is mounted */
|
|
||||||
StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%C:%s \"%wZ\"",
|
|
||||||
PartEntry->DriveLetter, PathComponent, &InstallName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* We failed somewhere, just show the NT path */
|
|
||||||
StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ \"%wZ\"",
|
|
||||||
&SystemRootPath, &InstallName);
|
|
||||||
}
|
|
||||||
AddNTOSInstallation(List, KeyData, &SystemRootPath, PathComponent,
|
|
||||||
DiskNumber, PartitionNumber, PartEntry,
|
|
||||||
InstallNameW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
|
|
||||||
|
|
||||||
IniCacheFindClose(Iterator);
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
IniCacheDestroy(IniCache);
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
|
||||||
NtLdrEnumerateInstallations(
|
|
||||||
IN OUT PGENERIC_LIST List,
|
|
||||||
IN PPARTLIST PartList,
|
|
||||||
// IN PPARTENTRY PartEntry,
|
|
||||||
IN PCHAR FileBuffer,
|
|
||||||
IN ULONG FileLength)
|
|
||||||
{
|
|
||||||
NTSTATUS Status;
|
|
||||||
PINICACHE IniCache;
|
|
||||||
PINICACHEITERATOR Iterator;
|
|
||||||
PINICACHESECTION IniSection;
|
|
||||||
PWCHAR SectionName, KeyData;
|
|
||||||
UNICODE_STRING InstallName;
|
|
||||||
|
|
||||||
PNTOS_INSTALLATION NtOsInstall;
|
|
||||||
UNICODE_STRING SystemRootPath;
|
|
||||||
WCHAR SystemRoot[MAX_PATH];
|
|
||||||
WCHAR InstallNameW[MAX_PATH];
|
|
||||||
|
|
||||||
/* Open an *existing* FreeLdr.ini configuration file */
|
|
||||||
Status = IniCacheLoadFromMemory(&IniCache, FileBuffer, FileLength, FALSE);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
return Status;
|
|
||||||
|
|
||||||
/* Get the "Operating Systems" section */
|
|
||||||
IniSection = IniCacheGetSection(IniCache, L"operating systems");
|
|
||||||
if (IniSection == NULL)
|
|
||||||
{
|
|
||||||
IniCacheDestroy(IniCache);
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enumerate all the valid installations */
|
|
||||||
Iterator = IniCacheFindFirstValue(IniSection, &SectionName, &KeyData);
|
|
||||||
if (!Iterator) goto Quit;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// FIXME: Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni).
|
|
||||||
if (KeyData[0] == L'"')
|
|
||||||
{
|
|
||||||
/* Quoted name, copy up to the closing quote */
|
|
||||||
PWCHAR Begin = &KeyData[1];
|
|
||||||
PWCHAR End = wcschr(Begin, L'"');
|
|
||||||
if (!End)
|
|
||||||
End = Begin + wcslen(Begin);
|
|
||||||
RtlInitEmptyUnicodeString(&InstallName, Begin, (ULONG_PTR)End - (ULONG_PTR)Begin);
|
|
||||||
InstallName.Length = InstallName.MaximumLength;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Non-quoted name, copy everything */
|
|
||||||
RtlInitUnicodeString(&InstallName, KeyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT1("Possible installation '%wZ' with ARC path '%S'\n", &InstallName, SectionName);
|
|
||||||
|
|
||||||
DPRINT1(" Found a Win2k3 install '%wZ' with ARC path '%S'\n", &InstallName, SectionName);
|
|
||||||
|
|
||||||
// TODO: Normalize the ARC path.
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether we already have an installation with this ARC path.
|
|
||||||
* If this is the case, stop there.
|
|
||||||
*/
|
|
||||||
NtOsInstall = FindExistingNTOSInstall(List, SectionName, NULL);
|
|
||||||
if (NtOsInstall)
|
|
||||||
{
|
|
||||||
DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
|
|
||||||
NtOsInstall->InstallationName, &NtOsInstall->SystemArcPath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert the ARC path into an NT path, from which we will deduce
|
* Convert the ARC path into an NT path, from which we will deduce
|
||||||
* the real disk drive & partition on which the candidate installation
|
* the real disk drive & partition on which the candidate installation
|
||||||
* resides, as well verifying whether it is indeed an NTOS installation.
|
* resides, as well verifying whether it is indeed an NTOS installation.
|
||||||
*/
|
*/
|
||||||
RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
|
RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
|
||||||
if (!ArcPathToNtPath(&SystemRootPath, SectionName, PartList))
|
if (!ArcPathToNtPath(&SystemRootPath, BootEntry->OsLoadPath, Data->PartList))
|
||||||
{
|
{
|
||||||
DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", SectionName);
|
DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", BootEntry->OsLoadPath);
|
||||||
continue;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT1("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n", SectionName, &SystemRootPath);
|
DPRINT1("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n",
|
||||||
|
BootEntry->OsLoadPath, &SystemRootPath);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether we already have an installation with this NT path.
|
* Check whether we already have an installation with this NT path.
|
||||||
* If this is the case, stop there.
|
* If this is the case, stop there.
|
||||||
*/
|
*/
|
||||||
NtOsInstall = FindExistingNTOSInstall(List, NULL /*SectionName*/, &SystemRootPath);
|
NtOsInstall = FindExistingNTOSInstall(Data->List, NULL /*BootEntry->OsLoadPath*/, &SystemRootPath);
|
||||||
if (NtOsInstall)
|
if (NtOsInstall)
|
||||||
{
|
{
|
||||||
DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
|
DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
|
||||||
NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
|
NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
|
||||||
continue;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set SystemRootPath */
|
DPRINT1("EnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
|
||||||
DPRINT1("NtLdrEnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
|
|
||||||
|
|
||||||
if (IsValidNTOSInstallation_UStr(&SystemRootPath))
|
/* Check if this is a valid NTOS installation; stop there if it isn't one */
|
||||||
{
|
if (!IsValidNTOSInstallation_UStr(&SystemRootPath))
|
||||||
ULONG DiskNumber = 0, PartitionNumber = 0;
|
return STATUS_SUCCESS;
|
||||||
PCWSTR PathComponent = NULL;
|
|
||||||
PDISKENTRY DiskEntry = NULL;
|
|
||||||
PPARTENTRY PartEntry = NULL;
|
|
||||||
|
|
||||||
DPRINT1("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n", SectionName, &SystemRootPath);
|
DPRINT1("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n",
|
||||||
|
BootEntry->OsLoadPath, &SystemRootPath);
|
||||||
|
|
||||||
/* From the NT path, compute the disk, partition and path components */
|
/* From the NT path, compute the disk, partition and path components */
|
||||||
if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
|
if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
|
||||||
|
@ -432,8 +217,11 @@ NtLdrEnumerateInstallations(
|
||||||
&SystemRootPath, DiskNumber, PartitionNumber, PathComponent);
|
&SystemRootPath, DiskNumber, PartitionNumber, PathComponent);
|
||||||
|
|
||||||
/* Retrieve the corresponding disk and partition */
|
/* Retrieve the corresponding disk and partition */
|
||||||
if (!GetDiskOrPartition(PartList, DiskNumber, PartitionNumber, &DiskEntry, &PartEntry))
|
if (!GetDiskOrPartition(Data->PartList, DiskNumber, PartitionNumber, &DiskEntry, &PartEntry))
|
||||||
DPRINT1("GetDiskOrPartition(disk #%d, partition #%d) failed\n", DiskNumber, PartitionNumber);
|
{
|
||||||
|
DPRINT1("GetDiskOrPartition(disk #%d, partition #%d) failed\n",
|
||||||
|
DiskNumber, PartitionNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -452,17 +240,11 @@ NtLdrEnumerateInstallations(
|
||||||
StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ \"%wZ\"",
|
StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ \"%wZ\"",
|
||||||
&SystemRootPath, &InstallName);
|
&SystemRootPath, &InstallName);
|
||||||
}
|
}
|
||||||
AddNTOSInstallation(List, SectionName, &SystemRootPath, PathComponent,
|
AddNTOSInstallation(Data->List, BootEntry->OsLoadPath,
|
||||||
|
&SystemRootPath, PathComponent,
|
||||||
DiskNumber, PartitionNumber, PartEntry,
|
DiskNumber, PartitionNumber, PartEntry,
|
||||||
InstallNameW);
|
InstallNameW);
|
||||||
}
|
|
||||||
}
|
|
||||||
while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
|
|
||||||
|
|
||||||
IniCacheFindClose(Iterator);
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
IniCacheDestroy(IniCache);
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,28 +381,32 @@ IsValidNTOSInstallationByHandle(
|
||||||
IN HANDLE SystemRootDirectory)
|
IN HANDLE SystemRootDirectory)
|
||||||
{
|
{
|
||||||
BOOLEAN Success = FALSE;
|
BOOLEAN Success = FALSE;
|
||||||
|
PCWSTR PathName;
|
||||||
USHORT i;
|
USHORT i;
|
||||||
UNICODE_STRING VendorName;
|
UNICODE_STRING VendorName;
|
||||||
WCHAR VendorNameBuffer[MAX_PATH];
|
WCHAR VendorNameBuffer[MAX_PATH];
|
||||||
|
|
||||||
/* Check for the existence of \SystemRoot\System32 */
|
/* Check for the existence of \SystemRoot\System32 */
|
||||||
if (!DoesPathExist(SystemRootDirectory, L"System32\\"))
|
PathName = L"System32\\";
|
||||||
|
if (!DoesPathExist(SystemRootDirectory, PathName))
|
||||||
{
|
{
|
||||||
// DPRINT1("Failed to open directory '%wZ', Status 0x%08lx\n", &FileName, Status);
|
// DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for the existence of \SystemRoot\System32\drivers */
|
/* Check for the existence of \SystemRoot\System32\drivers */
|
||||||
if (!DoesPathExist(SystemRootDirectory, L"System32\\drivers\\"))
|
PathName = L"System32\\drivers\\";
|
||||||
|
if (!DoesPathExist(SystemRootDirectory, PathName))
|
||||||
{
|
{
|
||||||
// DPRINT1("Failed to open directory '%wZ', Status 0x%08lx\n", &FileName, Status);
|
// DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for the existence of \SystemRoot\System32\config */
|
/* Check for the existence of \SystemRoot\System32\config */
|
||||||
if (!DoesPathExist(SystemRootDirectory, L"System32\\config\\"))
|
PathName = L"System32\\config\\";
|
||||||
|
if (!DoesPathExist(SystemRootDirectory, PathName))
|
||||||
{
|
{
|
||||||
// DPRINT1("Failed to open directory '%wZ', Status 0x%08lx\n", &FileName, Status);
|
// DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,14 +415,16 @@ IsValidNTOSInstallationByHandle(
|
||||||
* Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
|
* Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
|
||||||
* (but we don't check here whether they are actually valid).
|
* (but we don't check here whether they are actually valid).
|
||||||
*/
|
*/
|
||||||
if (!DoesFileExist(SystemRootDirectory, L"System32\\config\\SYSTEM"))
|
PathName = L"System32\\config\\SYSTEM";
|
||||||
|
if (!DoesFileExist(SystemRootDirectory, PathName))
|
||||||
{
|
{
|
||||||
// DPRINT1("Failed to open file '%wZ', Status 0x%08lx\n", &FileName, Status);
|
// DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!DoesFileExist(SystemRootDirectory, L"System32\\config\\SOFTWARE"))
|
PathName = L"System32\\config\\SOFTWARE";
|
||||||
|
if (!DoesFileExist(SystemRootDirectory, PathName))
|
||||||
{
|
{
|
||||||
// DPRINT1("Failed to open file '%wZ', Status 0x%08lx\n", &FileName, Status);
|
// DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -644,9 +432,10 @@ IsValidNTOSInstallationByHandle(
|
||||||
RtlInitEmptyUnicodeString(&VendorName, VendorNameBuffer, sizeof(VendorNameBuffer));
|
RtlInitEmptyUnicodeString(&VendorName, VendorNameBuffer, sizeof(VendorNameBuffer));
|
||||||
|
|
||||||
/* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and retrieves its vendor name */
|
/* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and retrieves its vendor name */
|
||||||
Success = CheckForValidPEAndVendor(SystemRootDirectory, L"System32\\ntoskrnl.exe", &VendorName);
|
PathName = L"System32\\ntoskrnl.exe";
|
||||||
|
Success = CheckForValidPEAndVendor(SystemRootDirectory, PathName, &VendorName);
|
||||||
if (!Success)
|
if (!Success)
|
||||||
DPRINT1("Kernel file ntoskrnl.exe is either not a PE file, or does not have any vendor?\n");
|
DPRINT1("Kernel executable '%S' is either not a PE file, or does not have any vendor?\n", PathName);
|
||||||
|
|
||||||
/* The kernel gives the OS its flavour */
|
/* The kernel gives the OS its flavour */
|
||||||
if (Success)
|
if (Success)
|
||||||
|
@ -666,9 +455,10 @@ IsValidNTOSInstallationByHandle(
|
||||||
/* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
|
/* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
|
||||||
|
|
||||||
/* Check for the existence of \SystemRoot\System32\ntdll.dll and retrieves its vendor name */
|
/* Check for the existence of \SystemRoot\System32\ntdll.dll and retrieves its vendor name */
|
||||||
Success = CheckForValidPEAndVendor(SystemRootDirectory, L"System32\\ntdll.dll", &VendorName);
|
PathName = L"System32\\ntdll.dll";
|
||||||
|
Success = CheckForValidPEAndVendor(SystemRootDirectory, PathName, &VendorName);
|
||||||
if (!Success)
|
if (!Success)
|
||||||
DPRINT1("User-mode file ntdll.dll is either not a PE file, or does not have any vendor?\n");
|
DPRINT1("User-mode DLL '%S' is either not a PE file, or does not have any vendor?\n", PathName);
|
||||||
if (Success)
|
if (Success)
|
||||||
{
|
{
|
||||||
for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
|
for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
|
||||||
|
@ -676,7 +466,7 @@ IsValidNTOSInstallationByHandle(
|
||||||
if (!!FindSubStrI(VendorName.Buffer, KnownVendors[i]))
|
if (!!FindSubStrI(VendorName.Buffer, KnownVendors[i]))
|
||||||
{
|
{
|
||||||
/* We have found a correct vendor combination */
|
/* We have found a correct vendor combination */
|
||||||
DPRINT1("IsValidNTOSInstallation: The user-mode file ntdll.dll is from %S\n", KnownVendors[i]);
|
DPRINT1("IsValidNTOSInstallation: The user-mode DLL '%S' is from %S\n", PathName, KnownVendors[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,15 +666,13 @@ FindNTOSInstallations(
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
ULONG DiskNumber = PartEntry->DiskEntry->DiskNumber;
|
ULONG DiskNumber = PartEntry->DiskEntry->DiskNumber;
|
||||||
ULONG PartitionNumber = PartEntry->PartitionNumber;
|
ULONG PartitionNumber = PartEntry->PartitionNumber;
|
||||||
HANDLE PartitionHandle, FileHandle;
|
HANDLE PartitionHandle;
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
IO_STATUS_BLOCK IoStatusBlock;
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
UNICODE_STRING PartitionRootPath;
|
UNICODE_STRING PartitionRootPath;
|
||||||
UINT i;
|
NTOS_BOOT_LOADER_TYPE Type;
|
||||||
HANDLE SectionHandle;
|
ENUM_INSTALLS_DATA Data;
|
||||||
// SIZE_T ViewSize;
|
ULONG Version;
|
||||||
ULONG FileSize;
|
|
||||||
PVOID ViewBase;
|
|
||||||
WCHAR PathBuffer[MAX_PATH];
|
WCHAR PathBuffer[MAX_PATH];
|
||||||
|
|
||||||
/* Set PartitionRootPath */
|
/* Set PartitionRootPath */
|
||||||
|
@ -912,49 +700,26 @@ FindNTOSInstallations(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to see whether we recognize some NT boot loaders */
|
Data.List = List;
|
||||||
for (i = 0; i < ARRAYSIZE(NtosBootLoaders); ++i)
|
Data.PartList = PartList;
|
||||||
{
|
|
||||||
/* Check whether the loader executable exists */
|
|
||||||
if (!DoesFileExist(PartitionHandle, NtosBootLoaders[i].LoaderExecutable))
|
|
||||||
{
|
|
||||||
/* The loader does not exist, continue with another one */
|
|
||||||
DPRINT1("Loader executable '%S' does not exist, continue with another one...\n", NtosBootLoaders[i].LoaderExecutable);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check whether the loader configuration file exists */
|
/* Try to see whether we recognize some NT boot loaders */
|
||||||
Status = OpenAndMapFile(PartitionHandle, NtosBootLoaders[i].LoaderConfigurationFile,
|
for (Type = FreeLdr; Type < BldrTypeMax; ++Type)
|
||||||
&FileHandle, &SectionHandle, &ViewBase, &FileSize);
|
{
|
||||||
|
Status = FindNTOSBootLoader(PartitionHandle, Type, &Version);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* The loader does not exist, continue with another one */
|
/* The loader does not exist, continue with another one */
|
||||||
// FIXME: Consider it might be optional??
|
DPRINT1("Loader type '%d' does not exist, or an error happened (Status 0x%08lx), continue with another one...\n",
|
||||||
DPRINT1("Loader configuration file '%S' does not exist, continue with another one...\n", NtosBootLoaders[i].LoaderConfigurationFile);
|
Type, Status);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The loader configuration file exists, interpret it to find valid installations */
|
/* The loader exists, try to enumerate its boot entries */
|
||||||
DPRINT1("Analyse the OS installations inside '%S' in disk #%d, partition #%d\n",
|
DPRINT1("Analyse the OS installations for loader type '%d' in disk #%d, partition #%d\n",
|
||||||
NtosBootLoaders[i].LoaderConfigurationFile, DiskNumber, PartitionNumber);
|
Type, DiskNumber, PartitionNumber);
|
||||||
switch (NtosBootLoaders[i].Type)
|
|
||||||
{
|
|
||||||
case FreeLdr:
|
|
||||||
Status = FreeLdrEnumerateInstallations(List, PartList, ViewBase, FileSize);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NtLdr:
|
EnumerateNTOSBootEntries(PartitionHandle, Type, EnumerateInstallations, &Data);
|
||||||
Status = NtLdrEnumerateInstallations(List, PartList, ViewBase, FileSize);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[i].Type);
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally, unmap and close the file */
|
|
||||||
UnMapFile(SectionHandle, ViewBase);
|
|
||||||
NtClose(FileHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close the partition */
|
/* Close the partition */
|
||||||
|
|
Loading…
Reference in a new issue