/*++ 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 // // 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; }