/* * ReactOS kernel * Copyright (C) 2002 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/bootsup.c * PURPOSE: Bootloader support functions * PROGRAMMER: Eric Kohl */ #include #include #include "usetup.h" #include "inicache.h" #include "bootsup.h" #define SECTORSIZE 512 /* FUNCTIONS ****************************************************************/ static VOID CreateCommonFreeLoaderSections(PINICACHE IniCache) { PINICACHESECTION IniSection; /* Create "FREELOADER" section */ IniSection = IniCacheAppendSection(IniCache, L"FREELOADER"); /* DefaultOS=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"DefaultOS", L"ReactOS"); #if 0 /* Timeout=10 */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"TimeOut", L"10"); #endif /* Create "Display" section */ IniSection = IniCacheAppendSection(IniCache, L"Display"); /* TitleText=ReactOS Boot Manager */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"TitleText", L"ReactOS Boot Manager"); /* StatusBarColor=Cyan */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"StatusBarColor", L"Cyan"); /* StatusBarTextColor=Black */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"StatusBarTextColor", L"Black"); /* BackdropTextColor=White */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BackdropTextColor", L"White"); /* BackdropColor=Blue */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BackdropColor", L"Blue"); /* BackdropFillStyle=Medium */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BackdropFillStyle", L"Medium"); /* TitleBoxTextColor=White */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"TitleBoxTextColor", L"White"); /* TitleBoxColor=Red */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"TitleBoxColor", L"Red"); /* MessageBoxTextColor=White */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"MessageBoxTextColor", L"White"); /* MessageBoxColor=Blue */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"MessageBoxColor", L"Blue"); /* MenuTextColor=White */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"MenuTextColor", L"White"); /* MenuColor=Blue */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"MenuColor", L"Blue"); /* TextColor=Yellow */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"TextColor", L"Yellow"); /* SelectedTextColor=Black */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SelectedTextColor", L"Black"); /* SelectedColor=Gray */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SelectedColor", L"Gray"); } NTSTATUS CreateFreeLoaderIniForDos(PWCHAR IniPath, PWCHAR ArcPath) { PINICACHE IniCache; PINICACHESECTION IniSection; IniCache = IniCacheCreate(); CreateCommonFreeLoaderSections(IniCache); /* Create "Operating Systems" section */ IniSection = IniCacheAppendSection(IniCache, L"Operating Systems"); /* REACTOS=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"ReactOS", L"\"ReactOS\""); /* ReactOS_Debug="ReactOS (Debug)" */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"ReactOS_Debug", L"\"ReactOS (Debug)\""); /* DOS=Dos/Windows */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"DOS", L"\"DOS/Windows\""); /* Create "ReactOS" section */ IniSection = IniCacheAppendSection(IniCache, L"ReactOS"); /* BootType=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootType", L"ReactOS"); /* SystemPath= */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SystemPath", ArcPath); /* Create "ReactOS_Debug" section */ IniSection = IniCacheAppendSection(IniCache, L"ReactOS_Debug"); /* BootType=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootType", L"ReactOS"); /* SystemPath= */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SystemPath", ArcPath); /* Options=/DEBUGPORT=SCREEN */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"Options", L"/DEBUGPORT=SCREEN"); /* Create "DOS" section */ IniSection = IniCacheAppendSection(IniCache, L"DOS"); /* BootType=BootSector */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootType", L"BootSector"); /* BootDrive=hd0 */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootDrive", L"hd0"); /* BootPartition=1 */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootPartition", L"1"); /* BootSector=BOOTSECT.DOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootSectorFile", L"BOOTSECT.DOS"); IniCacheSave(IniCache, IniPath); IniCacheDestroy(IniCache); return(STATUS_SUCCESS); } NTSTATUS CreateFreeLoaderIniForReactos(PWCHAR IniPath, PWCHAR ArcPath) { PINICACHE IniCache; PINICACHESECTION IniSection; IniCache = IniCacheCreate(); CreateCommonFreeLoaderSections(IniCache); /* Create "Operating Systems" section */ IniSection = IniCacheAppendSection(IniCache, L"Operating Systems"); /* ReactOS="ReactOS" */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"ReactOS", L"\"ReactOS\""); /* ReactOS_Debug="ReactOS (Debug)" */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"ReactOS_Debug", L"\"ReactOS (Debug)\""); /* Create "ReactOS" section */ IniSection = IniCacheAppendSection(IniCache, L"ReactOS"); /* BootType=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootType", L"ReactOS"); /* SystemPath= */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SystemPath", ArcPath); /* Create "ReactOS_Debug" section */ IniSection = IniCacheAppendSection(IniCache, L"ReactOS_Debug"); /* BootType=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootType", L"ReactOS"); /* SystemPath= */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SystemPath", ArcPath); /* Options=/DEBUGPORT=SCREEN */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"Options", L"/DEBUGPORT=SCREEN"); /* Save the ini file */ IniCacheSave(IniCache, IniPath); IniCacheDestroy(IniCache); return(STATUS_SUCCESS); } NTSTATUS UpdateFreeLoaderIni(PWCHAR IniPath, PWCHAR ArcPath) { UNICODE_STRING Name; PINICACHE IniCache; PINICACHESECTION IniSection; WCHAR SectionName[80]; WCHAR OsName[80]; PWCHAR KeyData; ULONG i; NTSTATUS Status; RtlInitUnicodeString(&Name, IniPath); Status = IniCacheLoad(&IniCache, &Name, FALSE); if (!NT_SUCCESS(Status)) return(Status); /* Get "Operating Systems" section */ IniSection = IniCacheGetSection(IniCache, L"Operating Systems"); if (IniSection == NULL) return(STATUS_UNSUCCESSFUL); /* Find an unused section name */ i = 1; wcscpy(SectionName, L"ReactOS"); wcscpy(OsName, L"\"ReactOS\""); while(TRUE) { Status = IniCacheGetKey(IniSection, SectionName, &KeyData); if (!NT_SUCCESS(Status)) break; swprintf(SectionName, L"ReactOS_%lu", i); swprintf(OsName, L"\"ReactOS %lu\"", i); i++; } /* = */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, SectionName, OsName); /* Create section */ IniSection = IniCacheAppendSection(IniCache, SectionName); /* BootType=ReactOS */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"BootType", L"ReactOS"); /* SystemPath= */ IniCacheInsertKey(IniSection, NULL, INSERT_LAST, L"SystemPath", ArcPath); IniCacheSave(IniCache, IniPath); IniCacheDestroy(IniCache); return(STATUS_SUCCESS); } NTSTATUS SaveCurrentBootSector(PWSTR RootPath, PWSTR DstPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; PUCHAR BootSector; /* Allocate buffer for bootsector */ BootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (BootSector == NULL) return(STATUS_INSUFFICIENT_RESOURCES); /* Read current boot sector into buffer */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, BootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, BootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, BootSector); return(Status); } /* Write bootsector to DstPath */ RtlInitUnicodeString(&Name, DstPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtCreateFile(&FileHandle, FILE_WRITE_ACCESS, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY, NULL, 0); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, BootSector); return(Status); } Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, BootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); /* Free the new boot sector */ RtlFreeHeap(ProcessHeap, 0, BootSector); return(Status); } NTSTATUS InstallFat16BootCodeToFile(PWSTR SrcPath, PWSTR DstPath, PWSTR RootPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; PUCHAR OrigBootSector; PUCHAR NewBootSector; /* Allocate buffer for original bootsector */ OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (OrigBootSector == NULL) return(STATUS_INSUFFICIENT_RESOURCES); /* Read current boot sector into buffer */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, OrigBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } /* Allocate buffer for new bootsector */ NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (NewBootSector == NULL) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(STATUS_INSUFFICIENT_RESOURCES); } /* Read new bootsector from SrcPath */ RtlInitUnicodeString(&Name, SrcPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Adjust bootsector (copy a part of the FAT BPB) */ memcpy((NewBootSector + 11), (OrigBootSector + 11), 51 /*fat BPB length*/); /* Free the original boot sector */ RtlFreeHeap(ProcessHeap, 0, OrigBootSector); /* Write new bootsector to DstPath */ RtlInitUnicodeString(&Name, DstPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtCreateFile(&FileHandle, FILE_WRITE_ACCESS, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY, NULL, 0); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } #if 0 FilePosition.QuadPart = 0; #endif Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); /* Free the new boot sector */ RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } NTSTATUS InstallFat32BootCodeToFile(PWSTR SrcPath, PWSTR DstPath, PWSTR RootPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; PUCHAR OrigBootSector; PUCHAR NewBootSector; LARGE_INTEGER FileOffset; /* Allocate buffer for original bootsector */ OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (OrigBootSector == NULL) return(STATUS_INSUFFICIENT_RESOURCES); /* Read current boot sector into buffer */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, OrigBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { CHECKPOINT1; RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } /* Allocate buffer for new bootsector (2 sectors) */ NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE); if (NewBootSector == NULL) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(STATUS_INSUFFICIENT_RESOURCES); } /* Read new bootsector from SrcPath */ RtlInitUnicodeString(&Name, SrcPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, 2 * SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Adjust bootsector (copy a part of the FAT32 BPB) */ memcpy((NewBootSector + 3), (OrigBootSector + 3), 87); /* FAT32 BPB length */ /* Disable the backup boot sector */ NewBootSector[0x32] = 0x00; NewBootSector[0x33] = 0x00; /* Free the original boot sector */ RtlFreeHeap(ProcessHeap, 0, OrigBootSector); /* Write the first sector of the new bootcode to DstPath */ RtlInitUnicodeString(&Name, DstPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtCreateFile(&FileHandle, FILE_WRITE_ACCESS, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY, NULL, 0); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Write the second sector of the new bootcode to boot disk sector 14 */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_WRITE_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE); Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, (NewBootSector + SECTORSIZE), SECTORSIZE, &FileOffset, NULL); if (!NT_SUCCESS(Status)) { } NtClose(FileHandle); /* Free the new boot sector */ RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } NTSTATUS InstallMbrBootCodeToDisk (PWSTR SrcPath, PWSTR RootPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; PUCHAR OrigBootSector; PUCHAR NewBootSector; /* Allocate buffer for original bootsector */ OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (OrigBootSector == NULL) return(STATUS_INSUFFICIENT_RESOURCES); /* Read current boot sector into buffer */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, OrigBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } /* Allocate buffer for new bootsector */ NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (NewBootSector == NULL) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(STATUS_INSUFFICIENT_RESOURCES); } /* Read new bootsector from SrcPath */ RtlInitUnicodeString(&Name, SrcPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Copy partition table from old MBR to new */ RtlCopyMemory ((NewBootSector + 446), (OrigBootSector + 446), 4*16 /* Length of partition table */); /* Free the original boot sector */ RtlFreeHeap(ProcessHeap, 0, OrigBootSector); /* Write new bootsector to RootPath */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtCreateFile(&FileHandle, FILE_WRITE_ACCESS, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY, NULL, 0); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); /* Free the new boot sector */ RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } NTSTATUS InstallFat16BootCodeToDisk(PWSTR SrcPath, PWSTR RootPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; PUCHAR OrigBootSector; PUCHAR NewBootSector; /* Allocate buffer for original bootsector */ OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (OrigBootSector == NULL) return(STATUS_INSUFFICIENT_RESOURCES); /* Read current boot sector into buffer */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, OrigBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } /* Allocate buffer for new bootsector */ NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (NewBootSector == NULL) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(STATUS_INSUFFICIENT_RESOURCES); } /* Read new bootsector from SrcPath */ RtlInitUnicodeString(&Name, SrcPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Adjust bootsector (copy a part of the FAT16 BPB) */ memcpy((NewBootSector + 3), (OrigBootSector + 3), 59); /* FAT16 BPB length*/ /* Free the original boot sector */ RtlFreeHeap(ProcessHeap, 0, OrigBootSector); /* Write new bootsector to RootPath */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtCreateFile(&FileHandle, FILE_WRITE_ACCESS, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY, NULL, 0); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } #if 0 FilePosition.QuadPart = 0; #endif Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); /* Free the new boot sector */ RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } NTSTATUS InstallFat32BootCodeToDisk(PWSTR SrcPath, PWSTR RootPath) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; PUCHAR OrigBootSector; PUCHAR NewBootSector; LARGE_INTEGER FileOffset; USHORT BackupBootSector; /* Allocate buffer for original bootsector */ OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); if (OrigBootSector == NULL) return(STATUS_INSUFFICIENT_RESOURCES); /* Read current boot sector into buffer */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, OrigBootSector, SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(Status); } /* Allocate buffer for new bootsector (2 sectors) */ NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE); if (NewBootSector == NULL) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return(STATUS_INSUFFICIENT_RESOURCES); } /* Read new bootsector from SrcPath */ RtlInitUnicodeString(&Name, SrcPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } Status = NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, 2 * SECTORSIZE, NULL, NULL); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { RtlFreeHeap(ProcessHeap, 0, OrigBootSector); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Adjust bootsector (copy a part of the FAT32 BPB) */ memcpy((NewBootSector + 3), (OrigBootSector + 3), 87); /* FAT32 BPB length */ /* Get the location of the backup boot sector */ BackupBootSector = (OrigBootSector[0x33] << 8) + OrigBootSector[0x32]; /* Free the original boot sector */ RtlFreeHeap(ProcessHeap, 0, OrigBootSector); /* Write the first sector of the new bootcode to DstPath */ RtlInitUnicodeString(&Name, RootPath); InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Write sector 0 */ FileOffset.QuadPart = 0ULL; Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); NtClose(FileHandle); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } /* Write backup boot sector */ if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF)) { FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE); Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, NewBootSector, SECTORSIZE, &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); NtClose(FileHandle); RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } } /* Write sector 14 */ FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE); Status = NtWriteFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, (NewBootSector + SECTORSIZE), SECTORSIZE, &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); } NtClose(FileHandle); /* Free the new boot sector */ RtlFreeHeap(ProcessHeap, 0, NewBootSector); return(Status); } static NTSTATUS UnprotectBootIni(PWSTR FileName, PULONG Attributes) { UNICODE_STRING Name; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileInfo; HANDLE FileHandle; NTSTATUS Status; RtlInitUnicodeString(&Name, FileName); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (Status == STATUS_NO_SUCH_FILE) { DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); *Attributes = 0; return(STATUS_SUCCESS); } if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); return(Status); } Status = NtQueryInformationFile(FileHandle, &IoStatusBlock, &FileInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status); NtClose(FileHandle); 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 %lx)\n", Status); } NtClose(FileHandle); return(Status); } static NTSTATUS ProtectBootIni(PWSTR FileName, ULONG Attributes) { UNICODE_STRING Name; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileInfo; HANDLE FileHandle; NTSTATUS Status; RtlInitUnicodeString(&Name, FileName); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); return(Status); } Status = NtQueryInformationFile(FileHandle, &IoStatusBlock, &FileInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status); NtClose(FileHandle); 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 %lx)\n", Status); } NtClose(FileHandle); return(Status); } NTSTATUS UpdateBootIni(PWSTR BootIniPath, PWSTR EntryName, PWSTR EntryValue) { UNICODE_STRING Name; PINICACHE Cache = NULL; PINICACHESECTION Section = NULL; NTSTATUS Status; ULONG FileAttribute; RtlInitUnicodeString(&Name, BootIniPath); Status = IniCacheLoad(&Cache, &Name, FALSE); if (!NT_SUCCESS(Status)) { CHECKPOINT1; return(Status); } Section = IniCacheGetSection(Cache, L"operating systems"); if (Section == NULL) { CHECKPOINT1; IniCacheDestroy(Cache); return(STATUS_UNSUCCESSFUL); } IniCacheInsertKey(Section, NULL, INSERT_LAST, EntryName, EntryValue); Status = UnprotectBootIni(BootIniPath, &FileAttribute); if (!NT_SUCCESS(Status)) { CHECKPOINT1; IniCacheDestroy(Cache); return(Status); } Status = IniCacheSave(Cache, BootIniPath); if (!NT_SUCCESS(Status)) { CHECKPOINT1; IniCacheDestroy(Cache); return(Status); } FileAttribute |= (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); Status = ProtectBootIni(BootIniPath, FileAttribute); IniCacheDestroy(Cache); return(Status); } /* EOF */