https://git.reactos.org/?p=reactos.git;a=commitdiff;h=593bcce9991d56de97e6e3...
commit 593bcce9991d56de97e6e34c8acbf0b1bc1fa0cc Author: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org AuthorDate: Sat Oct 17 20:29:47 2020 +0200 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Sun Oct 18 20:56:16 2020 +0200
[SETUPLIB] Code re-organization in bootsup.c and fsutil.c.
- Move the actual VBR bootcode installation helpers into fsutil.c (they depend on the selected filesystem).
- Introduce InstallBootCodeToDisk() and InstallBootCodeToFile() and bootcode.c helpers, in order to replace the several functions that were duplicating the same code. --- base/setup/lib/CMakeLists.txt | 1 + base/setup/lib/bootcode.c | 116 ++++ base/setup/lib/bootcode.h | 37 + base/setup/lib/bootsup.c | 1535 ++++++----------------------------------- base/setup/lib/fsutil.c | 380 +++++++++- base/setup/lib/fsutil.h | 38 +- base/setup/lib/setuplib.h | 5 +- 7 files changed, 792 insertions(+), 1320 deletions(-)
diff --git a/base/setup/lib/CMakeLists.txt b/base/setup/lib/CMakeLists.txt index ff23bc57d16..68b00922b14 100644 --- a/base/setup/lib/CMakeLists.txt +++ b/base/setup/lib/CMakeLists.txt @@ -16,6 +16,7 @@ list(APPEND SOURCE utils/osdetect.c utils/partlist.c utils/regutil.c + bootcode.c bootsup.c fsutil.c install.c diff --git a/base/setup/lib/bootcode.c b/base/setup/lib/bootcode.c new file mode 100644 index 00000000000..b72ac1fab42 --- /dev/null +++ b/base/setup/lib/bootcode.c @@ -0,0 +1,116 @@ +/* + * PROJECT: ReactOS Setup Library + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: BootCode support functions. + * COPYRIGHT: Copyright 2020 Hermes Belusca-Maito + */ + +/* INCLUDES *****************************************************************/ + +#include "precomp.h" + +#include "bootcode.h" + +#define NDEBUG +#include <debug.h> + + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS +ReadBootCodeByHandle( + IN OUT PBOOTCODE BootCodeInfo, + IN HANDLE FileHandle, + IN ULONG Length OPTIONAL) +{ + NTSTATUS Status; + PVOID BootCode; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER FileOffset; + + ASSERT(BootCodeInfo); + + /* Normalize the bootcode length */ + if (Length == 0 || Length == (ULONG)-1) + Length = SECTORSIZE; + + /* Allocate a buffer for the bootcode */ + BootCode = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, Length); + if (BootCode == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Read the bootcode from the file into the buffer */ + FileOffset.QuadPart = 0ULL; + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + BootCode, + Length, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, BootCode); + return Status; + } + + /* Update the bootcode information */ + if (BootCodeInfo->BootCode) + RtlFreeHeap(ProcessHeap, 0, BootCodeInfo->BootCode); + BootCodeInfo->BootCode = BootCode; + /**/ BootCodeInfo->Length = Length; /**/ + + return STATUS_SUCCESS; +} + +NTSTATUS +ReadBootCodeFromFile( + IN OUT PBOOTCODE BootCodeInfo, + IN PUNICODE_STRING FilePath, + IN ULONG Length OPTIONAL) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE FileHandle; + + ASSERT(BootCodeInfo); + + /* Open the file */ + InitializeObjectAttributes(&ObjectAttributes, + FilePath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenFile(&FileHandle, + GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, // Is FILE_SHARE_WRITE necessary? + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + return Status; + + Status = ReadBootCodeByHandle(BootCodeInfo, FileHandle, Length); + + /* Close the file and return */ + NtClose(FileHandle); + return Status; +} + +VOID +FreeBootCode( + IN OUT PBOOTCODE BootCodeInfo) +{ + ASSERT(BootCodeInfo); + + /* Update the bootcode information */ + if (BootCodeInfo->BootCode) + RtlFreeHeap(ProcessHeap, 0, BootCodeInfo->BootCode); + BootCodeInfo->BootCode = NULL; + /**/ BootCodeInfo->Length = 0; /**/ +} + +/* EOF */ diff --git a/base/setup/lib/bootcode.h b/base/setup/lib/bootcode.h new file mode 100644 index 00000000000..cd8c8269e21 --- /dev/null +++ b/base/setup/lib/bootcode.h @@ -0,0 +1,37 @@ +/* + * PROJECT: ReactOS Setup Library + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: BootCode support functions. + * COPYRIGHT: Copyright 2020 Hermes Belusca-Maito + */ + +#pragma once + +#ifdef SECTORSIZE +#undef SECTORSIZE +#endif +#define SECTORSIZE 512 + +typedef struct _BOOTCODE +{ + PVOID BootCode; + ULONG Length; +} BOOTCODE, *PBOOTCODE; + +NTSTATUS +ReadBootCodeByHandle( + IN OUT PBOOTCODE BootCodeInfo, + IN HANDLE FileHandle, + IN ULONG Length OPTIONAL); + +NTSTATUS +ReadBootCodeFromFile( + IN OUT PBOOTCODE BootCodeInfo, + IN PUNICODE_STRING FilePath, + IN ULONG Length OPTIONAL); + +VOID +FreeBootCode( + IN OUT PBOOTCODE BootCodeInfo); + +/* EOF */ diff --git a/base/setup/lib/bootsup.c b/base/setup/lib/bootsup.c index ec9a1a4cf56..c7462403630 100644 --- a/base/setup/lib/bootsup.c +++ b/base/setup/lib/bootsup.c @@ -13,8 +13,9 @@
#include "bldrsup.h" #include "filesup.h" -#include "fsutil.h" #include "partlist.h" +#include "bootcode.h" +#include "fsutil.h"
#include "setuplib.h" // HAXX for IsUnattendedSetup!!
@@ -23,108 +24,17 @@ #define NDEBUG #include <debug.h>
- -/* TYPEDEFS *****************************************************************/ - /* * BIG FIXME!! * =========== * - * All that stuff *MUST* go into the fsutil.c module. - * Indeed, all that relates to filesystem formatting details and as such - * *MUST* be abstracted out from this module (bootsup.c). - * However, bootsup.c can still deal with MBR code (actually it'll have - * at some point to share or give it to partlist.c, because when we'll - * support GPT disks, things will change a bit). - * And, bootsup.c can still manage initializing / adding boot entries - * into NTLDR and FREELDR, and installing the latter, and saving the old - * MBR / boot sectors in files. + * bootsup.c can deal with MBR code (actually it'll have at some point + * to share or give it to partlist.c, because when we'll support GPT disks, + * things will change a bit). + * And, bootsup.c can manage initializing / adding boot entries into NTLDR + * and FREELDR, and installing the latter, and saving the old MBR / boot + * sectors in files. */ -#define SECTORSIZE 512 - -#include <pshpack1.h> -typedef struct _FAT_BOOTSECTOR -{ - UCHAR JumpBoot[3]; // Jump instruction to boot code - CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes - USHORT BytesPerSector; // Bytes per sector - UCHAR SectorsPerCluster; // Number of sectors in a cluster - USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector) - UCHAR NumberOfFats; // Number of FAT tables - USHORT RootDirEntries; // Number of root directory entries (fat12/16) - USHORT TotalSectors; // Number of total sectors on the drive, 16-bit - UCHAR MediaDescriptor; // Media descriptor byte - USHORT SectorsPerFat; // Sectors per FAT table (fat12/16) - USHORT SectorsPerTrack; // Number of sectors in a track - USHORT NumberOfHeads; // Number of heads on the disk - ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) - ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume - UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80) - UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0. - UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present. - ULONG VolumeSerialNumber; // Volume serial number - CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory - CHAR FileSystemType[8]; // One of the strings "FAT12 ", "FAT16 ", or "FAT " - - UCHAR BootCodeAndData[448]; // The remainder of the boot sector - - USHORT BootSectorMagic; // 0xAA55 - -} FAT_BOOTSECTOR, *PFAT_BOOTSECTOR; - -typedef struct _FAT32_BOOTSECTOR -{ - UCHAR JumpBoot[3]; // Jump instruction to boot code - CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes - USHORT BytesPerSector; // Bytes per sector - UCHAR SectorsPerCluster; // Number of sectors in a cluster - USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector) - UCHAR NumberOfFats; // Number of FAT tables - USHORT RootDirEntries; // Number of root directory entries (fat12/16) - USHORT TotalSectors; // Number of total sectors on the drive, 16-bit - UCHAR MediaDescriptor; // Media descriptor byte - USHORT SectorsPerFat; // Sectors per FAT table (fat12/16) - USHORT SectorsPerTrack; // Number of sectors in a track - USHORT NumberOfHeads; // Number of heads on the disk - ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) - ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume - ULONG SectorsPerFatBig; // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0 - USHORT ExtendedFlags; // Extended flags (fat32) - USHORT FileSystemVersion; // File system version (fat32) - ULONG RootDirStartCluster; // Starting cluster of the root directory (fat32) - USHORT FsInfo; // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1. - USHORT BackupBootSector; // If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6. - UCHAR Reserved[12]; // Reserved for future expansion - UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80) - UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0. - UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present. - ULONG VolumeSerialNumber; // Volume serial number - CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory - CHAR FileSystemType[8]; // Always set to the string "FAT32 " - - UCHAR BootCodeAndData[420]; // The remainder of the boot sector - - USHORT BootSectorMagic; // 0xAA55 - -} FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR; - -typedef struct _BTRFS_BOOTSECTOR -{ - UCHAR JumpBoot[3]; - UCHAR ChunkMapSize; - UCHAR BootDrive; - ULONGLONG PartitionStartLBA; - UCHAR Fill[1521]; // 1536 - 15 - USHORT BootSectorMagic; -} BTRFS_BOOTSECTOR, *PBTRFS_BOOTSECTOR; -C_ASSERT(sizeof(BTRFS_BOOTSECTOR) == 3 * 512); - -// TODO: Add more bootsector structures! - -#include <poppack.h> - -/* End of BIG FIXME!! */ -
/* FUNCTIONS ****************************************************************/
@@ -550,63 +460,26 @@ IsThereAValidBootSector( BOOLEAN IsValid = FALSE; NTSTATUS Status; UNICODE_STRING RootPartition; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - LARGE_INTEGER FileOffset; - PUCHAR BootSector; + BOOTCODE BootSector = {0};
- /* Allocate buffer for bootsector */ - BootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); - if (BootSector == NULL) - return FALSE; // STATUS_INSUFFICIENT_RESOURCES; - RtlZeroMemory(BootSector, SECTORSIZE); - - /* Open the root partition - Remove any trailing backslash if needed */ + /* Allocate and read the root partition bootsector. + * Remove any trailing backslash if needed. */ RtlInitUnicodeString(&RootPartition, RootPath); TrimTrailingPathSeparators_UStr(&RootPartition); - - InitializeObjectAttributes(&ObjectAttributes, - &RootPartition, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - goto Quit; - - /* Read current boot sector into buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - BootSector, - SECTORSIZE, - &FileOffset, - NULL); - NtClose(FileHandle); + Status = ReadBootCodeFromFile(&BootSector, &RootPartition, SECTORSIZE); if (!NT_SUCCESS(Status)) - goto Quit; + return FALSE;
/* Check for the existence of the bootsector signature */ - IsValid = (*(PUSHORT)(BootSector + 0x1FE) == 0xAA55); + IsValid = (*(PUSHORT)((PUCHAR)BootSector.BootCode + 0x1FE) == 0xAA55); if (IsValid) { /* Check for the first instruction encoded on three bytes */ - IsValid = (((*(PULONG)BootSector) & 0x00FFFFFF) != 0x00000000); + IsValid = (((*(PULONG)BootSector.BootCode) & 0x00FFFFFF) != 0x00000000); }
-Quit: - /* Free the boot sector */ - RtlFreeHeap(ProcessHeap, 0, BootSector); + /* Free the bootsector and return */ + FreeBootCode(&BootSector); return IsValid; }
@@ -622,55 +495,18 @@ SaveBootSector( OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; HANDLE FileHandle; - LARGE_INTEGER FileOffset; - PUCHAR BootSector; - - /* Allocate buffer for bootsector */ - BootSector = RtlAllocateHeap(ProcessHeap, 0, Length); - if (BootSector == NULL) - return STATUS_INSUFFICIENT_RESOURCES; + // LARGE_INTEGER FileOffset; + BOOTCODE BootSector = {0};
- /* Open the root partition - Remove any trailing backslash if needed */ + /* Allocate and read the root partition bootsector. + * Remove any trailing backslash if needed. */ RtlInitUnicodeString(&Name, RootPath); TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, BootSector); - return Status; - } - - /* Read current boot sector into buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - BootSector, - Length, - &FileOffset, - NULL); - NtClose(FileHandle); + Status = ReadBootCodeFromFile(&BootSector, &Name, Length); if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, BootSector); return Status; - }
- /* Write bootsector to DstPath */ + /* Write the bootsector to DstPath */ RtlInitUnicodeString(&Name, DstPath); InitializeObjectAttributes(&ObjectAttributes, &Name, @@ -691,7 +527,7 @@ SaveBootSector( 0); if (!NT_SUCCESS(Status)) { - RtlFreeHeap(ProcessHeap, 0, BootSector); + FreeBootCode(&BootSector); return Status; }
@@ -700,40 +536,36 @@ SaveBootSector( NULL, NULL, &IoStatusBlock, - BootSector, - Length, + BootSector.BootCode, + BootSector.Length, NULL, NULL); NtClose(FileHandle);
- /* Free the boot sector */ - RtlFreeHeap(ProcessHeap, 0, BootSector); - + /* Free the bootsector and return */ + FreeBootCode(&BootSector); return Status; }
static NTSTATUS -InstallMbrBootCodeToDiskHelper( +InstallBootCodeToDisk( IN PCWSTR SrcPath, - IN PCWSTR RootPath) + IN PCWSTR RootPath, + IN PFS_INSTALL_BOOTCODE InstallBootCode) { NTSTATUS Status; UNICODE_STRING Name; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - LARGE_INTEGER FileOffset; - PPARTITION_SECTOR OrigBootSector; - PPARTITION_SECTOR NewBootSector; - - /* Allocate buffer for original bootsector */ - OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTITION_SECTOR)); - if (OrigBootSector == NULL) - return STATUS_INSUFFICIENT_RESOURCES; + HANDLE PartitionHandle;
- /* Open the root partition - Remove any trailing backslash if needed */ + /* + * Open the root partition from which the bootcode (MBR, VBR) parameters + * will be obtained; this is also where we will write the updated bootcode. + * Remove any trailing backslash if needed. + */ RtlInitUnicodeString(&Name, RootPath); TrimTrailingPathSeparators_UStr(&Name);
@@ -743,132 +575,164 @@ InstallMbrBootCodeToDiskHelper( NULL, NULL);
- Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, + Status = NtOpenFile(&PartitionHandle, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT); + FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); return Status; - }
- /* Read current boot sector into buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - OrigBootSector, - sizeof(PARTITION_SECTOR), - &FileOffset, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return Status; - } + /* Install the bootcode (MBR, VBR) */ + Status = InstallBootCode(SrcPath, PartitionHandle, PartitionHandle);
- /* Allocate buffer for new bootsector */ - NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTITION_SECTOR)); - if (NewBootSector == NULL) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return STATUS_INSUFFICIENT_RESOURCES; - } + /* Close the partition */ + NtClose(PartitionHandle); + + return Status; +} + +static +NTSTATUS +InstallBootCodeToFile( + IN PCWSTR SrcPath, + IN PCWSTR DstPath, + IN PCWSTR RootPath, + IN PFS_INSTALL_BOOTCODE InstallBootCode) +{ + NTSTATUS Status; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE PartitionHandle, FileHandle; + + /* + * Open the root partition from which the bootcode (MBR, VBR) + * parameters will be obtained. + * + * FIXME? It might be possible that we need to also open it for writing + * access in case we really need to still write the second portion of + * the boot sector ???? + * + * Remove any trailing backslash if needed. + */ + RtlInitUnicodeString(&Name, RootPath); + TrimTrailingPathSeparators_UStr(&Name);
- /* Read new bootsector from SrcPath */ - RtlInitUnicodeString(&Name, SrcPath); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL);
- Status = NtOpenFile(&FileHandle, + Status = NtOpenFile(&PartitionHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); return Status; - }
- Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - sizeof(PARTITION_SECTOR), - NULL, - NULL); - NtClose(FileHandle); + /* Open or create the file where the new bootsector will be saved */ + RtlInitUnicodeString(&Name, DstPath); + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtCreateFile(&FileHandle, + GENERIC_WRITE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_SUPERSEDE, // FILE_OVERWRITE_IF + FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, + NULL, + 0); if (!NT_SUCCESS(Status)) { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); + DPRINT1("NtCreateFile() failed (Status %lx)\n", Status); + NtClose(PartitionHandle); return Status; }
- /* - * Copy the disk signature, the reserved fields and - * the partition table from the old MBR to the new one. - */ - RtlCopyMemory(&NewBootSector->Signature, - &OrigBootSector->Signature, - sizeof(PARTITION_SECTOR) - offsetof(PARTITION_SECTOR, Signature) - /* Length of partition table */); + /* Install the bootcode (MBR, VBR) */ + Status = InstallBootCode(SrcPath, FileHandle, PartitionHandle);
- /* Free the original boot sector */ - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + /* Close the file and the partition */ + NtClose(FileHandle); + NtClose(PartitionHandle);
- /* Open the root partition - Remove any trailing backslash if needed */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); + return Status; +}
- InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL);
- Status = NtOpenFile(&FileHandle, - GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); +static +NTSTATUS +InstallMbrBootCode( + IN PCWSTR SrcPath, // MBR source file (on the installation medium) + IN HANDLE DstPath, // Where to save the bootsector built from the source + disk information + IN HANDLE DiskHandle) // Disk holding the (old) MBR information +{ + NTSTATUS Status; + UNICODE_STRING Name; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER FileOffset; + BOOTCODE OrigBootSector = {0}; + BOOTCODE NewBootSector = {0}; + +C_ASSERT(sizeof(PARTITION_SECTOR) == SECTORSIZE); + + /* Allocate and read the current original MBR bootsector */ + Status = ReadBootCodeByHandle(&OrigBootSector, + DiskHandle, + sizeof(PARTITION_SECTOR)); + if (!NT_SUCCESS(Status)) + return Status; + + /* Allocate and read the new bootsector from SrcPath */ + RtlInitUnicodeString(&Name, SrcPath); + Status = ReadBootCodeFromFile(&NewBootSector, + &Name, + sizeof(PARTITION_SECTOR)); if (!NT_SUCCESS(Status)) { - DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); + FreeBootCode(&OrigBootSector); return Status; }
- /* Write new bootsector to RootPath */ + /* + * Copy the disk signature, the reserved fields and + * the partition table from the old MBR to the new one. + */ + RtlCopyMemory(&((PPARTITION_SECTOR)NewBootSector.BootCode)->Signature, + &((PPARTITION_SECTOR)OrigBootSector.BootCode)->Signature, + sizeof(PARTITION_SECTOR) - + FIELD_OFFSET(PARTITION_SECTOR, Signature) + /* Length of partition table */); + + /* Free the original bootsector */ + FreeBootCode(&OrigBootSector); + + /* Write the new bootsector to DstPath */ FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(FileHandle, + Status = NtWriteFile(DstPath, NULL, NULL, NULL, &IoStatusBlock, - NewBootSector, - sizeof(PARTITION_SECTOR), + NewBootSector.BootCode, + NewBootSector.Length, &FileOffset, NULL); - NtClose(FileHandle);
- /* Free the new boot sector */ - RtlFreeHeap(ProcessHeap, 0, NewBootSector); + /* Free the new bootsector */ + FreeBootCode(&NewBootSector);
return Status; } @@ -917,1023 +781,65 @@ InstallMbrBootCodeToDisk( DPRINT1("Install MBR bootcode: %S ==> %S\n", SourceMbrPathBuffer, DestinationDevicePathBuffer);
- return InstallMbrBootCodeToDiskHelper(SourceMbrPathBuffer, - DestinationDevicePathBuffer); + /* Install the MBR */ + return InstallBootCodeToDisk(SourceMbrPathBuffer, + DestinationDevicePathBuffer, + InstallMbrBootCode); }
static NTSTATUS -InstallFat12BootCodeToFloppy( - IN PCWSTR SrcPath, - IN PCWSTR RootPath) +InstallFatBootcodeToPartition( + IN PUNICODE_STRING SystemRootPath, + IN PUNICODE_STRING SourceRootPath, + IN PUNICODE_STRING DestinationArcPath, + IN UCHAR PartitionType) { NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - LARGE_INTEGER FileOffset; - PFAT_BOOTSECTOR OrigBootSector; - PFAT_BOOTSECTOR NewBootSector; - - /* Allocate buffer for original bootsector */ - OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); - if (OrigBootSector == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - /* Open the root partition - Remove any trailing backslash if needed */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); + BOOLEAN DoesFreeLdrExist; + WCHAR SrcPath[MAX_PATH]; + WCHAR DstPath[MAX_PATH];
- InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); + /* FAT or FAT32 partition */ + DPRINT("System path: '%wZ'\n", SystemRootPath);
- Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return Status; - } + /* Copy FreeLoader to the system partition, always overwriting the older version */ + CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\freeldr.sys"); + CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
- /* Read current boot sector into buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - OrigBootSector, - SECTORSIZE, - &FileOffset, - NULL); - NtClose(FileHandle); + DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); + Status = SetupCopyFile(SrcPath, DstPath, FALSE); if (!NT_SUCCESS(Status)) { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); return Status; }
- /* Allocate buffer for new bootsector */ - NewBootSector = RtlAllocateHeap(ProcessHeap, - 0, - SECTORSIZE); - if (NewBootSector == NULL) + /* Prepare for possibly updating 'freeldr.ini' */ + DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); + if (DoesFreeLdrExist) { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return STATUS_INSUFFICIENT_RESOURCES; + /* Update existing 'freeldr.ini' */ + DPRINT1("Update existing 'freeldr.ini'\n"); + Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); + if (!NT_SUCCESS(Status)) + { + DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); + return Status; + } }
- /* Read new bootsector from SrcPath */ - RtlInitUnicodeString(&Name, SrcPath); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); + /* Check for NT and other bootloaders */
- Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) + // FIXME: Check for Vista+ bootloader! + /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/ + /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/ + if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE || + DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE) { - 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->OemName, - &OrigBootSector->OemName, - FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) - - FIELD_OFFSET(FAT_BOOTSECTOR, OemName)); - - /* Free the original boot sector */ - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - - /* Open the root partition - Remove any trailing backslash if needed */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - /* Write new bootsector to RootPath */ - FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - NtClose(FileHandle); - - /* Free the new boot sector */ - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - - return Status; -} - -static -NTSTATUS -InstallFat16BootCode( - IN PCWSTR SrcPath, // FAT16 bootsector source file (on the installation medium) - IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information - IN HANDLE RootPartition) // Partition holding the (old) FAT16 information -{ - NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - LARGE_INTEGER FileOffset; - PFAT_BOOTSECTOR OrigBootSector; - PFAT_BOOTSECTOR NewBootSector; - - /* Allocate a buffer for the original bootsector */ - OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); - if (OrigBootSector == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - /* Read the current partition boot sector into the buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(RootPartition, - NULL, - NULL, - NULL, - &IoStatusBlock, - OrigBootSector, - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return Status; - } - - /* Allocate a buffer for the new bootsector */ - NewBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); - if (NewBootSector == NULL) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Read the new bootsector from SrcPath */ - RtlInitUnicodeString(&Name, SrcPath); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - /* Adjust the bootsector (copy a part of the FAT16 BPB) */ - memcpy(&NewBootSector->OemName, - &OrigBootSector->OemName, - FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) - - FIELD_OFFSET(FAT_BOOTSECTOR, OemName)); - - /* Free the original boot sector */ - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - - /* Write the new bootsector to DstPath */ - FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(DstPath, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - - /* Free the new boot sector */ - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - - return Status; -} - -static -NTSTATUS -InstallFat16BootCodeToFile( - IN PCWSTR SrcPath, - IN PCWSTR DstPath, - IN PCWSTR RootPath) -{ - NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE PartitionHandle, FileHandle; - - /* - * Open the root partition from which the boot sector - * parameters will be obtained. - * Remove any trailing backslash if needed. - */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&PartitionHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); - if (!NT_SUCCESS(Status)) - return Status; - - /* Open or create the file where the new bootsector will be saved */ - RtlInitUnicodeString(&Name, DstPath); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtCreateFile(&FileHandle, - GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - 0, - FILE_OVERWRITE_IF, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtCreateFile() failed (Status %lx)\n", Status); - NtClose(PartitionHandle); - return Status; - } - - /* Install the FAT16 boot sector */ - Status = InstallFat16BootCode(SrcPath, FileHandle, PartitionHandle); - - /* Close the file and the partition */ - NtClose(FileHandle); - NtClose(PartitionHandle); - - return Status; -} - -static -NTSTATUS -InstallFat16BootCodeToDisk( - IN PCWSTR SrcPath, - IN PCWSTR RootPath) -{ - NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE PartitionHandle; - - /* - * Open the root partition from which the boot sector parameters will be - * obtained; this is also where we will write the updated boot sector. - * Remove any trailing backslash if needed. - */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&PartitionHandle, - GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); - if (!NT_SUCCESS(Status)) - return Status; - - /* Install the FAT16 boot sector */ - Status = InstallFat16BootCode(SrcPath, PartitionHandle, PartitionHandle); - - /* Close the partition */ - NtClose(PartitionHandle); - - return Status; -} - - -static -NTSTATUS -InstallFat32BootCode( - IN PCWSTR SrcPath, // FAT32 bootsector source file (on the installation medium) - IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information - IN HANDLE RootPartition) // Partition holding the (old) FAT32 information -{ - NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - LARGE_INTEGER FileOffset; - PFAT32_BOOTSECTOR OrigBootSector; - PFAT32_BOOTSECTOR NewBootSector; - USHORT BackupBootSector; - - /* Allocate a buffer for the original bootsector */ - OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); - if (OrigBootSector == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - /* Read the current boot sector into the buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(RootPartition, - NULL, - NULL, - NULL, - &IoStatusBlock, - OrigBootSector, - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return Status; - } - - /* Allocate a buffer for the new bootsector (2 sectors) */ - NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE); - if (NewBootSector == NULL) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Read the new bootsector from SrcPath */ - RtlInitUnicodeString(&Name, SrcPath); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - 2 * SECTORSIZE, - &FileOffset, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - /* Adjust the bootsector (copy a part of the FAT32 BPB) */ - memcpy(&NewBootSector->OemName, - &OrigBootSector->OemName, - FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) - - FIELD_OFFSET(FAT32_BOOTSECTOR, OemName)); - - /* - * We know we copy the boot code to a file only when DstPath != RootPartition, - * otherwise the boot code is copied to the specified root partition. - */ - if (DstPath != RootPartition) - { - /* Copy to a file: Disable the backup boot sector */ - NewBootSector->BackupBootSector = 0; - } - else - { - /* Copy to a disk: Get the location of the backup boot sector */ - BackupBootSector = OrigBootSector->BackupBootSector; - } - - /* Free the original boot sector */ - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - - /* Write the first sector of the new bootcode to DstPath sector 0 */ - FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(DstPath, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - if (DstPath == RootPartition) - { - /* Copy to a disk: Write the backup boot sector */ - if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF)) - { - FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE); - Status = NtWriteFile(DstPath, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - } - } - - /* Write the second sector of the new bootcode to boot disk sector 14 */ - // FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE); - FileOffset.QuadPart = 14 * SECTORSIZE; - Status = NtWriteFile(DstPath, // or really RootPartition ??? - NULL, - NULL, - NULL, - &IoStatusBlock, - ((PUCHAR)NewBootSector + SECTORSIZE), - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - } - - /* Free the new boot sector */ - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - - return Status; -} - -static -NTSTATUS -InstallFat32BootCodeToFile( - IN PCWSTR SrcPath, - IN PCWSTR DstPath, - IN PCWSTR RootPath) -{ - NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE PartitionHandle, FileHandle; - - /* - * Open the root partition from which the boot sector parameters - * will be obtained. - * FIXME? It might be possible that we need to also open it for writing - * access in case we really need to still write the second portion of - * the boot sector ???? - * - * Remove any trailing backslash if needed. - */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&PartitionHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); - if (!NT_SUCCESS(Status)) - return Status; - - /* Open or create the file where (the first sector of ????) the new bootsector will be saved */ - RtlInitUnicodeString(&Name, DstPath); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtCreateFile(&FileHandle, - GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - 0, - FILE_SUPERSEDE, // FILE_OVERWRITE_IF, <- is used for FAT16 - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtCreateFile() failed (Status %lx)\n", Status); - NtClose(PartitionHandle); - return Status; - } - - /* Install the FAT32 boot sector */ - Status = InstallFat32BootCode(SrcPath, FileHandle, PartitionHandle); - - /* Close the file and the partition */ - NtClose(FileHandle); - NtClose(PartitionHandle); - - return Status; -} - -static -NTSTATUS -InstallFat32BootCodeToDisk( - IN PCWSTR SrcPath, - IN PCWSTR RootPath) -{ - NTSTATUS Status; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE PartitionHandle; - - /* - * Open the root partition from which the boot sector parameters will be - * obtained; this is also where we will write the updated boot sector. - * Remove any trailing backslash if needed. - */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&PartitionHandle, - GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); - if (!NT_SUCCESS(Status)) - return Status; - - /* Install the FAT32 boot sector */ - Status = InstallFat32BootCode(SrcPath, PartitionHandle, PartitionHandle); - - /* Close the partition */ - NtClose(PartitionHandle); - - return Status; -} - -static -NTSTATUS -InstallBtrfsBootCodeToDisk( - IN PCWSTR SrcPath, - IN PCWSTR RootPath) -{ - NTSTATUS Status; - NTSTATUS LockStatus; - UNICODE_STRING Name; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - LARGE_INTEGER FileOffset; -// PEXT2_BOOTSECTOR OrigBootSector; - PBTRFS_BOOTSECTOR NewBootSector; - // USHORT BackupBootSector; - PARTITION_INFORMATION_EX PartInfo; - -#if 0 - /* Allocate buffer for original bootsector */ - OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE); - if (OrigBootSector == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - /* Open the root partition - Remove any trailing backslash if needed */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return Status; - } - - /* Read current boot sector into buffer */ - FileOffset.QuadPart = 0ULL; - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - OrigBootSector, - SECTORSIZE, - &FileOffset, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return Status; - } -#endif - - /* Allocate buffer for new bootsector */ - NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(BTRFS_BOOTSECTOR)); - 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, - GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - // RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - sizeof(BTRFS_BOOTSECTOR), - NULL, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - // RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - -#if 0 - /* Adjust bootsector (copy a part of the FAT32 BPB) */ - memcpy(&NewBootSector->OemName, - &OrigBootSector->OemName, - FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) - - FIELD_OFFSET(FAT32_BOOTSECTOR, OemName)); - - /* Get the location of the backup boot sector */ - BackupBootSector = OrigBootSector->BackupBootSector; - - /* Free the original boot sector */ - // RtlFreeHeap(ProcessHeap, 0, OrigBootSector); -#endif - - /* Open the root partition - Remove any trailing backslash if needed */ - RtlInitUnicodeString(&Name, RootPath); - TrimTrailingPathSeparators_UStr(&Name); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return Status; - } - - /* - * The BTRFS driver requires the volume to be locked in order to modify - * the first sectors of the partition, even though they are outside the - * file-system space / in the reserved area (they are situated before - * the super-block at 0x1000) and is in principle allowed by the NT - * storage stack. - * So we lock here in order to write the bootsector at sector 0. - * If locking fails, we ignore and continue nonetheless. - */ - LockStatus = NtFsControlFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - FSCTL_LOCK_VOLUME, - NULL, - 0, - NULL, - 0); - if (!NT_SUCCESS(LockStatus)) - { - DPRINT1("WARNING: Failed to lock BTRFS volume for writing bootsector! Operations may fail! (Status 0x%lx)\n", LockStatus); - } - - /* Obtaining partition info and writing it to bootsector */ - Status = NtDeviceIoControlFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - IOCTL_DISK_GET_PARTITION_INFO_EX, - NULL, - 0, - &PartInfo, - sizeof(PartInfo)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status); - goto Quit; - } - - /* Write new bootsector to RootPath */ - - NewBootSector->PartitionStartLBA = PartInfo.StartingOffset.QuadPart / SECTORSIZE; - - /* Write sector 0 */ - FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - sizeof(BTRFS_BOOTSECTOR), - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - goto Quit; - } - -#if 0 - /* 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); - goto Quit; - } - } - - /* Write sector 14 */ - FileOffset.QuadPart = 14 * SECTORSIZE; - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - ((PUCHAR)NewBootSector + SECTORSIZE), - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - } -#endif - -Quit: - /* Unlock the volume */ - LockStatus = NtFsControlFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - FSCTL_UNLOCK_VOLUME, - NULL, - 0, - NULL, - 0); - if (!NT_SUCCESS(LockStatus)) - { - DPRINT1("Failed to unlock BTRFS volume (Status 0x%lx)\n", LockStatus); - } - - /* Close the volume */ - NtClose(FileHandle); - - /* Free the new boot sector */ - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - - return Status; -} - - -static -NTSTATUS -InstallFatBootcodeToPartition( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath, - IN UCHAR PartitionType) -{ - NTSTATUS Status; - BOOLEAN DoesFreeLdrExist; - WCHAR SrcPath[MAX_PATH]; - WCHAR DstPath[MAX_PATH]; - - /* FAT or FAT32 partition */ - DPRINT("System path: '%wZ'\n", SystemRootPath); - - /* Copy FreeLoader to the system partition, always overwriting the older version */ - CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\freeldr.sys"); - CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); - - DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); - Status = SetupCopyFile(SrcPath, DstPath, FALSE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); - return Status; - } - - /* Prepare for possibly updating 'freeldr.ini' */ - DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); - if (DoesFreeLdrExist) - { - /* Update existing 'freeldr.ini' */ - DPRINT1("Update existing 'freeldr.ini'\n"); - Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); - if (!NT_SUCCESS(Status)) - { - DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); - return Status; - } - } - - /* Check for NT and other bootloaders */ - - // FIXME: Check for Vista+ bootloader! - /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/ - /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/ - if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE || - DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE) - { - /* Search root directory for 'NTLDR' and 'BOOT.INI' */ - DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n"); + /* Search root directory for 'NTLDR' and 'BOOT.INI' */ + DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
/* Create or update 'freeldr.ini' */ if (DoesFreeLdrExist == FALSE) @@ -1957,11 +863,12 @@ InstallFatBootcodeToPartition( CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\fat32.bin");
DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath); - Status = InstallFat32BootCodeToFile(SrcPath, DstPath, - SystemRootPath->Buffer); + Status = InstallBootCodeToFile(SrcPath, DstPath, + SystemRootPath->Buffer, + InstallFat32BootCode); if (!NT_SUCCESS(Status)) { - DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status); + DPRINT1("InstallBootCodeToFile(FAT32) failed (Status %lx)\n", Status); return Status; } } @@ -1970,12 +877,13 @@ InstallFatBootcodeToPartition( /* Install FAT16 bootcode */ CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\fat.bin");
- DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath); - Status = InstallFat16BootCodeToFile(SrcPath, DstPath, - SystemRootPath->Buffer); + DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, DstPath); + Status = InstallBootCodeToFile(SrcPath, DstPath, + SystemRootPath->Buffer, + InstallFat16BootCode); if (!NT_SUCCESS(Status)) { - DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status); + DPRINT1("InstallBootCodeToFile(FAT16) failed (Status %lx)\n", Status); return Status; } } @@ -2169,10 +1077,10 @@ InstallFatBootcodeToPartition( CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\fat32.bin");
DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); - Status = InstallFat32BootCodeToDisk(SrcPath, SystemRootPath->Buffer); + Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat32BootCode); if (!NT_SUCCESS(Status)) { - DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status); + DPRINT1("InstallBootCodeToDisk(FAT32) failed (Status %lx)\n", Status); return Status; } } @@ -2182,10 +1090,10 @@ InstallFatBootcodeToPartition( CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\fat.bin");
DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); - Status = InstallFat16BootCodeToDisk(SrcPath, SystemRootPath->Buffer); + Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat16BootCode); if (!NT_SUCCESS(Status)) { - DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status); + DPRINT1("InstallBootCodeToDisk(FAT16) failed (Status %lx)\n", Status); return Status; } } @@ -2200,8 +1108,7 @@ NTSTATUS InstallBtrfsBootcodeToPartition( IN PUNICODE_STRING SystemRootPath, IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath, - IN UCHAR PartitionType) + IN PUNICODE_STRING DestinationArcPath) { NTSTATUS Status; BOOLEAN DoesFreeLdrExist; @@ -2266,7 +1173,7 @@ InstallBtrfsBootcodeToPartition( CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); - Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(BTRFS_BOOTSECTOR)); + Status = SaveBootSector(SystemRootPath->Buffer, DstPath, BTRFS_BOOTSECTOR_SIZE); if (!NT_SUCCESS(Status)) { DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); @@ -2284,18 +1191,15 @@ InstallBtrfsBootcodeToPartition( }
/* Install new bootsector on the disk */ - // if (PartitionType == PARTITION_EXT2) - { - /* Install BTRFS bootcode */ - CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\btrfs.bin"); + /* Install BTRFS bootcode */ + CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\btrfs.bin");
- DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); - Status = InstallBtrfsBootCodeToDisk(SrcPath, SystemRootPath->Buffer); - if (!NT_SUCCESS(Status)) - { - DPRINT1("InstallBtrfsBootCodeToDisk() failed (Status %lx)\n", Status); - return Status; - } + DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); + Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallBtrfsBootCode); + if (!NT_SUCCESS(Status)) + { + DPRINT1("InstallBootCodeToDisk(BTRFS) failed (Status %lx)\n", Status); + return Status; } }
@@ -2329,8 +1233,7 @@ InstallVBRToPartition( { return InstallBtrfsBootcodeToPartition(SystemRootPath, SourceRootPath, - DestinationArcPath, - PartitionType); + DestinationArcPath); }
case PARTITION_IFS: @@ -2405,11 +1308,11 @@ InstallFatBootcodeToFloppy( CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\loader\fat.bin"); CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice);
- DPRINT("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath); - Status = InstallFat12BootCodeToFloppy(SrcPath, DstPath); + DPRINT("Install FAT12 bootcode: %S ==> %S\n", SrcPath, DstPath); + Status = InstallBootCodeToDisk(SrcPath, DstPath, InstallFat12BootCode); if (!NT_SUCCESS(Status)) { - DPRINT1("InstallFat12BootCodeToFloppy() failed (Status %lx)\n", Status); + DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status %lx)\n", Status); return Status; }
diff --git a/base/setup/lib/fsutil.c b/base/setup/lib/fsutil.c index 2abe8e4c7a8..9bd0aee4c2a 100644 --- a/base/setup/lib/fsutil.c +++ b/base/setup/lib/fsutil.c @@ -3,7 +3,7 @@ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Filesystem support functions * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net) - * Copyright 2017-2019 Hermes Belusca-Maito + * Copyright 2017-2020 Hermes Belusca-Maito */
// @@ -18,6 +18,7 @@
#include "partlist.h" #include "fsrec.h" +#include "bootcode.h" #include "fsutil.h"
#include <fslib/vfatlib.h> @@ -29,6 +30,92 @@ #include <debug.h>
+/* TYPEDEFS *****************************************************************/ + +#include <pshpack1.h> +typedef struct _FAT_BOOTSECTOR +{ + UCHAR JumpBoot[3]; // Jump instruction to boot code + CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes + USHORT BytesPerSector; // Bytes per sector + UCHAR SectorsPerCluster; // Number of sectors in a cluster + USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector) + UCHAR NumberOfFats; // Number of FAT tables + USHORT RootDirEntries; // Number of root directory entries (fat12/16) + USHORT TotalSectors; // Number of total sectors on the drive, 16-bit + UCHAR MediaDescriptor; // Media descriptor byte + USHORT SectorsPerFat; // Sectors per FAT table (fat12/16) + USHORT SectorsPerTrack; // Number of sectors in a track + USHORT NumberOfHeads; // Number of heads on the disk + ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) + ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume + UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80) + UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0. + UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present. + ULONG VolumeSerialNumber; // Volume serial number + CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory + CHAR FileSystemType[8]; // One of the strings "FAT12 ", "FAT16 ", or "FAT " + + UCHAR BootCodeAndData[448]; // The remainder of the boot sector + + USHORT BootSectorMagic; // 0xAA55 + +} FAT_BOOTSECTOR, *PFAT_BOOTSECTOR; +C_ASSERT(sizeof(FAT_BOOTSECTOR) == FAT_BOOTSECTOR_SIZE); + +typedef struct _FAT32_BOOTSECTOR +{ + UCHAR JumpBoot[3]; // Jump instruction to boot code + CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes + USHORT BytesPerSector; // Bytes per sector + UCHAR SectorsPerCluster; // Number of sectors in a cluster + USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector) + UCHAR NumberOfFats; // Number of FAT tables + USHORT RootDirEntries; // Number of root directory entries (fat12/16) + USHORT TotalSectors; // Number of total sectors on the drive, 16-bit + UCHAR MediaDescriptor; // Media descriptor byte + USHORT SectorsPerFat; // Sectors per FAT table (fat12/16) + USHORT SectorsPerTrack; // Number of sectors in a track + USHORT NumberOfHeads; // Number of heads on the disk + ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) + ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume + ULONG SectorsPerFatBig; // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0 + USHORT ExtendedFlags; // Extended flags (fat32) + USHORT FileSystemVersion; // File system version (fat32) + ULONG RootDirStartCluster; // Starting cluster of the root directory (fat32) + USHORT FsInfo; // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1. + USHORT BackupBootSector; // If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6. + UCHAR Reserved[12]; // Reserved for future expansion + UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80) + UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0. + UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present. + ULONG VolumeSerialNumber; // Volume serial number + CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory + CHAR FileSystemType[8]; // Always set to the string "FAT32 " + + UCHAR BootCodeAndData[420]; // The remainder of the boot sector + + USHORT BootSectorMagic; // 0xAA55 + +} FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR; +C_ASSERT(sizeof(FAT32_BOOTSECTOR) == FAT32_BOOTSECTOR_SIZE); + +typedef struct _BTRFS_BOOTSECTOR +{ + UCHAR JumpBoot[3]; + UCHAR ChunkMapSize; + UCHAR BootDrive; + ULONGLONG PartitionStartLBA; + UCHAR Fill[1521]; // 1536 - 15 + USHORT BootSectorMagic; +} BTRFS_BOOTSECTOR, *PBTRFS_BOOTSECTOR; +C_ASSERT(sizeof(BTRFS_BOOTSECTOR) == BTRFS_BOOTSECTOR_SIZE); + +// TODO: Add more bootsector structures! + +#include <poppack.h> + + /* LOCALS *******************************************************************/
/** IFS_PROVIDER **/ @@ -238,6 +325,297 @@ FormatFileSystem( }
+// +// Bootsector routines +// + +NTSTATUS +InstallFat1216BootCode( + IN PCWSTR SrcPath, // FAT12/16 bootsector source file (on the installation medium) + IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information + IN HANDLE RootPartition) // Partition holding the (old) FAT12/16 information +{ + NTSTATUS Status; + UNICODE_STRING Name; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER FileOffset; + BOOTCODE OrigBootSector = {0}; + BOOTCODE NewBootSector = {0}; + + /* Allocate and read the current original partition bootsector */ + Status = ReadBootCodeByHandle(&OrigBootSector, + RootPartition, + FAT_BOOTSECTOR_SIZE); + if (!NT_SUCCESS(Status)) + return Status; + + /* Allocate and read the new bootsector from SrcPath */ + RtlInitUnicodeString(&Name, SrcPath); + Status = ReadBootCodeFromFile(&NewBootSector, + &Name, + FAT_BOOTSECTOR_SIZE); + if (!NT_SUCCESS(Status)) + { + FreeBootCode(&OrigBootSector); + return Status; + } + + /* Adjust the bootsector (copy a part of the FAT12/16 BPB) */ + RtlCopyMemory(&((PFAT_BOOTSECTOR)NewBootSector.BootCode)->OemName, + &((PFAT_BOOTSECTOR)OrigBootSector.BootCode)->OemName, + FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) - + FIELD_OFFSET(FAT_BOOTSECTOR, OemName)); + + /* Free the original bootsector */ + FreeBootCode(&OrigBootSector); + + /* Write the new bootsector to DstPath */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(DstPath, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector.BootCode, + NewBootSector.Length, + &FileOffset, + NULL); + + /* Free the new bootsector */ + FreeBootCode(&NewBootSector); + + return Status; +} + +NTSTATUS +InstallFat32BootCode( + IN PCWSTR SrcPath, // FAT32 bootsector source file (on the installation medium) + IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information + IN HANDLE RootPartition) // Partition holding the (old) FAT32 information +{ + NTSTATUS Status; + UNICODE_STRING Name; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER FileOffset; + USHORT BackupBootSector = 0; + BOOTCODE OrigBootSector = {0}; + BOOTCODE NewBootSector = {0}; + + /* Allocate and read the current original partition bootsector */ + Status = ReadBootCodeByHandle(&OrigBootSector, + RootPartition, + FAT32_BOOTSECTOR_SIZE); + if (!NT_SUCCESS(Status)) + return Status; + + /* Allocate and read the new bootsector (2 sectors) from SrcPath */ + RtlInitUnicodeString(&Name, SrcPath); + Status = ReadBootCodeFromFile(&NewBootSector, + &Name, + 2 * FAT32_BOOTSECTOR_SIZE); + if (!NT_SUCCESS(Status)) + { + FreeBootCode(&OrigBootSector); + return Status; + } + + /* Adjust the bootsector (copy a part of the FAT32 BPB) */ + RtlCopyMemory(&((PFAT32_BOOTSECTOR)NewBootSector.BootCode)->OemName, + &((PFAT32_BOOTSECTOR)OrigBootSector.BootCode)->OemName, + FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) - + FIELD_OFFSET(FAT32_BOOTSECTOR, OemName)); + + /* + * We know we copy the boot code to a file only when DstPath != RootPartition, + * otherwise the boot code is copied to the specified root partition. + */ + if (DstPath != RootPartition) + { + /* Copy to a file: Disable the backup bootsector */ + ((PFAT32_BOOTSECTOR)NewBootSector.BootCode)->BackupBootSector = 0; + } + else + { + /* Copy to a disk: Get the location of the backup bootsector */ + BackupBootSector = ((PFAT32_BOOTSECTOR)OrigBootSector.BootCode)->BackupBootSector; + } + + /* Free the original bootsector */ + FreeBootCode(&OrigBootSector); + + /* Write the first sector of the new bootcode to DstPath sector 0 */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(DstPath, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector.BootCode, + FAT32_BOOTSECTOR_SIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + FreeBootCode(&NewBootSector); + return Status; + } + + if (DstPath == RootPartition) + { + /* Copy to a disk: Write the backup bootsector */ + if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF)) + { + FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * FAT32_BOOTSECTOR_SIZE); + Status = NtWriteFile(DstPath, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector.BootCode, + FAT32_BOOTSECTOR_SIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + FreeBootCode(&NewBootSector); + return Status; + } + } + } + + /* Write the second sector of the new bootcode to boot disk sector 14 */ + // FileOffset.QuadPart = (ULONGLONG)(14 * FAT32_BOOTSECTOR_SIZE); + FileOffset.QuadPart = 14 * FAT32_BOOTSECTOR_SIZE; + Status = NtWriteFile(DstPath, // or really RootPartition ??? + NULL, + NULL, + NULL, + &IoStatusBlock, + ((PUCHAR)NewBootSector.BootCode + FAT32_BOOTSECTOR_SIZE), + FAT32_BOOTSECTOR_SIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + } + + /* Free the new bootsector */ + FreeBootCode(&NewBootSector); + + return Status; +} + +NTSTATUS +InstallBtrfsBootCode( + IN PCWSTR SrcPath, // BTRFS bootsector source file (on the installation medium) + IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information + IN HANDLE RootPartition) // Partition holding the (old) BTRFS information +{ + NTSTATUS Status; + NTSTATUS LockStatus; + UNICODE_STRING Name; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER FileOffset; + PARTITION_INFORMATION_EX PartInfo; + BOOTCODE NewBootSector = {0}; + + /* Allocate and read the new bootsector from SrcPath */ + RtlInitUnicodeString(&Name, SrcPath); + Status = ReadBootCodeFromFile(&NewBootSector, + &Name, + BTRFS_BOOTSECTOR_SIZE); + if (!NT_SUCCESS(Status)) + return Status; + + /* + * The BTRFS driver requires the volume to be locked in order to modify + * the first sectors of the partition, even though they are outside the + * file-system space / in the reserved area (they are situated before + * the super-block at 0x1000) and is in principle allowed by the NT + * storage stack. + * So we lock here in order to write the bootsector at sector 0. + * If locking fails, we ignore and continue nonetheless. + */ + LockStatus = NtFsControlFile(DstPath, + NULL, + NULL, + NULL, + &IoStatusBlock, + FSCTL_LOCK_VOLUME, + NULL, + 0, + NULL, + 0); + if (!NT_SUCCESS(LockStatus)) + { + DPRINT1("WARNING: Failed to lock BTRFS volume for writing bootsector! Operations may fail! (Status 0x%lx)\n", LockStatus); + } + + /* Obtain partition info and write it to the bootsector */ + Status = NtDeviceIoControlFile(RootPartition, + NULL, + NULL, + NULL, + &IoStatusBlock, + IOCTL_DISK_GET_PARTITION_INFO_EX, + NULL, + 0, + &PartInfo, + sizeof(PartInfo)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status); + goto Quit; + } + + /* Write new bootsector to RootPath */ + ((PBTRFS_BOOTSECTOR)NewBootSector.BootCode)->PartitionStartLBA = + PartInfo.StartingOffset.QuadPart / SECTORSIZE; + + /* Write sector 0 */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(DstPath, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector.BootCode, + NewBootSector.Length, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + goto Quit; + } + +Quit: + /* Unlock the volume */ + LockStatus = NtFsControlFile(DstPath, + NULL, + NULL, + NULL, + &IoStatusBlock, + FSCTL_UNLOCK_VOLUME, + NULL, + 0, + NULL, + 0); + if (!NT_SUCCESS(LockStatus)) + { + DPRINT1("Failed to unlock BTRFS volume (Status 0x%lx)\n", LockStatus); + } + + /* Free the new bootsector */ + FreeBootCode(&NewBootSector); + + return Status; +} + + // // Formatting routines // diff --git a/base/setup/lib/fsutil.h b/base/setup/lib/fsutil.h index dd2fb3e5964..d4518885b9f 100644 --- a/base/setup/lib/fsutil.h +++ b/base/setup/lib/fsutil.h @@ -3,7 +3,7 @@ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Filesystem support functions * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net) - * Copyright 2017-2019 Hermes Belusca-Maito + * Copyright 2017-2020 Hermes Belusca-Maito */
#pragma once @@ -61,6 +61,42 @@ FormatFileSystem( IN PFMIFSCALLBACK Callback);
+// +// Bootsector routines +// + +#define FAT_BOOTSECTOR_SIZE (1 * SECTORSIZE) +#define FAT32_BOOTSECTOR_SIZE (1 * SECTORSIZE) // Counts only the primary sector. +#define BTRFS_BOOTSECTOR_SIZE (3 * SECTORSIZE) + +typedef NTSTATUS +(/*NTAPI*/ *PFS_INSTALL_BOOTCODE)( + IN PCWSTR SrcPath, // Bootsector source file (on the installation medium) + IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information + IN HANDLE RootPartition); // Partition holding the (old) bootsector data information + +NTSTATUS +InstallFat1216BootCode( + IN PCWSTR SrcPath, + IN HANDLE DstPath, + IN HANDLE RootPartition); + +#define InstallFat12BootCode InstallFat1216BootCode +#define InstallFat16BootCode InstallFat1216BootCode + +NTSTATUS +InstallFat32BootCode( + IN PCWSTR SrcPath, + IN HANDLE DstPath, + IN HANDLE RootPartition); + +NTSTATUS +InstallBtrfsBootCode( + IN PCWSTR SrcPath, + IN HANDLE DstPath, + IN HANDLE RootPartition); + + // // Formatting routines // diff --git a/base/setup/lib/setuplib.h b/base/setup/lib/setuplib.h index 15358f24885..2dcb349f369 100644 --- a/base/setup/lib/setuplib.h +++ b/base/setup/lib/setuplib.h @@ -31,16 +31,17 @@ extern HANDLE ProcessHeap; #include "utils/ntverrsrc.h" // #include "utils/arcname.h" #include "utils/bldrsup.h" -#include "bootsup.h" #include "utils/filesup.h" #include "utils/fsrec.h" -#include "fsutil.h" #include "utils/genlist.h" #include "utils/inicache.h" #include "utils/partlist.h" #include "utils/arcname.h" #include "utils/osdetect.h" #include "utils/regutil.h" +#include "bootcode.h" +#include "fsutil.h" +#include "bootsup.h" #include "registry.h" #include "mui.h" #include "settings.h"