windows-nt/Source/XPSP1/NT/base/ntsetup/bootent/bootini/bootient.c

1204 lines
35 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995-2001 Microsoft Corporation
Module Name:
bootient.c
Abstract:
Contains the Boot.ini OS boot entry and boot options
abstraction implementation.
Author:
Revision History:
None.
--*/
#include <bootient.h>
//
// defines
//
#define BOIOS_SECTION_NAME_START TEXT('[')
#define BOIOS_SECTION_NAME_END TEXT(']')
#define BOIOS_SECTION_NAME_START_STR TEXT("[")
#define BOIOS_SECTION_NAME_END_STR TEXT("]")
#define BOIOS_BOOTLOADER_SECTION TEXT("boot loader")
#define BOIOS_OS_SECTION TEXT("operating systems")
#define BOIOS_TIMEOUT_KEY TEXT("timeout=")
#define BOIOS_DEFAULT_KEY TEXT("default=")
#define MAX_BOOT_INI_SIZE (4 * 1024)
static
PTSTR
BOIOSFixupString(
IN PTSTR String,
IN PTSTR SpecialChars
)
{
PTSTR ResultStr = String;
//
// Verify arguments
//
if (ResultStr && SpecialChars) {
ULONG Index;
BOOLEAN DoneWithStart = FALSE;
TCHAR Buffer[MAX_PATH * 4] = {0};
TCHAR NextIndex = 0;
//
// skip unwanted characters
//
for (Index = 0; String[Index]; Index++) {
if (!_tcschr(SpecialChars, String[Index])) {
Buffer[NextIndex++] = String[Index];
}
}
//
// Null terminate the string
//
Buffer[NextIndex] = 0;
if (!NextIndex) {
ResultStr = NULL;
} else {
//
// Copy back the new string to the
// input / output buffer
//
_tcscpy(ResultStr, Buffer);
}
}
return ResultStr;
}
//
// BOI_OS_SECTION Methods
//
PBOI_SECTION
BOISectionCreate(
IN PCTSTR SectionData
)
{
PBOI_SECTION This = NULL;
if (SectionData) {
PTSTR Buffer = (PTSTR)SBE_MALLOC((_tcslen(SectionData) + 1) * sizeof(TCHAR));
if (Buffer && _tcscpy(Buffer, SectionData)) {
PTSTR SectionNameStart = _tcschr(Buffer, BOIOS_SECTION_NAME_START);
PTSTR SectionNameEnd = _tcschr(Buffer, BOIOS_SECTION_NAME_END);
BOOLEAN Result = FALSE;
if (SectionNameStart && SectionNameEnd && (SectionNameEnd > SectionNameStart)) {
This = (PBOI_SECTION)SBE_MALLOC(sizeof(BOI_SECTION));
if (*Buffer && This) {
DWORD DataLength = (_tcslen(Buffer) + 1) * sizeof(TCHAR);
DataLength -= (((SectionNameEnd + 1) - Buffer) * sizeof(TCHAR));
//
// Init default object state
//
memset(This, 0, sizeof(BOI_SECTION));
//
// Get the name
//
_tcsncpy(This->Name, SectionNameStart + 1,
SectionNameEnd - SectionNameStart - 1);
//
// Replicate the contents and keep it
//
This->Contents = (PTSTR)SBE_MALLOC(DataLength);
if (This->Contents) {
_tcscpy(This->Contents, SectionNameEnd + 1);
Result = TRUE;
} else {
Result = FALSE;
}
}
if (!Result) {
BOISectionDelete(This);
This = NULL;
}
}
SBE_FREE(Buffer);
}
}
return This;
}
VOID
BOISectionDelete(
IN PBOI_SECTION This
)
{
if (This) {
if (This->Contents) {
SBE_FREE(This->Contents);
}
SBE_FREE(This);
}
}
static
BOOLEAN
BOISectionWrite(
IN PBOI_SECTION This,
IN OUT PTSTR Buffer
)
{
BOOLEAN Result = FALSE;
if (This && Buffer) {
_tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
_tcscat(Buffer, BOISectionGetName(This));
_tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
_tcscat(Buffer, TEXT("\r\n"));
if (This->Contents) {
_tcscat(Buffer, This->Contents);
}
}
return Result;
}
//
// BOI_OS_BOOT_ENTRY Methods
//
static
VOID
BOIOSBEInit(
IN PBOI_OS_BOOT_ENTRY This
)
{
This->OsBootEntry.Delete = BOIOSBEDelete;
This->OsBootEntry.Flush = BOIOSBEFlush;
}
PBOI_SECTION
BOIOSBOFindSection(
IN PBOI_OS_BOOT_OPTIONS This,
IN PTSTR SectionName
)
{
PBOI_SECTION Entry = NULL;
for (Entry = This->Sections; Entry; Entry = Entry->Next) {
if (!_tcsicmp(Entry->Name, SectionName)) {
break; // found the required section
}
}
return Entry;
}
static
POS_BOOT_ENTRY
BOIOSBECreate(
IN ULONG Id,
IN PCTSTR BootEntryLine,
IN PBOI_OS_BOOT_OPTIONS Container
)
{
POS_BOOT_ENTRY Entry = NULL;
if (BootEntryLine && Container) {
BOOLEAN Result = FALSE;
TCHAR Buffer[MAX_PATH * 4];
TCHAR Token[MAX_PATH];
PBOI_OS_BOOT_ENTRY BootEntry = (PBOI_OS_BOOT_ENTRY)SBE_MALLOC(sizeof(BOI_OS_BOOT_ENTRY));
POS_BOOT_ENTRY BaseBootEntry = (POS_BOOT_ENTRY)BootEntry;
//
// Replicate the input string
//
_tcsncpy(Buffer, BootEntryLine, sizeof(Buffer)/sizeof(TCHAR));
//
// Remove unwanted charcters in the string
//
if (BootEntry && BOIOSFixupString(Buffer, TEXT("\n\r"))) {
PTSTR EqualSign = _tcschr(Buffer, TEXT('='));
//
// Initialize object state
//
memset(BootEntry, 0, sizeof(BOI_OS_BOOT_ENTRY));
BOIOSBEInit(BootEntry);
BaseBootEntry->Id = Id;
BaseBootEntry->BootOptions = (POS_BOOT_OPTIONS)Container;
if (EqualSign) {
PTSTR Slash;
*EqualSign = 0;
Slash = _tcschr(Buffer, TEXT('\\'));
if (Slash) {
PTSTR NameStart = NULL, NameEnd = NULL;
PTSTR NextToken = NULL;
Result = TRUE;
*Slash = 0;
//
// Parse & set the boot device name
//
_tcscpy(Token, Buffer);
BOIOSFixupString(Token, TEXT("\n\r "));
_tcslwr(Token);
OSBESetBootVolumeName(BaseBootEntry, Token);
//
// if it starts with "C:" its either old OS,
// or CmdCons or WinPE or Setup entry
//
if (_tcschr(Token, TEXT(':'))) {
OSBE_SET_OLDOS(BaseBootEntry);
}
//
// Parse & set the boot path
//
_tcscpy(Token, Slash + 1);
BOIOSFixupString(Token, TEXT("\n\r "));
OSBESetBootPath(BaseBootEntry, Token);
//
// Parse & set the friendly name
//
NameStart = _tcschr(EqualSign + 1, TEXT('\"'));
//
// Set friendly name
//
if (NameStart) {
NameEnd = _tcschr(NameStart + 1, TEXT('\"'));
}
if (NameEnd) {
_tcsncpy(Token, NameStart, NameEnd - NameStart);
Token[NameEnd - NameStart] = 0;
BOIOSFixupString(Token, TEXT("\r\n\""));
OSBESetFriendlyName(BaseBootEntry, Token);
} else {
Result = FALSE;
}
//
// Set osload options
//
NextToken = _tcschr(EqualSign + 1, TEXT('/'));
if (NextToken) {
_tcscpy(Token, NextToken);
BOIOSFixupString(Token, TEXT("\r\n"));
OSBESetOsLoadOptions(BaseBootEntry, Token);
}
}
}
if (!Result) {
SBE_FREE(BaseBootEntry);
BaseBootEntry = NULL;
} else {
Entry = BaseBootEntry;
}
}
}
return Entry;
}
static
VOID
BOIOSBEDelete(
IN POS_BOOT_ENTRY Obj
)
{
PBOI_OS_BOOT_ENTRY This = (PBOI_OS_BOOT_ENTRY)Obj;
if (This) {
SBE_FREE(This);
}
}
static
BOOLEAN
BOIOSBEWrite(
IN POS_BOOT_ENTRY This,
IN OUT PTSTR Buffer
)
{
BOOLEAN Result = FALSE;
if (This && Buffer && !OSBE_IS_DELETED(This)) {
_tcscat(Buffer, OSBEGetBootVolumeName(This));
_tcscat(Buffer, TEXT("\\"));
_tcscat(Buffer, OSBEGetBootPath(This));
_tcscat(Buffer, TEXT("="));
_tcscat(Buffer, TEXT("\""));
_tcscat(Buffer, OSBEGetFriendlyName(This));
_tcscat(Buffer, TEXT("\""));
_tcscat(Buffer, TEXT(" "));
_tcscat(Buffer, OSBEGetOsLoadOptions(This));
_tcscat(Buffer, TEXT("\r\n"));
Result = TRUE;
}
return Result;
}
static
BOOLEAN
BOIOSBEFlush(
IN POS_BOOT_ENTRY Obj
)
{
return TRUE; // currently can't flush individual entries
}
//
// BOI_OS_BOOT_OPTIONS Methods
//
static
VOID
BOIOSBOInit(
IN PBOI_OS_BOOT_OPTIONS This
)
{
This->OsBootOptions.Delete = BOIOSBODelete;
This->OsBootOptions.Flush = BOIOSBOFlush;
This->OsBootOptions.AddNewBootEntry = BOIOSBOAddNewBootEntry;
This->OsBootOptions.DeleteBootEntry = OSBODeleteBootEntry;
}
BOOLEAN
BOIOSBOParseAndCreateBootEntries(
IN PBOI_OS_BOOT_OPTIONS This,
IN PBOI_SECTION Section
)
{
BOOLEAN Result = FALSE;
if (This && Section) {
Result = TRUE;
if (Section->Contents) {
PTSTR NextLineStart = Section->Contents;
PTSTR NextLineEnd;
TCHAR OldChar;
POS_BOOT_ENTRY FirstBootEntry = NULL;
POS_BOOT_ENTRY BootEntry = NULL;
POS_BOOT_ENTRY LastBootEntry = NULL;
ULONG BootEntryCount;
while (NextLineStart) {
NextLineEnd = _tcschr(NextLineStart, TEXT('\r'));
if (NextLineEnd) {
if (*(NextLineEnd + 1) == TEXT('\n')) {
NextLineEnd++;
}
NextLineEnd++;
OldChar = *NextLineEnd;
*NextLineEnd = 0;
}
//
// Each boot entry line needs to be more than 2 characters in
// length and contain an entry of "a=b" form
//
if ((!NextLineEnd || ((NextLineEnd - NextLineStart) > 2)) &&
(_tcschr(NextLineStart, TEXT('=')))) {
BootEntry = BOIOSBECreate(This->NextEntryId++, NextLineStart, This);
if (BootEntry) {
This->OsBootOptions.EntryCount++;
if (!FirstBootEntry) {
FirstBootEntry = LastBootEntry = BootEntry;
} else {
LastBootEntry->NextEntry = BootEntry;
LastBootEntry = BootEntry;
}
} else {
Result = FALSE;
break; // don't continue on
}
}
if (NextLineEnd) {
*NextLineEnd = OldChar;
}
NextLineStart = NextLineEnd;
}
This->OsBootOptions.BootEntries = FirstBootEntry;
//
// Initialize the boot order array
// NOTE : Doesn't make much sense with boot.ini currently
//
BootEntryCount = OSBOGetBootEntryCount((POS_BOOT_OPTIONS)This);
if (BootEntryCount) {
PULONG BootOrder = (PULONG)SBE_MALLOC(BootEntryCount * sizeof(ULONG));
if (BootOrder) {
ULONG Index = 0;
memset(BootOrder, 0, sizeof(ULONG) * BootEntryCount);
BootEntry = OSBOGetFirstBootEntry((POS_BOOT_OPTIONS)This);
while (BootEntry && (Index < BootEntryCount)) {
BootOrder[Index] = OSBEGetId(BootEntry);
BootEntry = OSBOGetNextBootEntry((POS_BOOT_OPTIONS)This, BootEntry);
}
This->OsBootOptions.BootOrder = BootOrder;
This->OsBootOptions.BootOrderCount = BootEntryCount;
}
}
}
}
return Result;
}
BOOLEAN
BOIOSBOParseTimeoutAndActiveEntry(
IN PBOI_OS_BOOT_OPTIONS This,
IN PBOI_SECTION Section
)
{
BOOLEAN Result = FALSE;
if (This && Section && !_tcsicmp(Section->Name, BOIOS_BOOTLOADER_SECTION)) {
TCHAR Buffer[MAX_PATH * 2];
TCHAR Timeout[MAX_PATH];
TCHAR Default[MAX_PATH];
PTSTR DefKey, TimeoutKey;
PTSTR DefValue;
DWORD TimeKeyLength = _tcslen(BOIOS_TIMEOUT_KEY);
DWORD DefKeyLength = _tcslen(BOIOS_DEFAULT_KEY);
DWORD CopyLength;
Result = TRUE;
_tcscpy(Buffer, Section->Contents);
_tcslwr(Buffer);
BOIOSFixupString(Buffer, TEXT("\r\n "));
Timeout[0] = Default[0] = 0;
DefKey = _tcsstr(Buffer, BOIOS_DEFAULT_KEY);
TimeoutKey = _tcsstr(Buffer, BOIOS_TIMEOUT_KEY);
if (DefKey && TimeoutKey) {
if (DefKey > TimeoutKey) {
CopyLength = DefKey - TimeoutKey - TimeKeyLength;
_tcsncpy(Timeout, TimeoutKey + TimeKeyLength, CopyLength);
Timeout[CopyLength] = 0;
_tcscpy(Default, DefKey + DefKeyLength);
} else {
CopyLength = TimeoutKey - DefKey - DefKeyLength;
_tcsncpy(Default, DefKey + DefKeyLength, CopyLength);
Default[CopyLength] = 0;
_tcscpy(Timeout, TimeoutKey + TimeKeyLength);
}
} else if (DefKey) {
_tcscpy(Default, DefKey + DefKeyLength);
} else if (TimeoutKey) {
_tcscpy(Timeout, TimeoutKey + TimeKeyLength);
}
if (TimeoutKey) {
ULONG TimeoutValue = _ttol(Timeout);
OSBOSetTimeOut((POS_BOOT_OPTIONS)This, TimeoutValue);
}
if (DefKey) {
PTSTR BootPath = _tcschr(Default, TEXT('\\'));
if (BootPath) {
POS_BOOT_ENTRY CurrEntry;
*BootPath = 0;
CurrEntry = OSBOGetFirstBootEntry((POS_BOOT_OPTIONS)This);
while (CurrEntry) {
if (_tcsstr(Default, OSBEGetBootVolumeName(CurrEntry)) &&
!_tcsicmp(OSBEGetBootPath(CurrEntry), BootPath + 1)) {
break;
}
CurrEntry = OSBOGetNextBootEntry((POS_BOOT_OPTIONS)This, CurrEntry);
}
if (CurrEntry) {
OSBOSetActiveBootEntry((POS_BOOT_OPTIONS)This, CurrEntry);
}
} else {
Result = FALSE;
}
}
OSBO_RESET_DIRTY((POS_BOOT_OPTIONS)This);
}
return Result;
}
POS_BOOT_OPTIONS
BOIOSBOCreate(
IN PCTSTR BootIniPath,
IN BOOLEAN OpenExisting
)
{
POS_BOOT_OPTIONS This = NULL;
if (BootIniPath) {
BY_HANDLE_FILE_INFORMATION FileInfo = {0};
PCHAR FileContent = NULL;
HANDLE BootIniHandle;
//
// Open the file
//
BootIniHandle = CreateFile(BootIniPath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if ((BootIniHandle != INVALID_HANDLE_VALUE) &&
GetFileInformationByHandle(BootIniHandle,
&FileInfo)){
//
// Map the file
//
HANDLE MapHandle = CreateFileMapping(BootIniHandle,
NULL,
PAGE_READONLY,
FileInfo.nFileSizeHigh,
FileInfo.nFileSizeLow,
NULL);
if (MapHandle) {
//
// Get hold of view for the file content
//
PVOID FileView = MapViewOfFile(MapHandle,
FILE_MAP_READ,
0,
0,
0);
if (FileView) {
DWORD BytesRead = 0;
//
// Allocate the buffer and read the file contents
//
FileContent = SBE_MALLOC(FileInfo.nFileSizeLow + 1);
if (FileContent) {
if (!ReadFile(BootIniHandle,
FileContent,
FileInfo.nFileSizeLow,
&BytesRead,
NULL)) {
SBE_FREE(FileContent);
FileContent = NULL;
} else {
FileContent[FileInfo.nFileSizeLow] = 0;
}
}
UnmapViewOfFile(FileView);
}
CloseHandle(MapHandle);
}
CloseHandle(BootIniHandle);
} else {
//
// Could be that user is creating boot options fresh
//
if (!OpenExisting) {
PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)SBE_MALLOC(sizeof(BOI_OS_BOOT_OPTIONS));
if (Obj) {
//
// Initialize object
//
memset(Obj, 0, sizeof(BOI_OS_BOOT_OPTIONS));
BOIOSBOInit(Obj);
_tcscpy(Obj->BootIniPath, BootIniPath);
}
This = (POS_BOOT_OPTIONS)Obj;
}
}
//
// If there is any file content then parse it
//
if (FileContent) {
#ifdef UNICODE
PWSTR Content = SBE_MALLOC((FileInfo.nFileSizeLow + 1) * sizeof(WCHAR));
//
// Convert the Ansi/OEM content to unicode content
//
if (Content) {
if (MultiByteToWideChar(CP_OEMCP,
0,
FileContent,
FileInfo.nFileSizeLow,
Content,
FileInfo.nFileSizeLow + 1)) {
Content[FileInfo.nFileSizeLow ] = 0;
} else {
SBE_FREE(Content);
Content = NULL;
}
} else {
SBE_FREE(FileContent);
FileContent = NULL;
}
#else
PCHAR Content = FileContent;
#endif
if (Content && FileContent) {
TCHAR NextLine[MAX_PATH * 4];
PTSTR NextSectionStart = _tcschr(Content, BOIOS_SECTION_NAME_START);
PTSTR NextSectionEnd;
PBOI_SECTION SectionList = NULL;
PBOI_SECTION Section = NULL;
PBOI_SECTION TailSection = NULL;
BOOLEAN Result = TRUE;
//
// Prase the whole files and create section objects
//
while (NextSectionStart) {
TCHAR OldChar;
Section = NULL;
NextSectionEnd = _tcschr(NextSectionStart + 1, BOIOS_SECTION_NAME_START);
if (NextSectionEnd) {
OldChar = *NextSectionEnd;
*NextSectionEnd = 0; // null terminate
}
//
// Create the section object
//
Section = BOISectionCreate(NextSectionStart);
if (NextSectionEnd) {
*NextSectionEnd = OldChar;
}
if (Section) {
if (!SectionList) {
SectionList = Section;
} else {
TailSection->Next = Section;
}
TailSection = Section;
} else {
Result = FALSE;
break;
}
NextSectionStart = NextSectionEnd;
}
if (Result) {
PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)SBE_MALLOC(sizeof(BOI_OS_BOOT_OPTIONS));
if (Obj) {
//
// Initialize object
//
memset(Obj, 0, sizeof(BOI_OS_BOOT_OPTIONS));
BOIOSBOInit(Obj);
_tcscpy(Obj->BootIniPath, BootIniPath);
Obj->Sections = SectionList;
SectionList = NULL;
//
// Get hold of [operating systems] section and
// parse its entries and create boot entries
//
Section = BOIOSBOFindSection(Obj, BOIOS_OS_SECTION);
if (Section) {
Result = BOIOSBOParseAndCreateBootEntries(Obj, Section);
}
//
// Get hold of [boot loader] section and prase its
// entries
//
if (Result) {
Section = BOIOSBOFindSection(Obj, BOIOS_BOOTLOADER_SECTION);
if (Section) {
Result = BOIOSBOParseTimeoutAndActiveEntry(Obj, Section);
}
}
if (!Result) {
//
// Delete the object to free up all the sections
// and the entries
//
BOIOSBODelete((POS_BOOT_OPTIONS)Obj);
Obj = NULL;
}
This = (POS_BOOT_OPTIONS)Obj;
} else {
Result = FALSE;
}
}
//
// free up the allocated sections, in case of failure
//
if (!Result && SectionList) {
while (SectionList) {
Section = SectionList;
SectionList = SectionList->Next;
BOISectionDelete(Section);
}
}
//
// Free the content
//
if ((PVOID)Content != (PVOID)FileContent) {
SBE_FREE(Content);
}
}
SBE_FREE(FileContent);
}
}
return This;
}
static
VOID
BOIOSBODelete(
IN POS_BOOT_OPTIONS Obj
)
{
PBOI_OS_BOOT_OPTIONS This = (PBOI_OS_BOOT_OPTIONS)Obj;
if (This) {
PBOI_SECTION CurrSection, PrevSection;
//
// delete each boot entry
//
POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj);
POS_BOOT_ENTRY PrevEntry;
while (Entry) {
PrevEntry = Entry;
Entry = OSBOGetNextBootEntry(Obj, Entry);
OSBEDelete(PrevEntry);
}
//
// delete all the sections
//
CurrSection = This->Sections;
while (CurrSection) {
PrevSection = CurrSection;
CurrSection = CurrSection->Next;
BOISectionDelete(PrevSection);
}
if (Obj->BootOrder) {
SBE_FREE(Obj->BootOrder);
}
//
// delete the main object
//
SBE_FREE(This);
}
}
static
POS_BOOT_ENTRY
BOIOSBOAddNewBootEntry(
IN POS_BOOT_OPTIONS This,
IN PCTSTR FriendlyName,
IN PCTSTR OsLoaderVolumeName,
IN PCTSTR OsLoaderPath,
IN PCTSTR BootVolumeName,
IN PCTSTR BootPath,
IN PCTSTR OsLoadOptions
)
{
PBOI_OS_BOOT_ENTRY Entry = NULL;
if (This && FriendlyName && BootVolumeName && BootPath) {
Entry = SBE_MALLOC(sizeof(BOI_OS_BOOT_ENTRY));
if (Entry) {
ULONG OrderCount;
PULONG NewOrder;
POS_BOOT_ENTRY BaseEntry = (POS_BOOT_ENTRY)Entry;
PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)This;
//
// init core fields
//
memset(Entry, 0, sizeof(BOI_OS_BOOT_ENTRY));
BOIOSBEInit(Entry);
Entry->OsBootEntry.BootOptions = This;
//
// fill in the attributes
//
OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, FriendlyName);
OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry, BootVolumeName);
OSBESetBootPath((POS_BOOT_ENTRY)Entry, BootPath);
if (OsLoadOptions) {
OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry, OsLoadOptions);
}
BaseEntry->Id = Obj->NextEntryId++;
//
// Flush the entry now to get a proper Id;
//
Entry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
Entry->OsBootEntry.NextEntry = This->BootEntries;
This->BootEntries = (POS_BOOT_ENTRY)Entry;
This->EntryCount++;
//
// Put the new entry at the end of the boot order
//
OrderCount = OSBOGetOrderedBootEntryCount(This);
NewOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
if (NewOrder) {
memset(NewOrder, 0, sizeof(ULONG) * (OrderCount + 1));
//
// copy over the old ordered list
//
memcpy(NewOrder, This->BootOrder, sizeof(ULONG) * OrderCount);
NewOrder[OrderCount] = OSBEGetId((POS_BOOT_ENTRY)Entry);
SBE_FREE(This->BootOrder);
This->BootOrder = NewOrder;
This->BootOrderCount = OrderCount + 1;
} else {
OSBODeleteBootEntry(This, BaseEntry);
Entry = NULL;
}
if (Entry) {
//
// mark it dirty and new for flushing
//
OSBE_SET_NEW(Entry);
OSBE_SET_DIRTY(Entry);
}
}
}
return (POS_BOOT_ENTRY)Entry;
}
static
BOOLEAN
BOIOSBOWrite(
IN PBOI_OS_BOOT_OPTIONS This,
IN PCTSTR Buffer
)
{
BOOLEAN Result = FALSE;
if (This && Buffer) {
TCHAR BackupFileName[MAX_PATH];
PTSTR Extension;
HANDLE FileHandle;
//
// Create a backup name
//
_tcscpy(BackupFileName, This->BootIniPath);
Extension = _tcschr(BackupFileName, TEXT('.'));
if (Extension) {
_tcscpy(Extension, TEXT(".BAK"));
} else {
_tcscat(BackupFileName, TEXT(".BAK"));
}
//
// Delete the backup file if it exists
//
SetFileAttributes(BackupFileName, FILE_ATTRIBUTE_NORMAL);
DeleteFile(BackupFileName);
//
// Copy the existing boot.ini as backup file
//
SetFileAttributes(This->BootIniPath, FILE_ATTRIBUTE_NORMAL);
CopyFile(This->BootIniPath, BackupFileName, FALSE);
//
// Create new boot.ini file
//
FileHandle = CreateFile(This->BootIniPath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle && (FileHandle != INVALID_HANDLE_VALUE)) {
PCHAR AnsiBuffer;
ULONG BufferLength = _tcslen(Buffer);
DWORD BytesWritten = 0;
Result = TRUE;
#ifdef UNICODE
//
// Convert the unicode buffer to ansi buffer
//
AnsiBuffer = (PCHAR)SBE_MALLOC(BufferLength + 1);
if (AnsiBuffer) {
memset(AnsiBuffer, 0, BufferLength);
if (WideCharToMultiByte(CP_OEMCP,
0,
Buffer,
BufferLength,
AnsiBuffer,
BufferLength,
NULL,
NULL)) {
Result = TRUE;
AnsiBuffer[BufferLength] = 0;
} else {
Result = FALSE;
}
}
#else
AnsiBuffer = Buffer;
#endif
//
// Write the buffer to the file
//
if (AnsiBuffer &&
!WriteFile(FileHandle,
AnsiBuffer,
BufferLength,
&BytesWritten,
NULL)) {
Result = FALSE;
}
if ((PVOID)AnsiBuffer != (PVOID)Buffer) {
SBE_FREE(AnsiBuffer);
AnsiBuffer = NULL;
}
//
// Done with the file handle
//
CloseHandle(FileHandle);
SetFileAttributes(This->BootIniPath,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
}
}
return Result;
}
static
BOOLEAN
BOIOSBOFlush(
IN POS_BOOT_OPTIONS Obj
)
{
BOOLEAN Result = FALSE;
PBOI_OS_BOOT_OPTIONS This = (PBOI_OS_BOOT_OPTIONS)Obj;
if (This) {
PTSTR Buffer = (PTSTR)SBE_MALLOC(MAX_BOOT_INI_SIZE * sizeof(TCHAR));
if (Buffer) {
TCHAR ScratchBuffer[MAX_PATH * 2] = {0};
POS_BOOT_ENTRY ActiveEntry = OSBOGetActiveBootEntry(Obj);
POS_BOOT_ENTRY CurrentEntry;
PBOI_SECTION CurrentSection;
Result = TRUE;
memset(Buffer, 0, MAX_BOOT_INI_SIZE * sizeof(TCHAR));
//
// first flush the boot options
//
_tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
_tcscat(Buffer, BOIOS_BOOTLOADER_SECTION);
_tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
_tcscat(Buffer, TEXT("\r\n"));
//
// write time out
//
_tcscat(Buffer, BOIOS_TIMEOUT_KEY);
_tcscat(Buffer, _ltot(Obj->Timeout, ScratchBuffer, 10));
_tcscat(Buffer, TEXT("\r\n"));
//
// write active entry
//
if (ActiveEntry) {
_tcscpy(ScratchBuffer, BOIOS_DEFAULT_KEY);
_tcscat(ScratchBuffer, OSBEGetBootVolumeName(ActiveEntry));
_tcscat(ScratchBuffer, TEXT("\\"));
_tcscat(ScratchBuffer, OSBEGetBootPath(ActiveEntry));
_tcscat(ScratchBuffer, TEXT("\r\n"));
_tcscat(Buffer, ScratchBuffer);
}
//
// Write the boot entries section
//
_tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
_tcscat(Buffer, BOIOS_OS_SECTION);
_tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
_tcscat(Buffer, TEXT("\r\n"));
//
// write each boot entry now
//
//
// First write the valid arc entries
//
CurrentEntry = OSBOGetFirstBootEntry(Obj);
while (Result && CurrentEntry) {
if (!OSBE_IS_DELETED(CurrentEntry) &&
!OSBE_IS_OLDOS(CurrentEntry)) {
Result = BOIOSBEWrite(CurrentEntry, Buffer);
}
CurrentEntry = OSBOGetNextBootEntry(Obj, CurrentEntry);
}
//
// Now write the old OS entries
// NOTE : We do this for backward compatabily reasons
//
CurrentEntry = OSBOGetFirstBootEntry(Obj);
while (Result && CurrentEntry) {
if (OSBE_IS_OLDOS(CurrentEntry)) {
Result = BOIOSBEWrite(CurrentEntry, Buffer);
}
CurrentEntry = OSBOGetNextBootEntry(Obj, CurrentEntry);
}
//
// Write any additions sections which were present on the
//
CurrentSection = BOIOSGetFirstSection(This);
while (Result && CurrentSection) {
//
// Write all the other additional sections in boot.ini other
// than [boot loader] and [operating systems]
//
if (_tcsicmp(BOISectionGetName(CurrentSection), BOIOS_BOOTLOADER_SECTION) &&
_tcsicmp(BOISectionGetName(CurrentSection), BOIOS_OS_SECTION)) {
Result = BOISectionWrite(CurrentSection, Buffer);
}
CurrentSection = BOIOSGetNextSection(This, CurrentSection);
}
Result = BOIOSBOWrite(This, Buffer);
//
// Free the allocated buffer
//
SBE_FREE(Buffer);
}
}
return Result;
}