reactos/base/setup/lib/utils/bldrsup.c
Hermès Bélusca-Maïto ea4cfcfa12
[BOOTDATA][SETUPLIB] Don't hardcode FreeLdr's UI defaults in the freeldr.ini files.
This includes:
- the default TimeText;
- the default colors.

They can however be changed by the user at one's convenience, by
explicitly specifying different values.
2022-02-21 02:54:04 +01:00

1509 lines
51 KiB
C

/*
* PROJECT: ReactOS Setup Library
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Boot Stores Management functionality, with support for
* NT 5.x family (MS Windows <= 2003, and ReactOS) bootloaders.
* 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 NTSTATUS
(*POPEN_BOOT_STORE)(
OUT PVOID* Handle,
IN HANDLE PartitionDirectoryHandle, // OPTIONAL
IN BOOT_STORE_TYPE Type,
IN BOOLEAN CreateNew);
typedef NTSTATUS
(*PCLOSE_BOOT_STORE)(
IN PVOID Handle);
typedef NTSTATUS
(*PENUM_BOOT_STORE_ENTRIES)(
IN PVOID Handle,
// IN ULONG Flags, // Determine which data to retrieve
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
IN PVOID Parameter OPTIONAL);
typedef struct _NTOS_BOOT_LOADER_FILES
{
BOOT_STORE_TYPE Type;
PCZZWSTR LoaderExecutables;
PCWSTR LoaderConfigurationFile;
POPEN_BOOT_STORE OpenBootStore;
PCLOSE_BOOT_STORE CloseBootStore;
PENUM_BOOT_STORE_ENTRIES EnumBootStoreEntries;
} NTOS_BOOT_LOADER_FILES, *PNTOS_BOOT_LOADER_FILES;
/*
* Header for particular store contexts
*/
typedef struct _BOOT_STORE_CONTEXT
{
BOOT_STORE_TYPE Type;
// PNTOS_BOOT_LOADER_FILES ??
/*
PVOID PrivateData;
*/
} BOOT_STORE_CONTEXT, *PBOOT_STORE_CONTEXT;
typedef struct _BOOT_STORE_INI_CONTEXT
{
BOOT_STORE_CONTEXT Header;
/*
* If all these members are NULL, we know that the store is freshly created
* and is cached in memory only. At file closure we will therefore need to
* create the file proper and save its contents.
*/
HANDLE FileHandle;
HANDLE SectionHandle;
// SIZE_T ViewSize;
ULONG FileSize;
PVOID ViewBase;
PINICACHE IniCache;
PINICACHESECTION OptionsIniSection;
PINICACHESECTION OsIniSection;
} BOOT_STORE_INI_CONTEXT, *PBOOT_STORE_INI_CONTEXT;
// TODO!
typedef struct _BOOT_STORE_BCDREG_CONTEXT
{
BOOT_STORE_CONTEXT Header;
ULONG PlaceHolder;
} BOOT_STORE_BCDREG_CONTEXT, *PBOOT_STORE_BCDREG_CONTEXT;
static NTSTATUS
OpenIniBootLoaderStore(
OUT PVOID* Handle,
IN HANDLE PartitionDirectoryHandle, // OPTIONAL
IN BOOT_STORE_TYPE Type,
IN BOOLEAN CreateNew);
static NTSTATUS
CloseIniBootLoaderStore(
IN PVOID Handle);
static NTSTATUS
FreeLdrEnumerateBootEntries(
IN PBOOT_STORE_INI_CONTEXT BootStore,
// IN ULONG Flags, // Determine which data to retrieve
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
IN PVOID Parameter OPTIONAL);
static NTSTATUS
NtLdrEnumerateBootEntries(
IN PBOOT_STORE_INI_CONTEXT BootStore,
// IN ULONG Flags, // Determine which data to retrieve
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
IN PVOID Parameter OPTIONAL);
// 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\0", L"freeldr.ini",
OpenIniBootLoaderStore, CloseIniBootLoaderStore, (PENUM_BOOT_STORE_ENTRIES)FreeLdrEnumerateBootEntries},
{NtLdr , L"ntldr\0" L"osloader.exe\0", L"boot.ini",
OpenIniBootLoaderStore, CloseIniBootLoaderStore, (PENUM_BOOT_STORE_ENTRIES)NtLdrEnumerateBootEntries },
// {SetupLdr, L"setupldr\0" L"setupldr.bin\0" L"setupldr.exe\0", L"txtsetup.sif", UNIMPLEMENTED, UNIMPLEMENTED, UNIMPLEMENTED}
// {BootMgr , L"bootmgr", L"BCD", UNIMPLEMENTED, UNIMPLEMENTED, UNIMPLEMENTED}
};
C_ASSERT(_countof(NtosBootLoaders) == BldrTypeMax);
/* FUNCTIONS ****************************************************************/
NTSTATUS
FindBootStore( // By handle
IN HANDLE PartitionDirectoryHandle, // OPTIONAL
IN BOOT_STORE_TYPE Type,
OUT PULONG VersionNumber OPTIONAL)
// OUT PHANDLE ConfigFileHande OPTIONAL ????
{
PCWSTR LoaderExecutable;
// UINT i;
if (Type >= BldrTypeMax)
return STATUS_INVALID_PARAMETER;
if (VersionNumber)
*VersionNumber = 0;
/* Check whether any of the loader executables exist */
LoaderExecutable = NtosBootLoaders[Type].LoaderExecutables;
while (*LoaderExecutable)
{
if (DoesFileExist(PartitionDirectoryHandle, LoaderExecutable))
{
/* A loader was found, stop there */
DPRINT("Found loader executable '%S'\n", LoaderExecutable);
break;
}
/* The loader does not exist, continue with another one */
DPRINT("Loader executable '%S' does not exist, continue with another one...\n", LoaderExecutable);
LoaderExecutable += wcslen(LoaderExecutable) + 1;
}
if (!*LoaderExecutable)
{
/* No loader was found */
DPRINT("No loader executable was found\n");
return STATUS_NOT_FOUND;
}
/* Check for loader version if needed */
if (VersionNumber)
{
*VersionNumber = 0;
// TODO: Check for BLDR version!
}
/* Check whether the loader configuration file exists */
if (!DoesFileExist(PartitionDirectoryHandle, 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\n", NtosBootLoaders[Type].LoaderConfigurationFile);
return STATUS_NOT_FOUND;
}
#if 0
/* Check whether the loader configuration file exists */
Status = OpenAndMapFile(PartitionDirectoryHandle, NtosBootLoaders[Type].LoaderConfigurationFile,
&FileHandle, &SectionHandle, &ViewBase, &FileSize, FALSE);
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\n", NtosBootLoaders[Type].LoaderConfigurationFile);
return STATUS_NOT_FOUND;
}
#endif
return STATUS_SUCCESS;
}
static VOID
CreateCommonFreeLdrSections(
IN OUT PBOOT_STORE_INI_CONTEXT BootStore)
{
PINICACHESECTION IniSection;
/*
* Cache the "FREELOADER" section for our future usage.
*/
/* Get the "FREELOADER" section */
IniSection = IniCacheGetSection(BootStore->IniCache, L"FREELOADER");
if (!IniSection)
{
/* It does not exist yet, so create it */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"FREELOADER");
if (!IniSection)
{
DPRINT1("CreateCommonFreeLdrSections: Failed to create 'FREELOADER' section!\n");
}
}
BootStore->OptionsIniSection = IniSection;
/* TimeOut */
IniCacheInsertKey(BootStore->OptionsIniSection, NULL, INSERT_LAST,
L"TimeOut", L"0");
/* Create "Display" section */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"Display");
/* TitleText */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"TitleText", L"ReactOS Boot Manager");
/* MinimalUI */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"MinimalUI", L"Yes");
/*
* Cache the "Operating Systems" section for our future usage.
*/
/* Get the "Operating Systems" section */
IniSection = IniCacheGetSection(BootStore->IniCache, L"Operating Systems");
if (!IniSection)
{
/* It does not exist yet, so create it */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"Operating Systems");
if (!IniSection)
{
DPRINT1("CreateCommonFreeLdrSections: Failed to create 'Operating Systems' section!\n");
}
}
BootStore->OsIniSection = IniSection;
}
static NTSTATUS
OpenIniBootLoaderStore(
OUT PVOID* Handle,
IN HANDLE PartitionDirectoryHandle, // OPTIONAL
IN BOOT_STORE_TYPE Type,
IN BOOLEAN CreateNew)
{
NTSTATUS Status;
PBOOT_STORE_INI_CONTEXT BootStore;
/* Create a boot store structure */
BootStore = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*BootStore));
if (!BootStore)
return STATUS_INSUFFICIENT_RESOURCES;
BootStore->Header.Type = Type;
if (CreateNew)
{
UNICODE_STRING Name;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
//
// WARNING! We "support" the INI creation *ONLY* for FreeLdr, and not for NTLDR!!
//
if (Type == NtLdr)
{
DPRINT1("OpenIniBootLoaderStore() unsupported for NTLDR!\n");
RtlFreeHeap(ProcessHeap, 0, BootStore);
return STATUS_NOT_SUPPORTED;
}
/* Initialize the INI file */
BootStore->IniCache = IniCacheCreate();
if (!BootStore->IniCache)
{
DPRINT1("IniCacheCreate() failed.\n");
RtlFreeHeap(ProcessHeap, 0, BootStore);
return STATUS_INSUFFICIENT_RESOURCES;
}
/*
* So far, we only use the INI cache. The file itself is not created
* yet, therefore FileHandle, SectionHandle, ViewBase and FileSize
* are all NULL. We will use this fact to know that the INI file was
* indeed created, and not just opened as an existing file.
*/
// BootStore->FileHandle = NULL;
BootStore->SectionHandle = NULL;
BootStore->ViewBase = NULL;
BootStore->FileSize = 0;
/*
* The INI file is fresh new, we need to create it now.
*/
RtlInitUnicodeString(&Name, NtosBootLoaders[Type].LoaderConfigurationFile);
InitializeObjectAttributes(&ObjectAttributes,
&Name,
OBJ_CASE_INSENSITIVE,
PartitionDirectoryHandle,
NULL);
Status = NtCreateFile(&BootStore->FileHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE, // Contains SYNCHRONIZE
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_SUPERSEDE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateFile() failed (Status 0x%08lx)\n", Status);
IniCacheDestroy(BootStore->IniCache);
RtlFreeHeap(ProcessHeap, 0, BootStore);
return Status;
}
/* Initialize the INI file contents */
if (Type == FreeLdr)
CreateCommonFreeLdrSections(BootStore);
}
else
{
PINICACHESECTION IniSection;
/*
* Check whether the loader configuration INI file exists,
* and open it if so.
* TODO: FIXME: What if it doesn't exist yet???
*/
Status = OpenAndMapFile(PartitionDirectoryHandle,
NtosBootLoaders[Type].LoaderConfigurationFile,
&BootStore->FileHandle,
&BootStore->SectionHandle,
&BootStore->ViewBase,
&BootStore->FileSize,
TRUE);
if (!NT_SUCCESS(Status))
{
/* The loader configuration file does not exist */
// FIXME: Consider it might be optional??
DPRINT1("Loader configuration file '%S' does not exist (Status 0x%08lx)\n",
NtosBootLoaders[Type].LoaderConfigurationFile, Status);
RtlFreeHeap(ProcessHeap, 0, BootStore);
return Status;
}
/* Open an *existing* INI configuration file */
// Status = IniCacheLoad(&BootStore->IniCache, NtosBootLoaders[Type].LoaderConfigurationFile, FALSE);
Status = IniCacheLoadFromMemory(&BootStore->IniCache,
BootStore->ViewBase,
BootStore->FileSize,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT1("IniCacheLoadFromMemory() failed (Status 0x%08lx)\n", Status);
/* Finally, unmap and close the file */
UnMapAndCloseFile(BootStore->FileHandle,
BootStore->SectionHandle,
BootStore->ViewBase);
RtlFreeHeap(ProcessHeap, 0, BootStore);
return Status;
}
if (Type == FreeLdr)
{
/*
* Cache the "FREELOADER" section for our future usage.
*/
/* Get the "FREELOADER" section */
IniSection = IniCacheGetSection(BootStore->IniCache, L"FREELOADER");
if (!IniSection)
{
/* It does not exist yet, so create it */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"FREELOADER");
if (!IniSection)
{
DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'FREELOADER' section!\n");
}
}
BootStore->OptionsIniSection = IniSection;
/*
* Cache the "Operating Systems" section for our future usage.
*/
/* Get the "Operating Systems" section */
IniSection = IniCacheGetSection(BootStore->IniCache, L"Operating Systems");
if (!IniSection)
{
/* It does not exist yet, so create it */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"Operating Systems");
if (!IniSection)
{
DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'Operating Systems' section!\n");
}
}
BootStore->OsIniSection = IniSection;
}
else
if (Type == NtLdr)
{
/*
* Cache the "boot loader" section for our future usage.
*/
/*
* HISTORICAL NOTE:
*
* While the "operating systems" section acquired its definitive
* name already when Windows NT was at its very early beta stage
* (NT 3.1 October 1991 Beta, 10-16-1991), this was not the case
* for its general settings section "boot loader".
*
* The following section names were successively introduced:
*
* - In NT 3.1 October 1991 Beta, 10-16-1991, using OS Loader V1.5,
* the section was named "multiboot".
*
* - In the next public beta version NT 3.10.340 Beta, 10-12-1992,
* using OS Loader V2.10, a new name was introduced: "flexboot".
* This is around this time that the NT OS Loader was also
* introduced as the "Windows NT FlexBoot" loader, as shown by
* the Windows NT FAQs that circulated around this time:
* http://cd.textfiles.com/cica9308/CIS_LIBS/WINNT/1/NTFAQ.TXT
* http://cd.textfiles.com/cica/cica9308/UNZIPPED/NT/NTFAQ/FTP/NEWS/NTFAQ1.TXT
* I can only hypothesize that the "FlexBoot" name was chosen
* as a marketing coup, possibly to emphasise its "flexibility"
* as a simple multiboot-aware boot manager.
*
* - A bit later, with NT 3.10.404 Beta, 3-7-1993, using an updated
* version of OS Loader V2.10, the final section name "boot loader"
* was introduced, and was kept since then.
*
* Due to the necessity to be able to boot and / or upgrade any
* Windows NT version at any time, including its NT Loader and the
* associated boot.ini file, all versions of NTLDR and the NT installer
* understand and parse these three section names, the default one
* being "boot loader", and if not present, they successively fall
* back to "flexboot" and then to "multiboot".
*/
/* Get the "boot loader" section */
IniSection = IniCacheGetSection(BootStore->IniCache, L"boot loader");
if (!IniSection)
{
/* Fall back to "flexboot" */
IniSection = IniCacheGetSection(BootStore->IniCache, L"flexboot");
if (!IniSection)
{
/* Fall back to "multiboot" */
IniSection = IniCacheGetSection(BootStore->IniCache, L"multiboot");
}
}
#if 0
if (!IniSection)
{
/* It does not exist yet, so create it */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"boot loader");
if (!IniSection)
{
DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'boot loader' section!\n");
}
}
#endif
BootStore->OptionsIniSection = IniSection;
/*
* Cache the "Operating Systems" section for our future usage.
*/
/* Get the "Operating Systems" section */
IniSection = IniCacheGetSection(BootStore->IniCache, L"operating systems");
if (!IniSection)
{
#if 0
/* It does not exist yet, so create it */
IniSection = IniCacheAppendSection(BootStore->IniCache, L"operating systems");
if (!IniSection)
{
DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'operating systems' section!\n");
}
#endif
}
BootStore->OsIniSection = IniSection;
}
}
*Handle = BootStore;
return STATUS_SUCCESS;
}
static NTSTATUS
UnprotectBootIni(
IN HANDLE FileHandle,
OUT PULONG Attributes)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION FileInfo;
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtQueryInformationFile() failed (Status 0x%08lx)\n", Status);
return Status;
}
*Attributes = FileInfo.FileAttributes;
/* Delete attributes SYSTEM, HIDDEN and READONLY */
FileInfo.FileAttributes = FileInfo.FileAttributes &
~(FILE_ATTRIBUTE_SYSTEM |
FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_READONLY);
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&FileInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(Status))
DPRINT1("NtSetInformationFile() failed (Status 0x%08lx)\n", Status);
return Status;
}
static NTSTATUS
ProtectBootIni(
IN HANDLE FileHandle,
IN ULONG Attributes)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION FileInfo;
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtQueryInformationFile() failed (Status 0x%08lx)\n", Status);
return Status;
}
FileInfo.FileAttributes = FileInfo.FileAttributes | Attributes;
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&FileInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(Status))
DPRINT1("NtSetInformationFile() failed (Status 0x%08lx)\n", Status);
return Status;
}
static NTSTATUS
CloseIniBootLoaderStore(
IN PVOID Handle)
{
NTSTATUS Status;
PBOOT_STORE_INI_CONTEXT BootStore = (PBOOT_STORE_INI_CONTEXT)Handle;
ULONG FileAttribute = 0;
// if (!BootStore)
// return STATUS_INVALID_PARAMETER;
if (BootStore->SectionHandle)
{
/*
* The INI file was already opened because it already existed,
* thus (in the case of NTLDR's boot.ini), unprotect it.
*/
if (BootStore->Header.Type == NtLdr)
{
Status = UnprotectBootIni(BootStore->FileHandle, &FileAttribute);
if (!NT_SUCCESS(Status))
{
DPRINT1("Could not unprotect BOOT.INI ! (Status 0x%08lx)\n", Status);
goto Quit;
}
}
}
IniCacheSaveByHandle(BootStore->IniCache, BootStore->FileHandle);
/* In the case of NTLDR's boot.ini, re-protect the INI file */
if (BootStore->Header.Type == NtLdr)
{
FileAttribute |= (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
Status = ProtectBootIni(BootStore->FileHandle, FileAttribute);
}
Quit:
IniCacheDestroy(BootStore->IniCache);
if (BootStore->SectionHandle)
{
/* Finally, unmap and close the file */
UnMapAndCloseFile(BootStore->FileHandle,
BootStore->SectionHandle,
BootStore->ViewBase);
}
else // if (BootStore->FileHandle)
{
/* Just close the file we have opened for creation */
NtClose(BootStore->FileHandle);
}
/* Finally, free the boot store structure */
RtlFreeHeap(ProcessHeap, 0, BootStore);
// TODO: Use a correct Status based on the return values of the previous functions...
return STATUS_SUCCESS;
}
NTSTATUS
OpenBootStoreByHandle(
OUT PVOID* Handle,
IN HANDLE PartitionDirectoryHandle, // OPTIONAL
IN BOOT_STORE_TYPE Type,
IN BOOLEAN CreateNew)
{
/*
* 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.
*/
if (Type >= BldrTypeMax || NtosBootLoaders[Type].Type >= BldrTypeMax)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[Type].Type);
return STATUS_NOT_SUPPORTED;
}
return NtosBootLoaders[Type].OpenBootStore(Handle,
PartitionDirectoryHandle,
Type,
CreateNew);
}
NTSTATUS
OpenBootStore_UStr(
OUT PVOID* Handle,
IN PUNICODE_STRING SystemPartitionPath,
IN BOOT_STORE_TYPE Type,
IN BOOLEAN CreateNew)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE PartitionDirectoryHandle;
/*
* 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.
*/
if (Type >= BldrTypeMax || NtosBootLoaders[Type].Type >= BldrTypeMax)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[Type].Type);
return STATUS_NOT_SUPPORTED;
}
/* Open SystemPartition */
InitializeObjectAttributes(&ObjectAttributes,
SystemPartitionPath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&PartitionDirectoryHandle,
FILE_LIST_DIRECTORY | FILE_ADD_FILE /* | FILE_ADD_SUBDIRECTORY | FILE_TRAVERSE*/ | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE /* | FILE_OPEN_FOR_BACKUP_INTENT */);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open SystemPartition '%wZ', Status 0x%08lx\n", SystemPartitionPath, Status);
return Status;
}
Status = OpenBootStoreByHandle(Handle, PartitionDirectoryHandle, Type, CreateNew);
/* Done! */
NtClose(PartitionDirectoryHandle);
return Status;
}
NTSTATUS
OpenBootStore(
OUT PVOID* Handle,
IN PCWSTR SystemPartition,
IN BOOT_STORE_TYPE Type,
IN BOOLEAN CreateNew)
{
UNICODE_STRING SystemPartitionPath;
RtlInitUnicodeString(&SystemPartitionPath, SystemPartition);
return OpenBootStore_UStr(Handle, &SystemPartitionPath, Type, CreateNew);
}
NTSTATUS
CloseBootStore(
IN PVOID Handle)
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
if (!BootStore)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
return STATUS_NOT_SUPPORTED;
}
return NtosBootLoaders[BootStore->Type].CloseBootStore(Handle /* BootStore */);
}
static
NTSTATUS
CreateNTOSEntry(
IN PBOOT_STORE_INI_CONTEXT BootStore,
IN ULONG_PTR BootEntryKey,
IN PBOOT_STORE_ENTRY BootEntry)
{
PINICACHESECTION IniSection;
PWCHAR Section = (PWCHAR)BootEntryKey;
/* Insert the entry into the "Operating Systems" section */
IniCacheInsertKey(BootStore->OsIniSection, NULL, INSERT_LAST,
Section, (PWSTR)BootEntry->FriendlyName);
/* Create a new section */
IniSection = IniCacheAppendSection(BootStore->IniCache, Section);
if (BootEntry->OsOptionsLength >= sizeof(NTOS_OPTIONS) &&
RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
NTOS_OPTIONS_SIGNATURE,
RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) ==
RTL_FIELD_SIZE(NTOS_OPTIONS, Signature))
{
PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
/* BootType */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"BootType", L"Windows2003");
/* SystemPath */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"SystemPath", (PWSTR)Options->OsLoadPath);
/* Options */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"Options", (PWSTR)Options->OsLoadOptions);
}
else
if (BootEntry->OsOptionsLength >= sizeof(BOOT_SECTOR_OPTIONS) &&
RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
BOOT_SECTOR_OPTIONS_SIGNATURE,
RTL_FIELD_SIZE(BOOT_SECTOR_OPTIONS, Signature)) ==
RTL_FIELD_SIZE(BOOT_SECTOR_OPTIONS, Signature))
{
PBOOT_SECTOR_OPTIONS Options = (PBOOT_SECTOR_OPTIONS)&BootEntry->OsOptions;
/* BootType */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"BootType", L"BootSector");
/* BootDrive */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"BootDrive", (PWSTR)Options->Drive);
/* BootPartition */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"BootPartition", (PWSTR)Options->Partition);
/* BootSector */
IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
L"BootSectorFile", (PWSTR)Options->BootSectorFileName);
}
else
{
// DPRINT1("Unsupported BootType %lu/'%*.s'\n",
// BootEntry->OsOptionsLength, 8, &BootEntry->OsOptions);
DPRINT1("Unsupported BootType %lu\n", BootEntry->OsOptionsLength);
}
return STATUS_SUCCESS;
}
NTSTATUS
AddBootStoreEntry(
IN PVOID Handle,
IN PBOOT_STORE_ENTRY BootEntry,
IN ULONG_PTR BootEntryKey)
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
if (!BootStore || !BootEntry)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
//
// FIXME!!
//
// if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
if (BootStore->Type == FreeLdr)
{
if (BootEntry->Version != FreeLdr)
return STATUS_INVALID_PARAMETER;
return CreateNTOSEntry((PBOOT_STORE_INI_CONTEXT)BootStore,
BootEntryKey, BootEntry);
}
else
if (BootStore->Type == NtLdr)
{
PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
PWCHAR Buffer;
ULONG BufferLength;
PCWSTR InstallName, OsOptions;
// ULONG InstallNameLength, OsOptionsLength;
BOOLEAN IsNameNotQuoted;
if (BootEntry->Version != NtLdr)
return STATUS_INVALID_PARAMETER;
if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) ||
RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
NTOS_OPTIONS_SIGNATURE,
RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) !=
RTL_FIELD_SIZE(NTOS_OPTIONS, Signature))
{
// DPRINT1("Unsupported BootType '%S'\n", BootEntry->Version);
DPRINT1("Unsupported BootType %lu\n", BootEntry->OsOptionsLength);
return STATUS_SUCCESS; // STATUS_NOT_SUPPORTED;
}
InstallName = BootEntry->FriendlyName;
OsOptions = Options->OsLoadOptions;
// if (InstallNameLength == 0) InstallName = NULL;
// if (OsOptionsLength == 0) OsOptions = NULL;
IsNameNotQuoted = (InstallName[0] != L'\"' || InstallName[wcslen(InstallName)-1] != L'\"');
BufferLength = (IsNameNotQuoted ? 2 /* Quotes for FriendlyName*/ : 0) + wcslen(InstallName);
if (OsOptions)
BufferLength += 1 /* Space between FriendlyName and options */ + wcslen(OsOptions);
BufferLength++; /* NULL-termination */
Buffer = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, BufferLength * sizeof(WCHAR));
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
*Buffer = UNICODE_NULL;
if (IsNameNotQuoted) RtlStringCchCatW(Buffer, BufferLength, L"\"");
RtlStringCchCatW(Buffer, BufferLength, InstallName);
if (IsNameNotQuoted) RtlStringCchCatW(Buffer, BufferLength, L"\"");
if (OsOptions)
{
RtlStringCchCatW(Buffer, BufferLength, L" ");
RtlStringCchCatW(Buffer, BufferLength, OsOptions);
}
/* Insert the entry into the "Operating Systems" section */
IniCacheInsertKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OsIniSection, NULL, INSERT_LAST,
(PWSTR)Options->OsLoadPath, Buffer);
RtlFreeHeap(ProcessHeap, 0, Buffer);
return STATUS_SUCCESS;
}
else
{
DPRINT1("Loader type %d is currently unsupported!\n", BootStore->Type);
return STATUS_NOT_SUPPORTED;
}
}
NTSTATUS
DeleteBootStoreEntry(
IN PVOID Handle,
IN ULONG_PTR BootEntryKey)
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
if (!BootStore)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
//
// FIXME!!
//
// if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
if (BootStore->Type != FreeLdr)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
return STATUS_NOT_SUPPORTED;
}
// FIXME! This function needs my INI library rewrite to be implemented!!
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ModifyBootStoreEntry(
IN PVOID Handle,
IN PBOOT_STORE_ENTRY BootEntry)
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
if (!BootStore || !BootEntry)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
//
// FIXME!!
//
// if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
if (BootStore->Type != FreeLdr)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
return STATUS_NOT_SUPPORTED;
}
// FIXME! This function needs my INI library rewrite to operate properly!!
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
QueryBootStoreEntry(
IN PVOID Handle,
IN ULONG_PTR BootEntryKey,
OUT PBOOT_STORE_ENTRY BootEntry) // Technically this should be PBOOT_STORE_ENTRY*
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
if (!BootStore)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
//
// FIXME!!
//
// if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
if (BootStore->Type != FreeLdr)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
return STATUS_NOT_SUPPORTED;
}
// FIXME! This function needs my INI library rewrite to be implemented!!
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
QueryBootStoreOptions(
IN PVOID Handle,
IN OUT PBOOT_STORE_OPTIONS BootOptions
/* , IN PULONG BootOptionsLength */ )
{
NTSTATUS Status = STATUS_SUCCESS;
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
PWCHAR TimeoutStr;
if (!BootStore || !BootOptions)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
//
// FIXME!!
//
// if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
if (BootStore->Type != FreeLdr && BootStore->Type != NtLdr)
{
DPRINT1("Loader type %d is currently unsupported!\n", BootStore->Type);
return STATUS_NOT_SUPPORTED;
}
if (BootStore->Type == FreeLdr)
{
BootOptions->Version = FreeLdr;
Status = IniCacheGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
L"DefaultOS", (PWCHAR*)&BootOptions->CurrentBootEntryKey);
if (!NT_SUCCESS(Status))
BootOptions->CurrentBootEntryKey = 0;
Status = IniCacheGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
L"TimeOut", &TimeoutStr);
if (NT_SUCCESS(Status) && TimeoutStr)
BootOptions->Timeout = _wtoi(TimeoutStr);
else
BootOptions->Timeout = 0;
}
else if (BootStore->Type == NtLdr)
{
BootOptions->Version = NtLdr;
Status = IniCacheGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
L"default", (PWCHAR*)&BootOptions->CurrentBootEntryKey);
if (!NT_SUCCESS(Status))
BootOptions->CurrentBootEntryKey = 0;
Status = IniCacheGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
L"timeout", &TimeoutStr);
if (NT_SUCCESS(Status) && TimeoutStr)
BootOptions->Timeout = _wtoi(TimeoutStr);
else
BootOptions->Timeout = 0;
}
return STATUS_SUCCESS; // FIXME: use Status; instead?
}
NTSTATUS
SetBootStoreOptions(
IN PVOID Handle,
IN PBOOT_STORE_OPTIONS BootOptions,
IN ULONG FieldsToChange)
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
WCHAR TimeoutStr[15];
if (!BootStore || !BootOptions)
return STATUS_INVALID_PARAMETER;
/*
* 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.
*/
//
// FIXME!!
//
// if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
if (BootStore->Type != FreeLdr)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
return STATUS_NOT_SUPPORTED;
}
if (BootOptions->Version != FreeLdr)
return STATUS_INVALID_PARAMETER;
//
// TODO: Depending on the flags set in 'FieldsToChange',
// change either one or both these bootloader options.
//
IniCacheInsertKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
NULL, INSERT_LAST,
L"DefaultOS", (PWCHAR)BootOptions->CurrentBootEntryKey);
RtlStringCchPrintfW(TimeoutStr, ARRAYSIZE(TimeoutStr), L"%d", BootOptions->Timeout);
IniCacheInsertKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
NULL, INSERT_FIRST, // INSERT_LAST, // FIXME!! There is a bug in the INI parser where a given key can be inserted twice in the same section...
L"TimeOut", TimeoutStr);
return STATUS_SUCCESS;
}
static NTSTATUS
FreeLdrEnumerateBootEntries(
IN PBOOT_STORE_INI_CONTEXT BootStore,
// IN ULONG Flags, // Determine which data to retrieve
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
IN PVOID Parameter OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
PINICACHEITERATOR Iterator;
PINICACHESECTION OsIniSection;
PWCHAR SectionName, KeyData;
UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) +
max(sizeof(NTOS_OPTIONS), sizeof(BOOT_SECTOR_OPTIONS))];
PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
PWCHAR Buffer;
/* Enumerate all the valid installations listed in the "Operating Systems" section */
Iterator = IniCacheFindFirstValue(BootStore->OsIniSection, &SectionName, &KeyData);
if (!Iterator) return STATUS_SUCCESS;
do
{
PWCHAR InstallName;
ULONG InstallNameLength;
/* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */
if (*KeyData == L'"')
{
/* Quoted name, copy up to the closing quote */
PWCHAR End = wcschr(KeyData + 1, L'"');
if (End)
{
/* Skip the first quote */
InstallName = KeyData + 1;
InstallNameLength = End - InstallName;
}
else // if (!End)
{
/* No corresponding closing quote, so we include the first one in the InstallName */
InstallName = KeyData;
InstallNameLength = wcslen(InstallName);
}
if (InstallNameLength == 0) InstallName = NULL;
}
else
{
/* Non-quoted name, copy everything */
InstallName = KeyData;
InstallNameLength = wcslen(InstallName);
if (InstallNameLength == 0) InstallName = NULL;
}
/* Allocate the temporary buffer */
Buffer = NULL;
if (InstallNameLength)
Buffer = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, (InstallNameLength + 1) * sizeof(WCHAR));
if (Buffer)
{
RtlCopyMemory(Buffer, InstallName, InstallNameLength * sizeof(WCHAR));
Buffer[InstallNameLength] = UNICODE_NULL;
InstallName = Buffer;
}
DPRINT("Boot entry '%S' in OS section '%S'\n", InstallName, SectionName);
BootEntry->Version = FreeLdr;
BootEntry->BootEntryKey = MAKESTRKEY(SectionName);
BootEntry->FriendlyName = InstallName;
BootEntry->BootFilePath = NULL;
BootEntry->OsOptionsLength = 0;
/* Search for an existing boot entry section */
OsIniSection = IniCacheGetSection(BootStore->IniCache, SectionName);
if (!OsIniSection)
goto DoEnum;
/* Check for supported boot type "Windows2003" */
Status = IniCacheGetKey(OsIniSection, L"BootType", &KeyData);
if (!NT_SUCCESS(Status) || (KeyData == NULL))
{
/* Certainly not a ReactOS installation */
DPRINT1("No BootType value present!\n");
goto DoEnum;
}
// TODO: What to do with "Windows" ; "WindowsNT40" ; "ReactOSSetup" ?
if ((_wcsicmp(KeyData, L"Windows2003") == 0) ||
(_wcsicmp(KeyData, L"\"Windows2003\"") == 0))
{
/* BootType is Windows2003 */
PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
DPRINT("This is a '%S' boot entry\n", KeyData);
BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
RtlCopyMemory(Options->Signature,
NTOS_OPTIONS_SIGNATURE,
RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
// BootEntry->BootFilePath = NULL;
/* Check its SystemPath */
Status = IniCacheGetKey(OsIniSection, L"SystemPath", &KeyData);
if (!NT_SUCCESS(Status))
Options->OsLoadPath = NULL;
else
Options->OsLoadPath = KeyData;
// KeyData == SystemRoot;
/* Check the optional Options */
Status = IniCacheGetKey(OsIniSection, L"Options", &KeyData);
if (!NT_SUCCESS(Status))
Options->OsLoadOptions = NULL;
else
Options->OsLoadOptions = KeyData;
}
else
if ((_wcsicmp(KeyData, L"BootSector") == 0) ||
(_wcsicmp(KeyData, L"\"BootSector\"") == 0))
{
/* BootType is BootSector */
PBOOT_SECTOR_OPTIONS Options = (PBOOT_SECTOR_OPTIONS)&BootEntry->OsOptions;
DPRINT("This is a '%S' boot entry\n", KeyData);
BootEntry->OsOptionsLength = sizeof(BOOT_SECTOR_OPTIONS);
RtlCopyMemory(Options->Signature,
BOOT_SECTOR_OPTIONS_SIGNATURE,
RTL_FIELD_SIZE(BOOT_SECTOR_OPTIONS, Signature));
// BootEntry->BootFilePath = NULL;
/* Check its BootDrive */
Status = IniCacheGetKey(OsIniSection, L"BootDrive", &KeyData);
if (!NT_SUCCESS(Status))
Options->Drive = NULL;
else
Options->Drive = KeyData;
/* Check its BootPartition */
Status = IniCacheGetKey(OsIniSection, L"BootPartition", &KeyData);
if (!NT_SUCCESS(Status))
Options->Partition = NULL;
else
Options->Partition = KeyData;
/* Check its BootSector */
Status = IniCacheGetKey(OsIniSection, L"BootSectorFile", &KeyData);
if (!NT_SUCCESS(Status))
Options->BootSectorFileName = NULL;
else
Options->BootSectorFileName = KeyData;
}
else
{
DPRINT1("Unrecognized BootType value '%S'\n", KeyData);
// goto DoEnum;
}
DoEnum:
/* Call the user enumeration routine callback */
Status = EnumBootEntriesRoutine(FreeLdr, BootEntry, Parameter);
/* Free temporary buffers */
if (Buffer)
RtlFreeHeap(ProcessHeap, 0, Buffer);
/* Stop the enumeration if needed */
if (!NT_SUCCESS(Status))
break;
}
while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
IniCacheFindClose(Iterator);
return Status;
}
static NTSTATUS
NtLdrEnumerateBootEntries(
IN PBOOT_STORE_INI_CONTEXT BootStore,
// IN ULONG Flags, // Determine which data to retrieve
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
IN PVOID Parameter OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
PINICACHEITERATOR Iterator;
PWCHAR SectionName, KeyData;
UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
PWCHAR Buffer;
ULONG BufferLength;
/* Enumerate all the valid installations */
Iterator = IniCacheFindFirstValue(BootStore->OsIniSection, &SectionName, &KeyData);
if (!Iterator) return STATUS_SUCCESS;
do
{
PWCHAR InstallName, OsOptions;
ULONG InstallNameLength, OsOptionsLength;
/* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */
if (*KeyData == L'"')
{
/* Quoted name, copy up to the closing quote */
OsOptions = wcschr(KeyData + 1, L'"');
/* Retrieve the starting point of the installation name and the OS options */
if (OsOptions)
{
/* Skip the first quote */
InstallName = KeyData + 1;
InstallNameLength = OsOptions - InstallName;
if (InstallNameLength == 0) InstallName = NULL;
/* Skip the ending quote (if found) */
++OsOptions;
/* Skip any whitespace */
while (iswspace(*OsOptions)) ++OsOptions;
/* Get its final length */
OsOptionsLength = wcslen(OsOptions);
if (OsOptionsLength == 0) OsOptions = NULL;
}
else
{
/* No corresponding closing quote, so we include the first one in the InstallName */
InstallName = KeyData;
InstallNameLength = wcslen(InstallName);
if (InstallNameLength == 0) InstallName = NULL;
/* There are no OS options */
// OsOptions = NULL;
OsOptionsLength = 0;
}
}
else
{
/* Non-quoted name, copy everything */
/* Retrieve the starting point of the installation name */
InstallName = KeyData;
InstallNameLength = wcslen(InstallName);
if (InstallNameLength == 0) InstallName = NULL;
/* There are no OS options */
OsOptions = NULL;
OsOptionsLength = 0;
}
/* Allocate the temporary buffer */
Buffer = NULL;
BufferLength = (InstallNameLength + OsOptionsLength) * sizeof(WCHAR);
if (BufferLength)
Buffer = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, BufferLength + 2*sizeof(UNICODE_NULL));
if (Buffer)
{
PWCHAR ptr;
/* Copy the installation name, and make InstallName point into the buffer */
if (InstallName && InstallNameLength)
{
ptr = Buffer;
RtlCopyMemory(ptr, InstallName, InstallNameLength * sizeof(WCHAR));
ptr[InstallNameLength] = UNICODE_NULL;
InstallName = ptr;
}
/* Copy the OS options, and make OsOptions point into the buffer */
if (OsOptions && OsOptionsLength)
{
ptr = Buffer + InstallNameLength + 1;
RtlCopyMemory(ptr, OsOptions, OsOptionsLength * sizeof(WCHAR));
ptr[OsOptionsLength] = UNICODE_NULL;
OsOptions = ptr;
}
}
DPRINT1("Boot entry '%S' in OS section (path) '%S'\n", InstallName, SectionName);
// SectionName == SystemRoot;
BootEntry->Version = NtLdr;
BootEntry->BootEntryKey = 0; // FIXME??
BootEntry->FriendlyName = InstallName;
BootEntry->BootFilePath = NULL;
BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
RtlCopyMemory(Options->Signature,
NTOS_OPTIONS_SIGNATURE,
RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
Options->OsLoadPath = SectionName;
Options->OsLoadOptions = OsOptions;
/* Call the user enumeration routine callback */
Status = EnumBootEntriesRoutine(NtLdr, BootEntry, Parameter);
/* Free temporary buffers */
if (Buffer)
RtlFreeHeap(ProcessHeap, 0, Buffer);
/* Stop the enumeration if needed */
if (!NT_SUCCESS(Status))
break;
}
while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
IniCacheFindClose(Iterator);
return Status;
}
NTSTATUS
EnumerateBootStoreEntries(
IN PVOID Handle,
// IN ULONG Flags, // Determine which data to retrieve
IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
IN PVOID Parameter OPTIONAL)
{
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
if (!BootStore)
return STATUS_INVALID_PARAMETER;
if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
{
DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
/**/return STATUS_SUCCESS;/**/
// return STATUS_INVALID_PARAMETER;
}
return NtosBootLoaders[BootStore->Type].EnumBootStoreEntries(
(PBOOT_STORE_INI_CONTEXT)BootStore, // Flags,
EnumBootEntriesRoutine, Parameter);
}
/* EOF */