Reactos
at listview 1915 lines 68 kB view raw
1/* 2 * PROJECT: ReactOS Setup Library 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Bootloader support functions 5 * COPYRIGHT: ... 6 * Copyright 2017-2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> 7 */ 8 9/* INCLUDES *****************************************************************/ 10 11#include "precomp.h" 12 13#include <ntddstor.h> // For STORAGE_DEVICE_NUMBER 14 15#include "bldrsup.h" 16#include "devutils.h" 17#include "filesup.h" 18#include "partlist.h" 19#include "bootcode.h" 20#include "fsutil.h" 21 22#include "setuplib.h" 23extern BOOLEAN IsUnattendedSetup; // HACK 24 25#include "bootsup.h" 26 27#define NDEBUG 28#include <debug.h> 29 30/* 31 * BIG FIXME!! 32 * =========== 33 * 34 * bootsup.c can deal with MBR code (actually it'll have at some point 35 * to share or give it to partlist.c, because when we'll support GPT disks, 36 * things will change a bit). 37 * And, bootsup.c can manage initializing / adding boot entries into NTLDR 38 * and FREELDR, and installing the latter, and saving the old MBR / boot 39 * sectors in files. 40 */ 41 42/* FUNCTIONS ****************************************************************/ 43 44static VOID 45TrimTrailingPathSeparators_UStr( 46 IN OUT PUNICODE_STRING UnicodeString) 47{ 48 while (UnicodeString->Length >= sizeof(WCHAR) && 49 UnicodeString->Buffer[UnicodeString->Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 50 { 51 UnicodeString->Length -= sizeof(WCHAR); 52 } 53} 54 55 56static VOID 57CreateFreeLoaderReactOSEntries( 58 IN PVOID BootStoreHandle, 59 IN PCWSTR ArcPath) 60{ 61 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 62 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 63 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 64 BOOT_STORE_OPTIONS BootOptions; 65 66 BootEntry->Version = FreeLdr; 67 BootEntry->BootFilePath = NULL; 68 69 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 70 RtlCopyMemory(Options->Signature, 71 NTOS_OPTIONS_SIGNATURE, 72 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 73 74 Options->OsLoadPath = ArcPath; 75 76 /* ReactOS */ 77 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS"); 78 BootEntry->FriendlyName = L"\"ReactOS\""; 79 Options->OsLoadOptions = L"/FASTDETECT"; 80 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS")); 81 82 /* ReactOS_Debug */ 83 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Debug"); 84 BootEntry->FriendlyName = L"\"ReactOS (Debug)\""; 85 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS"; 86 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Debug")); 87 88#ifdef _WINKD_ 89 /* ReactOS_VBoxDebug */ 90 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_VBoxDebug"); 91 BootEntry->FriendlyName = L"\"ReactOS (VBox Debug)\""; 92 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=VBOX /SOS"; 93 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_VBoxDebug")); 94#endif 95#if DBG 96#ifndef _WINKD_ 97 /* ReactOS_KdSerial */ 98 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial"); 99 BootEntry->FriendlyName = L"\"ReactOS (RosDbg)\""; 100 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /KDSERIAL"; 101 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_KdSerial")); 102#endif 103 104 /* ReactOS_Screen */ 105 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Screen"); 106 BootEntry->FriendlyName = L"\"ReactOS (Screen)\""; 107 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=SCREEN /SOS"; 108 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Screen")); 109 110 /* ReactOS_LogFile */ 111 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_LogFile"); 112 BootEntry->FriendlyName = L"\"ReactOS (Log file)\""; 113 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=FILE /SOS"; 114 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_LogFile")); 115 116 /* ReactOS_Ram */ 117 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Ram"); 118 BootEntry->FriendlyName = L"\"ReactOS (RAM Disk)\""; 119 Options->OsLoadPath = L"ramdisk(0)\\ReactOS"; 120 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /RDPATH=reactos.img /RDIMAGEOFFSET=32256"; 121 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Ram")); 122 123 /* ReactOS_EMS */ 124 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_EMS"); 125 BootEntry->FriendlyName = L"\"ReactOS (Emergency Management Services)\""; 126 Options->OsLoadPath = ArcPath; 127 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /redirect=com2 /redirectbaudrate=115200"; 128 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_EMS")); 129#endif 130 131 132 /* DefaultOS=ReactOS */ 133#if DBG && !defined(_WINKD_) 134 if (IsUnattendedSetup) 135 { 136 BootOptions.NextBootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial"); 137 } 138 else 139#endif 140 { 141#if DBG 142 BootOptions.NextBootEntryKey = MAKESTRKEY(L"ReactOS_Debug"); 143#else 144 BootOptions.NextBootEntryKey = MAKESTRKEY(L"ReactOS"); 145#endif 146 } 147 148#if DBG 149 if (IsUnattendedSetup) 150#endif 151 { 152 /* Timeout=0 for unattended or non debug */ 153 BootOptions.Timeout = 0; 154 } 155#if DBG 156 else 157 { 158 /* Timeout=10 */ 159 BootOptions.Timeout = 10; 160 } 161#endif 162 163 SetBootStoreOptions(BootStoreHandle, &BootOptions, 164 BOOT_OPTIONS_TIMEOUT | BOOT_OPTIONS_NEXT_BOOTENTRY_KEY); 165} 166 167static NTSTATUS 168CreateFreeLoaderIniForReactOS( 169 IN PCWSTR IniPath, 170 IN PCWSTR ArcPath) 171{ 172 NTSTATUS Status; 173 PVOID BootStoreHandle; 174 175 /* Initialize the INI file and create the common FreeLdr sections */ 176 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, 177 BS_CreateAlways /* BS_OpenAlways */, BS_ReadWriteAccess); 178 if (!NT_SUCCESS(Status)) 179 return Status; 180 181 /* Add the ReactOS entries */ 182 CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath); 183 184 /* Close the INI file */ 185 CloseBootStore(BootStoreHandle); 186 return STATUS_SUCCESS; 187} 188 189static NTSTATUS 190CreateFreeLoaderIniForReactOSAndBootSector( 191 IN PCWSTR IniPath, 192 IN PCWSTR ArcPath, 193 IN PCWSTR Section, 194 IN PCWSTR Description, 195 IN PCWSTR BootPath, 196 IN PCWSTR BootSector) 197{ 198 NTSTATUS Status; 199 PVOID BootStoreHandle; 200 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(BOOTSECTOR_OPTIONS)]; 201 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 202 PBOOTSECTOR_OPTIONS Options = (PBOOTSECTOR_OPTIONS)&BootEntry->OsOptions; 203 WCHAR BootPathBuffer[MAX_PATH] = L""; 204 205 /* Since the BootPath given here is in NT format 206 * (not ARC), we need to hack-generate a mapping */ 207 ULONG DiskNumber = 0, PartitionNumber = 0; 208 PCWSTR PathComponent = NULL; 209 210 /* From the NT path, compute the disk, partition and path components */ 211 // NOTE: this function doesn't support stuff like \Device\FloppyX ... 212 if (NtPathToDiskPartComponents(BootPath, &DiskNumber, &PartitionNumber, &PathComponent)) 213 { 214 DPRINT1("BootPath = '%S' points to disk #%d, partition #%d, path '%S'\n", 215 BootPath, DiskNumber, PartitionNumber, PathComponent); 216 217 /* HACK-build a possible ARC path: 218 * Hard disk path: multi(0)disk(0)rdisk(x)partition(y)[\path] */ 219 RtlStringCchPrintfW(BootPathBuffer, _countof(BootPathBuffer), 220 L"multi(0)disk(0)rdisk(%lu)partition(%lu)", 221 DiskNumber, PartitionNumber); 222 if (PathComponent && *PathComponent && 223 (PathComponent[0] != L'\\' || PathComponent[1])) 224 { 225 RtlStringCchCatW(BootPathBuffer, _countof(BootPathBuffer), 226 PathComponent); 227 } 228 } 229 else 230 { 231 PCWSTR Path = BootPath; 232 233 if ((_wcsnicmp(Path, L"\\Device\\Floppy", 14) == 0) && 234 (Path += 14) && iswdigit(*Path)) 235 { 236 DiskNumber = wcstoul(Path, (PWSTR*)&PathComponent, 10); 237 if (PathComponent && *PathComponent && *PathComponent != L'\\') 238 PathComponent = NULL; 239 240 /* HACK-build a possible ARC path: 241 * Floppy disk path: multi(0)disk(0)fdisk(x)[\path] */ 242 RtlStringCchPrintfW(BootPathBuffer, _countof(BootPathBuffer), 243 L"multi(0)disk(0)fdisk(%lu)", DiskNumber); 244 if (PathComponent && *PathComponent && 245 (PathComponent[0] != L'\\' || PathComponent[1])) 246 { 247 RtlStringCchCatW(BootPathBuffer, _countof(BootPathBuffer), 248 PathComponent); 249 } 250 } 251 else 252 { 253 /* HACK: Just keep the unresolved NT path and hope for the best... */ 254 255 /* Remove any trailing backslash if needed */ 256 UNICODE_STRING RootPartition; 257 RtlInitUnicodeString(&RootPartition, BootPath); 258 TrimTrailingPathSeparators_UStr(&RootPartition); 259 260 /* RootPartition is BootPath without counting any trailing 261 * path separator. Because of this, we need to copy the string 262 * in the buffer, instead of just using a pointer to it. */ 263 RtlStringCchPrintfW(BootPathBuffer, _countof(BootPathBuffer), 264 L"%wZ", &RootPartition); 265 266 DPRINT1("Unhandled NT path '%S'\n", BootPath); 267 } 268 } 269 270 /* Initialize the INI file and create the common FreeLdr sections */ 271 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, 272 BS_CreateAlways /* BS_OpenAlways */, BS_ReadWriteAccess); 273 if (!NT_SUCCESS(Status)) 274 return Status; 275 276 /* Add the ReactOS entries */ 277 CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath); 278 279 BootEntry->Version = FreeLdr; 280 BootEntry->BootFilePath = NULL; 281 282 BootEntry->OsOptionsLength = sizeof(BOOTSECTOR_OPTIONS); 283 RtlCopyMemory(Options->Signature, 284 BOOTSECTOR_OPTIONS_SIGNATURE, 285 RTL_FIELD_SIZE(BOOTSECTOR_OPTIONS, Signature)); 286 287 Options->BootPath = BootPathBuffer; 288 Options->FileName = BootSector; 289 290 // BootEntry->BootEntryKey = MAKESTRKEY(Section); 291 BootEntry->FriendlyName = Description; 292 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Section)); 293 294 /* Close the INI file */ 295 CloseBootStore(BootStoreHandle); 296 return STATUS_SUCCESS; 297} 298 299// 300// I think this function can be generalizable as: 301// "find the corresponding 'ReactOS' boot entry in this loader config file 302// (here abstraction comes there), and if none, add a new one". 303// 304 305typedef struct _ENUM_REACTOS_ENTRIES_DATA 306{ 307 ULONG i; 308 BOOLEAN UseExistingEntry; 309 PCWSTR ArcPath; 310 WCHAR SectionName[80]; 311 WCHAR OsName[80]; 312} ENUM_REACTOS_ENTRIES_DATA, *PENUM_REACTOS_ENTRIES_DATA; 313 314// PENUM_BOOT_ENTRIES_ROUTINE 315static NTSTATUS 316NTAPI 317EnumerateReactOSEntries( 318 IN BOOT_STORE_TYPE Type, 319 IN PBOOT_STORE_ENTRY BootEntry, 320 IN PVOID Parameter OPTIONAL) 321{ 322 NTSTATUS Status; 323 PENUM_REACTOS_ENTRIES_DATA Data = (PENUM_REACTOS_ENTRIES_DATA)Parameter; 324 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 325 WCHAR SystemPath[MAX_PATH]; 326 327 /* We have a boot entry */ 328 329 /* Check for supported boot type "Windows2003" */ 330 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) || 331 RtlCompareMemory(&BootEntry->OsOptions /* Signature */, 332 NTOS_OPTIONS_SIGNATURE, 333 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) != 334 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) 335 { 336 /* This is not a ReactOS entry */ 337 // DPRINT(" An installation '%S' of unsupported type '%S'\n", 338 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a"); 339 DPRINT(" An installation '%S' of unsupported type %lu\n", 340 BootEntry->FriendlyName, BootEntry->OsOptionsLength); 341 /* Continue the enumeration */ 342 goto SkipThisEntry; 343 } 344 345 /* BootType is Windows2003, now check OsLoadPath */ 346 if (!Options->OsLoadPath || !*Options->OsLoadPath) 347 { 348 /* Certainly not a ReactOS installation */ 349 DPRINT1(" A Win2k3 install '%S' without an ARC path?!\n", BootEntry->FriendlyName); 350 /* Continue the enumeration */ 351 goto SkipThisEntry; 352 } 353 354 if (_wcsicmp(Options->OsLoadPath, Data->ArcPath) != 0) 355 { 356 /* Not found, retry with a quoted path */ 357 Status = RtlStringCchPrintfW(SystemPath, ARRAYSIZE(SystemPath), L"\"%s\"", Data->ArcPath); 358 if (!NT_SUCCESS(Status) || _wcsicmp(Options->OsLoadPath, SystemPath) != 0) 359 { 360 /* 361 * This entry is a ReactOS entry, but the SystemRoot 362 * does not match the one we are looking for. 363 */ 364 /* Continue the enumeration */ 365 goto SkipThisEntry; 366 } 367 } 368 369 DPRINT(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n", 370 BootEntry->FriendlyName, Options->OsLoadPath); 371 // DPRINT(" Found a Win2k3 install '%S' with ARC path '%S'\n", 372 // BootEntry->FriendlyName, Options->OsLoadPath); 373 374 DPRINT("EnumerateReactOSEntries: OsLoadPath: '%S'\n", Options->OsLoadPath); 375 376 Data->UseExistingEntry = TRUE; 377 RtlStringCchCopyW(Data->OsName, ARRAYSIZE(Data->OsName), BootEntry->FriendlyName); 378 379 /* We have found our entry, stop the enumeration now! */ 380 return STATUS_NO_MORE_ENTRIES; 381 382SkipThisEntry: 383 Data->UseExistingEntry = FALSE; 384 if (Type == FreeLdr && wcscmp(Data->SectionName, (PWSTR)BootEntry->BootEntryKey)== 0) 385 { 386 RtlStringCchPrintfW(Data->SectionName, ARRAYSIZE(Data->SectionName), 387 L"ReactOS_%lu", Data->i); 388 RtlStringCchPrintfW(Data->OsName, ARRAYSIZE(Data->OsName), 389 L"\"ReactOS %lu\"", Data->i); 390 Data->i++; 391 } 392 return STATUS_SUCCESS; 393} 394 395static 396NTSTATUS 397UpdateFreeLoaderIni( 398 IN PCWSTR IniPath, 399 IN PCWSTR ArcPath) 400{ 401 NTSTATUS Status; 402 PVOID BootStoreHandle; 403 ENUM_REACTOS_ENTRIES_DATA Data; 404 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 405 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 406 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 407 408 /* Open the INI file */ 409 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, 410 BS_OpenExisting /* BS_OpenAlways */, BS_ReadWriteAccess); 411 if (!NT_SUCCESS(Status)) 412 return Status; 413 414 /* Find an existing usable or an unused section name */ 415 Data.UseExistingEntry = TRUE; 416 Data.i = 1; 417 Data.ArcPath = ArcPath; 418 RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS"); 419 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\""); 420 421 // 422 // FIXME: We temporarily use EnumerateBootStoreEntries, until 423 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented. 424 // 425 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data); 426 427 /* Create a new "ReactOS" entry if there is none already existing that suits us */ 428 if (!Data.UseExistingEntry) 429 { 430 // RtlStringCchPrintfW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS_%lu", Data.i); 431 // RtlStringCchPrintfW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS %lu\"", Data.i); 432 433 BootEntry->Version = FreeLdr; 434 BootEntry->BootFilePath = NULL; 435 436 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 437 RtlCopyMemory(Options->Signature, 438 NTOS_OPTIONS_SIGNATURE, 439 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 440 441 Options->OsLoadPath = ArcPath; 442 443 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName); 444 BootEntry->FriendlyName = Data.OsName; 445 Options->OsLoadOptions = NULL; // L""; 446 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Data.SectionName)); 447 } 448 449 /* Close the INI file */ 450 CloseBootStore(BootStoreHandle); 451 return STATUS_SUCCESS; 452} 453 454static 455NTSTATUS 456UpdateBootIni( 457 IN PCWSTR IniPath, 458 IN PCWSTR EntryName, // ~= ArcPath 459 IN PCWSTR EntryValue) 460{ 461 NTSTATUS Status; 462 PVOID BootStoreHandle; 463 ENUM_REACTOS_ENTRIES_DATA Data; 464 465 // NOTE: Technically it would be "BootSector"... 466 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 467 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 468 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 469 470 /* Open the INI file */ 471 Status = OpenBootStore(&BootStoreHandle, IniPath, NtLdr, 472 BS_OpenExisting /* BS_OpenAlways */, BS_ReadWriteAccess); 473 if (!NT_SUCCESS(Status)) 474 return Status; 475 476 /* Find an existing usable or an unused section name */ 477 Data.UseExistingEntry = TRUE; 478 // Data.i = 1; 479 Data.ArcPath = EntryName; 480 // RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS"); 481 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\""); 482 483 // 484 // FIXME: We temporarily use EnumerateBootStoreEntries, until 485 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented. 486 // 487 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data); 488 489 /* If either the key was not found, or contains something else, add a new one */ 490 if (!Data.UseExistingEntry /* || 491 ( (Status == STATUS_NO_MORE_ENTRIES) && wcscmp(Data.OsName, EntryValue) ) */) 492 { 493 BootEntry->Version = NtLdr; 494 BootEntry->BootFilePath = NULL; 495 496 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 497 RtlCopyMemory(Options->Signature, 498 NTOS_OPTIONS_SIGNATURE, 499 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 500 501 Options->OsLoadPath = EntryName; 502 503 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName); 504 // BootEntry->FriendlyName = Data.OsName; 505 BootEntry->FriendlyName = EntryValue; 506 Options->OsLoadOptions = NULL; // L""; 507 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(0 /*Data.SectionName*/)); 508 } 509 510 /* Close the INI file */ 511 CloseBootStore(BootStoreHandle); 512 return STATUS_SUCCESS; // Status; 513} 514 515 516static 517BOOLEAN 518IsThereAValidBootSector( 519 IN PCWSTR RootPath) 520{ 521 /* 522 * We first demand that the bootsector has a valid signature at its end. 523 * We then check the first 3 bytes (as a ULONG) of the bootsector for a 524 * potential "valid" instruction (the BIOS starts execution of the bootsector 525 * at its beginning). Currently this criterium is that this ULONG must be 526 * non-zero. If both these tests pass, then the bootsector is valid; otherwise 527 * it is invalid and certainly needs to be overwritten. 528 */ 529 530 BOOLEAN IsValid = FALSE; 531 NTSTATUS Status; 532 UNICODE_STRING RootPartition; 533 BOOTCODE BootSector = {0}; 534 535 /* Allocate and read the root partition bootsector. 536 * Remove any trailing backslash if needed. */ 537 RtlInitUnicodeString(&RootPartition, RootPath); 538 TrimTrailingPathSeparators_UStr(&RootPartition); 539 Status = ReadBootCodeFromFile(&BootSector, &RootPartition, SECTORSIZE); 540 if (!NT_SUCCESS(Status)) 541 return FALSE; 542 543 /* Check for the existence of the bootsector signature */ 544 IsValid = (*(PUSHORT)((PUCHAR)BootSector.BootCode + 0x1FE) == 0xAA55); 545 if (IsValid) 546 { 547 /* Check for the first instruction encoded on three bytes */ 548 IsValid = (((*(PULONG)BootSector.BootCode) & 0x00FFFFFF) != 0x00000000); 549 } 550 551 /* Free the bootsector and return */ 552 FreeBootCode(&BootSector); 553 return IsValid; 554} 555 556static 557NTSTATUS 558SaveBootSector( 559 IN PCWSTR RootPath, 560 IN PCWSTR DstPath, 561 IN ULONG Length) 562{ 563 NTSTATUS Status; 564 UNICODE_STRING Name; 565 OBJECT_ATTRIBUTES ObjectAttributes; 566 IO_STATUS_BLOCK IoStatusBlock; 567 HANDLE FileHandle; 568 // LARGE_INTEGER FileOffset; 569 BOOTCODE BootSector = {0}; 570 571 /* Allocate and read the root partition bootsector. 572 * Remove any trailing backslash if needed. */ 573 RtlInitUnicodeString(&Name, RootPath); 574 TrimTrailingPathSeparators_UStr(&Name); 575 Status = ReadBootCodeFromFile(&BootSector, &Name, Length); 576 if (!NT_SUCCESS(Status)) 577 return Status; 578 579 /* Write the bootsector to DstPath */ 580 RtlInitUnicodeString(&Name, DstPath); 581 InitializeObjectAttributes(&ObjectAttributes, 582 &Name, 583 OBJ_CASE_INSENSITIVE, 584 NULL, 585 NULL); 586 587 Status = NtCreateFile(&FileHandle, 588 GENERIC_WRITE | SYNCHRONIZE, 589 &ObjectAttributes, 590 &IoStatusBlock, 591 NULL, 592 FILE_ATTRIBUTE_NORMAL, 593 0, 594 FILE_SUPERSEDE, 595 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, 596 NULL, 597 0); 598 if (!NT_SUCCESS(Status)) 599 { 600 FreeBootCode(&BootSector); 601 return Status; 602 } 603 604 Status = NtWriteFile(FileHandle, 605 NULL, 606 NULL, 607 NULL, 608 &IoStatusBlock, 609 BootSector.BootCode, 610 BootSector.Length, 611 NULL, 612 NULL); 613 NtClose(FileHandle); 614 615 /* Free the bootsector and return */ 616 FreeBootCode(&BootSector); 617 return Status; 618} 619 620 621static 622NTSTATUS 623InstallBootCodeToDisk( 624 IN PCWSTR SrcPath, 625 IN PCWSTR RootPath, 626 IN PFS_INSTALL_BOOTCODE InstallBootCode) 627{ 628 NTSTATUS Status, LockStatus; 629 UNICODE_STRING Name; 630 OBJECT_ATTRIBUTES ObjectAttributes; 631 IO_STATUS_BLOCK IoStatusBlock; 632 HANDLE PartitionHandle; 633 634 /* 635 * Open the root partition from which the bootcode (MBR, VBR) parameters 636 * will be obtained; this is also where we will write the updated bootcode. 637 * Remove any trailing backslash if needed. 638 */ 639 RtlInitUnicodeString(&Name, RootPath); 640 TrimTrailingPathSeparators_UStr(&Name); 641 642 InitializeObjectAttributes(&ObjectAttributes, 643 &Name, 644 OBJ_CASE_INSENSITIVE, 645 NULL, 646 NULL); 647 648 Status = NtOpenFile(&PartitionHandle, 649 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 650 &ObjectAttributes, 651 &IoStatusBlock, 652 FILE_SHARE_READ | FILE_SHARE_WRITE, 653 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); 654 if (!NT_SUCCESS(Status)) 655 return Status; 656 657 /* Lock the volume */ 658 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); 659 if (!NT_SUCCESS(LockStatus)) 660 { 661 DPRINT1("Unable to lock the volume before installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 662 } 663 664 /* Install the bootcode (MBR, VBR) */ 665 Status = InstallBootCode(SrcPath, PartitionHandle, PartitionHandle); 666 667 /* dismount & Unlock the volume */ 668 if (NT_SUCCESS(LockStatus)) 669 { 670 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); 671 if (!NT_SUCCESS(LockStatus)) 672 { 673 DPRINT1("Unable to dismount the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 674 } 675 676 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); 677 if (!NT_SUCCESS(LockStatus)) 678 { 679 DPRINT1("Unable to unlock the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 680 } 681 } 682 683 /* Close the partition */ 684 NtClose(PartitionHandle); 685 686 return Status; 687} 688 689static 690NTSTATUS 691InstallBootCodeToFile( 692 IN PCWSTR SrcPath, 693 IN PCWSTR DstPath, 694 IN PCWSTR RootPath, 695 IN PFS_INSTALL_BOOTCODE InstallBootCode) 696{ 697 NTSTATUS Status; 698 UNICODE_STRING Name; 699 OBJECT_ATTRIBUTES ObjectAttributes; 700 IO_STATUS_BLOCK IoStatusBlock; 701 HANDLE PartitionHandle, FileHandle; 702 703 /* 704 * Open the root partition from which the bootcode (MBR, VBR) 705 * parameters will be obtained. 706 * 707 * FIXME? It might be possible that we need to also open it for writing 708 * access in case we really need to still write the second portion of 709 * the boot sector ???? 710 * 711 * Remove any trailing backslash if needed. 712 */ 713 RtlInitUnicodeString(&Name, RootPath); 714 TrimTrailingPathSeparators_UStr(&Name); 715 716 InitializeObjectAttributes(&ObjectAttributes, 717 &Name, 718 OBJ_CASE_INSENSITIVE, 719 NULL, 720 NULL); 721 722 Status = NtOpenFile(&PartitionHandle, 723 GENERIC_READ | SYNCHRONIZE, 724 &ObjectAttributes, 725 &IoStatusBlock, 726 FILE_SHARE_READ | FILE_SHARE_WRITE, 727 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); 728 if (!NT_SUCCESS(Status)) 729 return Status; 730 731 /* Open or create the file where the new bootsector will be saved */ 732 RtlInitUnicodeString(&Name, DstPath); 733 InitializeObjectAttributes(&ObjectAttributes, 734 &Name, 735 OBJ_CASE_INSENSITIVE, 736 NULL, 737 NULL); 738 739 Status = NtCreateFile(&FileHandle, 740 GENERIC_WRITE | SYNCHRONIZE, 741 &ObjectAttributes, 742 &IoStatusBlock, 743 NULL, 744 FILE_ATTRIBUTE_NORMAL, 745 0, 746 FILE_SUPERSEDE, // FILE_OVERWRITE_IF 747 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, 748 NULL, 749 0); 750 if (!NT_SUCCESS(Status)) 751 { 752 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status); 753 NtClose(PartitionHandle); 754 return Status; 755 } 756 757 /* Install the bootcode (MBR, VBR) */ 758 Status = InstallBootCode(SrcPath, FileHandle, PartitionHandle); 759 760 /* Close the file and the partition */ 761 NtClose(FileHandle); 762 NtClose(PartitionHandle); 763 764 return Status; 765} 766 767 768static 769NTSTATUS 770InstallMbrBootCode( 771 IN PCWSTR SrcPath, // MBR source file (on the installation medium) 772 IN HANDLE DstPath, // Where to save the bootsector built from the source + disk information 773 IN HANDLE DiskHandle) // Disk holding the (old) MBR information 774{ 775 NTSTATUS Status; 776 UNICODE_STRING Name; 777 IO_STATUS_BLOCK IoStatusBlock; 778 LARGE_INTEGER FileOffset; 779 BOOTCODE OrigBootSector = {0}; 780 BOOTCODE NewBootSector = {0}; 781 782C_ASSERT(sizeof(PARTITION_SECTOR) == SECTORSIZE); 783 784 /* Allocate and read the current original MBR bootsector */ 785 Status = ReadBootCodeByHandle(&OrigBootSector, 786 DiskHandle, 787 sizeof(PARTITION_SECTOR)); 788 if (!NT_SUCCESS(Status)) 789 return Status; 790 791 /* Allocate and read the new bootsector from SrcPath */ 792 RtlInitUnicodeString(&Name, SrcPath); 793 Status = ReadBootCodeFromFile(&NewBootSector, 794 &Name, 795 sizeof(PARTITION_SECTOR)); 796 if (!NT_SUCCESS(Status)) 797 { 798 FreeBootCode(&OrigBootSector); 799 return Status; 800 } 801 802 /* 803 * Copy the disk signature, the reserved fields and 804 * the partition table from the old MBR to the new one. 805 */ 806 RtlCopyMemory(&((PPARTITION_SECTOR)NewBootSector.BootCode)->Signature, 807 &((PPARTITION_SECTOR)OrigBootSector.BootCode)->Signature, 808 sizeof(PARTITION_SECTOR) - 809 FIELD_OFFSET(PARTITION_SECTOR, Signature) 810 /* Length of partition table */); 811 812 /* Free the original bootsector */ 813 FreeBootCode(&OrigBootSector); 814 815 /* Write the new bootsector to DstPath */ 816 FileOffset.QuadPart = 0ULL; 817 Status = NtWriteFile(DstPath, 818 NULL, 819 NULL, 820 NULL, 821 &IoStatusBlock, 822 NewBootSector.BootCode, 823 NewBootSector.Length, 824 &FileOffset, 825 NULL); 826 827 /* Free the new bootsector */ 828 FreeBootCode(&NewBootSector); 829 830 return Status; 831} 832 833static 834NTSTATUS 835InstallMbrBootCodeToDisk( 836 _In_ PCUNICODE_STRING SystemRootPath, 837 _In_ PCUNICODE_STRING SourceRootPath, 838 _In_ PCWSTR DestinationDevicePathBuffer) 839{ 840 NTSTATUS Status; 841 WCHAR SourceMbrPathBuffer[MAX_PATH]; 842 WCHAR DstPath[MAX_PATH]; 843 844#if 0 845 /* 846 * The DestinationDevicePathBuffer parameter has been built with 847 * the following instruction by the caller; I'm not yet sure whether 848 * I actually want this function to build the path instead, hence 849 * I keep this code here but disabled for now... 850 */ 851 WCHAR DestinationDevicePathBuffer[MAX_PATH]; 852 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer), 853 L"\\Device\\Harddisk%d\\Partition0", 854 DiskNumber); 855#endif 856 857 CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, 858 SourceRootPath->Buffer, L"\\loader\\dosmbr.bin"); 859 860 if (IsThereAValidBootSector(DestinationDevicePathBuffer)) 861 { 862 /* Save current MBR */ 863 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, 864 SystemRootPath->Buffer, L"mbr.old"); 865 866 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath); 867 Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR)); 868 if (!NT_SUCCESS(Status)) 869 { 870 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 871 // Don't care if we succeeded or not saving the old MBR, just go ahead. 872 } 873 } 874 875 DPRINT1("Install MBR bootcode: %S ==> %S\n", 876 SourceMbrPathBuffer, DestinationDevicePathBuffer); 877 878 /* Install the MBR */ 879 return InstallBootCodeToDisk(SourceMbrPathBuffer, 880 DestinationDevicePathBuffer, 881 InstallMbrBootCode); 882} 883 884static 885NTSTATUS 886InstallBootloaderFiles( 887 _In_ PCUNICODE_STRING SystemRootPath, 888 _In_ PCUNICODE_STRING SourceRootPath) 889{ 890 NTSTATUS Status; 891 WCHAR SrcPath[MAX_PATH]; 892 WCHAR DstPath[MAX_PATH]; 893 894 /* Copy FreeLoader to the system partition, always overwriting the older version */ 895 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 896 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); 897 898 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 899 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 900 if (!NT_SUCCESS(Status)) 901 { 902 DPRINT1("SetupCopyFile() failed (Status 0x%08lx)\n", Status); 903 return Status; 904 } 905 906 /* Copy rosload to the system partition, always overwriting the older version */ 907 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\rosload.exe"); 908 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"rosload.exe"); 909 910 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 911 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 912 if (!NT_SUCCESS(Status)) 913 { 914 DPRINT1("SetupCopyFile() failed (Status 0x%08lx)\n", Status); 915 return Status; 916 } 917 918 return STATUS_SUCCESS; 919} 920 921static 922NTSTATUS 923InstallFatBootcodeToPartition( 924 _In_ PCUNICODE_STRING SystemRootPath, 925 _In_ PCUNICODE_STRING SourceRootPath, 926 _In_ PCUNICODE_STRING DestinationArcPath, 927 _In_ PCWSTR FileSystemName) 928{ 929 NTSTATUS Status; 930 BOOLEAN DoesFreeLdrExist; 931 WCHAR SrcPath[MAX_PATH]; 932 WCHAR DstPath[MAX_PATH]; 933 934 /* FAT or FAT32 partition */ 935 DPRINT("System path: '%wZ'\n", SystemRootPath); 936 937 /* Install the bootloader */ 938 Status = InstallBootloaderFiles(SystemRootPath, SourceRootPath); 939 if (!NT_SUCCESS(Status)) 940 { 941 DPRINT1("InstallBootloaderFiles() failed (Status %lx)\n", Status); 942 return Status; 943 } 944 945 /* Prepare for possibly updating 'freeldr.ini' */ 946 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 947 if (DoesFreeLdrExist) 948 { 949 /* Update existing 'freeldr.ini' */ 950 DPRINT1("Update existing 'freeldr.ini'\n"); 951 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 952 if (!NT_SUCCESS(Status)) 953 { 954 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 955 return Status; 956 } 957 } 958 959 /* Check for NT and other bootloaders */ 960 961 // FIXME: Check for Vista+ bootloader! 962 /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/ 963 /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/ 964 if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE || 965 DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE) 966 { 967 /* Search root directory for 'NTLDR' and 'BOOT.INI' */ 968 DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n"); 969 970 /* Create or update 'freeldr.ini' */ 971 if (DoesFreeLdrExist == FALSE) 972 { 973 /* Create new 'freeldr.ini' */ 974 DPRINT1("Create new 'freeldr.ini'\n"); 975 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 976 if (!NT_SUCCESS(Status)) 977 { 978 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 979 return Status; 980 } 981 982 /* Install new bootcode into a file */ 983 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"bootsect.ros"); 984 985 if (_wcsicmp(FileSystemName, L"FAT32") == 0) 986 { 987 /* Install FAT32 bootcode */ 988 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin"); 989 990 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath); 991 Status = InstallBootCodeToFile(SrcPath, DstPath, 992 SystemRootPath->Buffer, 993 InstallFat32BootCode); 994 if (!NT_SUCCESS(Status)) 995 { 996 DPRINT1("InstallBootCodeToFile(FAT32) failed (Status %lx)\n", Status); 997 return Status; 998 } 999 } 1000 else // if (wcsicmp(FileSystemName, L"FAT") == 0) 1001 { 1002 /* Install FAT16 bootcode */ 1003 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1004 1005 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, DstPath); 1006 Status = InstallBootCodeToFile(SrcPath, DstPath, 1007 SystemRootPath->Buffer, 1008 InstallFat16BootCode); 1009 if (!NT_SUCCESS(Status)) 1010 { 1011 DPRINT1("InstallBootCodeToFile(FAT16) failed (Status %lx)\n", Status); 1012 return Status; 1013 } 1014 } 1015 } 1016 1017 /* Update 'boot.ini' */ 1018 /* Windows' NTLDR loads an external bootsector file when the specified drive 1019 letter is C:, otherwise it will interpret it as a boot DOS path specifier. */ 1020 DPRINT1("Update 'boot.ini'\n"); 1021 Status = UpdateBootIni(SystemRootPath->Buffer, 1022 L"C:\\bootsect.ros", 1023 L"\"ReactOS\""); 1024 if (!NT_SUCCESS(Status)) 1025 { 1026 DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status); 1027 return Status; 1028 } 1029 } 1030 else 1031 { 1032 /* Non-NT bootloaders: install our own bootloader */ 1033 1034 PCWSTR Section; 1035 PCWSTR Description; 1036 PCWSTR BootSector; 1037 1038 /* Search for COMPAQ MS-DOS 1.x (1.11, 1.12, based on MS-DOS 1.25) boot loader */ 1039 if (DoesFileExist_2(SystemRootPath->Buffer, L"IOSYS.COM") == TRUE || 1040 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.COM") == TRUE) 1041 { 1042 DPRINT1("Found COMPAQ MS-DOS 1.x (1.11, 1.12) / MS-DOS 1.25 boot loader\n"); 1043 1044 Section = L"CPQDOS"; 1045 Description = L"\"COMPAQ MS-DOS 1.x / MS-DOS 1.25\""; 1046 BootSector = L"BOOTSECT.DOS"; 1047 } 1048 else 1049 /* Search for Microsoft DOS or Windows 9x boot loader */ 1050 if (DoesFileExist_2(SystemRootPath->Buffer, L"IO.SYS") == TRUE || 1051 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.SYS") == TRUE) 1052 // WINBOOT.SYS 1053 { 1054 DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n"); 1055 1056 Section = L"MSDOS"; 1057 Description = L"\"MS-DOS/Windows\""; 1058 BootSector = L"BOOTSECT.DOS"; 1059 } 1060 else 1061 /* Search for IBM PC-DOS or DR-DOS 5.x boot loader */ 1062 if (DoesFileExist_2(SystemRootPath->Buffer, L"IBMIO.COM" ) == TRUE || // Some people refer to this file instead of IBMBIO.COM... 1063 DoesFileExist_2(SystemRootPath->Buffer, L"IBMBIO.COM") == TRUE || 1064 DoesFileExist_2(SystemRootPath->Buffer, L"IBMDOS.COM") == TRUE) 1065 { 1066 DPRINT1("Found IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\n"); 1067 1068 Section = L"IBMDOS"; 1069 Description = L"\"IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\""; 1070 BootSector = L"BOOTSECT.DOS"; 1071 } 1072 else 1073 /* Search for DR-DOS 3.x boot loader */ 1074 if (DoesFileExist_2(SystemRootPath->Buffer, L"DRBIOS.SYS") == TRUE || 1075 DoesFileExist_2(SystemRootPath->Buffer, L"DRBDOS.SYS") == TRUE) 1076 { 1077 DPRINT1("Found DR-DOS 3.x\n"); 1078 1079 Section = L"DRDOS"; 1080 Description = L"\"DR-DOS 3.x\""; 1081 BootSector = L"BOOTSECT.DOS"; 1082 } 1083 else 1084 /* Search for Dell Real-Mode Kernel (DRMK) OS */ 1085 if (DoesFileExist_2(SystemRootPath->Buffer, L"DELLBIO.BIN") == TRUE || 1086 DoesFileExist_2(SystemRootPath->Buffer, L"DELLRMK.BIN") == TRUE) 1087 { 1088 DPRINT1("Found Dell Real-Mode Kernel OS\n"); 1089 1090 Section = L"DRMK"; 1091 Description = L"\"Dell Real-Mode Kernel OS\""; 1092 BootSector = L"BOOTSECT.DOS"; 1093 } 1094 else 1095 /* Search for MS OS/2 1.x */ 1096 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT.COM") == TRUE || 1097 DoesFileExist_2(SystemRootPath->Buffer, L"OS2BIO.COM" ) == TRUE || 1098 DoesFileExist_2(SystemRootPath->Buffer, L"OS2DOS.COM" ) == TRUE) 1099 { 1100 DPRINT1("Found MS OS/2 1.x\n"); 1101 1102 Section = L"MSOS2"; 1103 Description = L"\"MS OS/2 1.x\""; 1104 BootSector = L"BOOTSECT.OS2"; 1105 } 1106 else 1107 /* Search for MS or IBM OS/2 */ 1108 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT") == TRUE || 1109 DoesFileExist_2(SystemRootPath->Buffer, L"OS2LDR" ) == TRUE || 1110 DoesFileExist_2(SystemRootPath->Buffer, L"OS2KRNL") == TRUE) 1111 { 1112 DPRINT1("Found MS/IBM OS/2\n"); 1113 1114 Section = L"IBMOS2"; 1115 Description = L"\"MS/IBM OS/2\""; 1116 BootSector = L"BOOTSECT.OS2"; 1117 } 1118 else 1119 /* Search for FreeDOS boot loader */ 1120 if (DoesFileExist_2(SystemRootPath->Buffer, L"kernel.sys") == TRUE) 1121 { 1122 DPRINT1("Found FreeDOS boot loader\n"); 1123 1124 Section = L"FDOS"; 1125 Description = L"\"FreeDOS\""; 1126 BootSector = L"BOOTSECT.DOS"; 1127 } 1128 else 1129 { 1130 /* No or unknown boot loader */ 1131 DPRINT1("No or unknown boot loader found\n"); 1132 1133 Section = L"Unknown"; 1134 Description = L"\"Unknown Operating System\""; 1135 BootSector = L"BOOTSECT.OLD"; 1136 } 1137 1138 /* Create or update 'freeldr.ini' */ 1139 if (DoesFreeLdrExist == FALSE) 1140 { 1141 /* Create new 'freeldr.ini' */ 1142 DPRINT1("Create new 'freeldr.ini'\n"); 1143 1144 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1145 { 1146 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1147 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1148 Section, Description, 1149 SystemRootPath->Buffer, BootSector); 1150 if (!NT_SUCCESS(Status)) 1151 { 1152 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1153 return Status; 1154 } 1155 1156 /* Save current bootsector */ 1157 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1158 1159 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1160 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE); 1161 if (!NT_SUCCESS(Status)) 1162 { 1163 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1164 return Status; 1165 } 1166 } 1167 else 1168 { 1169 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1170 if (!NT_SUCCESS(Status)) 1171 { 1172 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1173 return Status; 1174 } 1175 } 1176 1177 /* Install new bootsector on the disk */ 1178 if (_wcsicmp(FileSystemName, L"FAT32") == 0) 1179 { 1180 /* Install FAT32 bootcode */ 1181 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin"); 1182 1183 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1184 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat32BootCode); 1185 DPRINT1("Status: 0x%08X\n", Status); 1186 if (!NT_SUCCESS(Status)) 1187 { 1188 DPRINT1("InstallBootCodeToDisk(FAT32) failed (Status %lx)\n", Status); 1189 return Status; 1190 } 1191 } 1192 else // if (wcsicmp(FileSystemName, L"FAT") == 0) 1193 { 1194 /* Install FAT16 bootcode */ 1195 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1196 1197 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1198 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat16BootCode); 1199 if (!NT_SUCCESS(Status)) 1200 { 1201 DPRINT1("InstallBootCodeToDisk(FAT16) failed (Status %lx)\n", Status); 1202 return Status; 1203 } 1204 } 1205 } 1206 } 1207 1208 return STATUS_SUCCESS; 1209} 1210 1211static 1212NTSTATUS 1213InstallBtrfsBootcodeToPartition( 1214 _In_ PCUNICODE_STRING SystemRootPath, 1215 _In_ PCUNICODE_STRING SourceRootPath, 1216 _In_ PCUNICODE_STRING DestinationArcPath) 1217{ 1218 NTSTATUS Status; 1219 BOOLEAN DoesFreeLdrExist; 1220 WCHAR SrcPath[MAX_PATH]; 1221 WCHAR DstPath[MAX_PATH]; 1222 1223 /* BTRFS partition */ 1224 DPRINT("System path: '%wZ'\n", SystemRootPath); 1225 1226 /* Install the bootloader */ 1227 Status = InstallBootloaderFiles(SystemRootPath, SourceRootPath); 1228 if (!NT_SUCCESS(Status)) 1229 { 1230 DPRINT1("InstallBootloaderFiles() failed (Status %lx)\n", Status); 1231 return Status; 1232 } 1233 1234 /* Prepare for possibly updating 'freeldr.ini' */ 1235 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 1236 if (DoesFreeLdrExist) 1237 { 1238 /* Update existing 'freeldr.ini' */ 1239 DPRINT1("Update existing 'freeldr.ini'\n"); 1240 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1241 if (!NT_SUCCESS(Status)) 1242 { 1243 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 1244 return Status; 1245 } 1246 } 1247 1248 /* Check for *nix bootloaders */ 1249 1250 /* Create or update 'freeldr.ini' */ 1251 if (DoesFreeLdrExist == FALSE) 1252 { 1253 /* Create new 'freeldr.ini' */ 1254 DPRINT1("Create new 'freeldr.ini'\n"); 1255 1256 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */ 1257 DPRINT1("*nix or unknown boot loader found\n"); 1258 1259 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1260 { 1261 PCWSTR BootSector = L"BOOTSECT.OLD"; 1262 1263 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1264 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1265 L"Linux", L"\"Linux\"", 1266 SystemRootPath->Buffer, BootSector); 1267 if (!NT_SUCCESS(Status)) 1268 { 1269 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1270 return Status; 1271 } 1272 1273 /* Save current bootsector */ 1274 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1275 1276 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1277 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, BTRFS_BOOTSECTOR_SIZE); 1278 if (!NT_SUCCESS(Status)) 1279 { 1280 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1281 return Status; 1282 } 1283 } 1284 else 1285 { 1286 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1287 if (!NT_SUCCESS(Status)) 1288 { 1289 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1290 return Status; 1291 } 1292 } 1293 1294 /* Install new bootsector on the disk */ 1295 /* Install BTRFS bootcode */ 1296 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin"); 1297 1298 DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1299 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallBtrfsBootCode); 1300 if (!NT_SUCCESS(Status)) 1301 { 1302 DPRINT1("InstallBootCodeToDisk(BTRFS) failed (Status %lx)\n", Status); 1303 return Status; 1304 } 1305 } 1306 1307 return STATUS_SUCCESS; 1308} 1309 1310static 1311NTSTATUS 1312InstallNtfsBootcodeToPartition( 1313 _In_ PCUNICODE_STRING SystemRootPath, 1314 _In_ PCUNICODE_STRING SourceRootPath, 1315 _In_ PCUNICODE_STRING DestinationArcPath) 1316{ 1317 NTSTATUS Status; 1318 BOOLEAN DoesFreeLdrExist; 1319 WCHAR SrcPath[MAX_PATH]; 1320 WCHAR DstPath[MAX_PATH]; 1321 1322 /* NTFS partition */ 1323 DPRINT("System path: '%wZ'\n", SystemRootPath); 1324 1325 /* Install the bootloader */ 1326 Status = InstallBootloaderFiles(SystemRootPath, SourceRootPath); 1327 if (!NT_SUCCESS(Status)) 1328 { 1329 DPRINT1("InstallBootloaderFiles() failed (Status %lx)\n", Status); 1330 return Status; 1331 } 1332 1333 /* Prepare for possibly updating 'freeldr.ini' */ 1334 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 1335 if (DoesFreeLdrExist) 1336 { 1337 /* Update existing 'freeldr.ini' */ 1338 DPRINT1("Update existing 'freeldr.ini'\n"); 1339 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1340 if (!NT_SUCCESS(Status)) 1341 { 1342 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 1343 return Status; 1344 } 1345 1346 return STATUS_SUCCESS; 1347 } 1348 1349 /* Check for *nix bootloaders */ 1350 1351 DPRINT1("Create new 'freeldr.ini'\n"); 1352 1353 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */ 1354 DPRINT1("*nix or unknown boot loader found\n"); 1355 1356 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1357 { 1358 PCWSTR BootSector = L"BOOTSECT.OLD"; 1359 1360 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1361 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1362 L"Linux", L"\"Linux\"", 1363 SystemRootPath->Buffer, BootSector); 1364 if (!NT_SUCCESS(Status)) 1365 { 1366 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1367 return Status; 1368 } 1369 1370 /* Save current bootsector */ 1371 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1372 1373 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1374 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, NTFS_BOOTSECTOR_SIZE); 1375 if (!NT_SUCCESS(Status)) 1376 { 1377 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1378 return Status; 1379 } 1380 } 1381 else 1382 { 1383 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1384 if (!NT_SUCCESS(Status)) 1385 { 1386 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1387 return Status; 1388 } 1389 } 1390 1391 /* Install new bootsector on the disk */ 1392 1393 /* Install NTFS bootcode */ 1394 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\ntfs.bin"); 1395 1396 DPRINT1("Install NTFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1397 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallNtfsBootCode); 1398 if (!NT_SUCCESS(Status)) 1399 { 1400 DPRINT1("InstallBootCodeToDisk(NTFS) failed (Status %lx)\n", Status); 1401 return Status; 1402 } 1403 1404 return STATUS_SUCCESS; 1405} 1406 1407static 1408NTSTATUS 1409InstallVBRToPartition( 1410 _In_ PCUNICODE_STRING SystemRootPath, 1411 _In_ PCUNICODE_STRING SourceRootPath, 1412 _In_ PCUNICODE_STRING DestinationArcPath, 1413 _In_ PCWSTR FileSystemName) 1414{ 1415 if (_wcsicmp(FileSystemName, L"FAT") == 0 || 1416 _wcsicmp(FileSystemName, L"FAT32") == 0) 1417 { 1418 return InstallFatBootcodeToPartition(SystemRootPath, 1419 SourceRootPath, 1420 DestinationArcPath, 1421 FileSystemName); 1422 } 1423 else if (_wcsicmp(FileSystemName, L"NTFS") == 0) 1424 { 1425 return InstallNtfsBootcodeToPartition(SystemRootPath, 1426 SourceRootPath, 1427 DestinationArcPath); 1428 } 1429 else if (_wcsicmp(FileSystemName, L"BTRFS") == 0) 1430 { 1431 return InstallBtrfsBootcodeToPartition(SystemRootPath, 1432 SourceRootPath, 1433 DestinationArcPath); 1434 } 1435 /* 1436 else if (_wcsicmp(FileSystemName, L"EXT2") == 0 || 1437 _wcsicmp(FileSystemName, L"EXT3") == 0 || 1438 _wcsicmp(FileSystemName, L"EXT4") == 0) 1439 { 1440 return STATUS_NOT_SUPPORTED; 1441 } 1442 */ 1443 else 1444 { 1445 /* Unknown file system */ 1446 DPRINT1("Unknown file system '%S'\n", FileSystemName); 1447 } 1448 1449 return STATUS_NOT_SUPPORTED; 1450} 1451 1452 1453/* GENERIC FUNCTIONS *********************************************************/ 1454 1455/** 1456 * @brief 1457 * Helper for InstallBootManagerAndBootEntries(). 1458 * 1459 * @param[in] ArchType 1460 * @param[in] SystemRootPath 1461 * See InstallBootManagerAndBootEntries() parameters. 1462 * 1463 * @param[in] DiskNumber 1464 * The NT disk number of the system disk that contains the system partition. 1465 * 1466 * @param[in] DiskStyle 1467 * The partitioning style of the system disk. 1468 * 1469 * @param[in] IsSuperFloppy 1470 * Whether the system disk is a super-floppy. 1471 * 1472 * @param[in] FileSystem 1473 * The file system of the system partition. 1474 * 1475 * @param[in] SourceRootPath 1476 * @param[in] DestinationArcPath 1477 * @param[in] Options 1478 * See InstallBootManagerAndBootEntries() parameters. 1479 * 1480 * @return An NTSTATUS code indicating success or failure. 1481 **/ 1482static 1483NTSTATUS 1484InstallBootManagerAndBootEntriesWorker( 1485 _In_ ARCHITECTURE_TYPE ArchType, 1486 _In_ PCUNICODE_STRING SystemRootPath, 1487 _In_ ULONG DiskNumber, // const STORAGE_DEVICE_NUMBER* DeviceNumber, 1488 _In_ PARTITION_STYLE DiskStyle, 1489 _In_ BOOLEAN IsSuperFloppy, 1490 _In_ PCWSTR FileSystem, 1491 _In_ PCUNICODE_STRING SourceRootPath, 1492 _In_ PCUNICODE_STRING DestinationArcPath, 1493 _In_ ULONG_PTR Options) 1494{ 1495 NTSTATUS Status; 1496 BOOLEAN IsBIOS = ((ArchType == ARCH_PcAT) || (ArchType == ARCH_NEC98x86)); 1497 UCHAR InstallType = (Options & 0x03); 1498 1499 // FIXME: We currently only support BIOS-based PCs 1500 // TODO: Support other platforms 1501 if (!IsBIOS) 1502 return STATUS_NOT_SUPPORTED; 1503 1504 if (InstallType <= 1) 1505 { 1506 /* Step 1: Write the VBR */ 1507 Status = InstallVBRToPartition(SystemRootPath, 1508 SourceRootPath, 1509 DestinationArcPath, 1510 FileSystem); 1511 if (!NT_SUCCESS(Status)) 1512 { 1513 DPRINT1("InstallVBRToPartition() failed (Status 0x%08lx)\n", Status); 1514 return ERROR_WRITE_BOOT; // Status; STATUS_BAD_MASTER_BOOT_RECORD; 1515 } 1516 1517 /* Step 2: Write the MBR if the disk containing the 1518 * system partition is MBR and not a super-floppy */ 1519 if ((InstallType == 1) && (DiskStyle == PARTITION_STYLE_MBR) && !IsSuperFloppy) 1520 { 1521 WCHAR SystemDiskPath[MAX_PATH]; 1522 RtlStringCchPrintfW(SystemDiskPath, _countof(SystemDiskPath), 1523 L"\\Device\\Harddisk%d\\Partition0", 1524 DiskNumber); 1525 Status = InstallMbrBootCodeToDisk(SystemRootPath, 1526 SourceRootPath, 1527 SystemDiskPath); 1528 if (!NT_SUCCESS(Status)) 1529 { 1530 DPRINT1("InstallMbrBootCodeToDisk() failed (Status 0x%08lx)\n", Status); 1531 return ERROR_INSTALL_BOOTCODE; // Status; STATUS_BAD_MASTER_BOOT_RECORD; 1532 } 1533 } 1534 } 1535 else if (InstallType == 2) 1536 { 1537 WCHAR SrcPath[MAX_PATH]; 1538 1539 // FIXME: We currently only support FAT12 file system. 1540 if (_wcsicmp(FileSystem, L"FAT") != 0) 1541 return STATUS_NOT_SUPPORTED; 1542 1543 // TODO: In the future, we'll be able to use InstallVBRToPartition() 1544 // directly, instead of re-doing manually the copy steps below. 1545 1546 /* Install the bootloader to the boot partition */ 1547 Status = InstallBootloaderFiles(SystemRootPath, SourceRootPath); 1548 if (!NT_SUCCESS(Status)) 1549 { 1550 DPRINT1("InstallBootloaderFiles() failed (Status 0x%08lx)\n", Status); 1551 return Status; 1552 } 1553 1554 /* Create new 'freeldr.ini' */ 1555 DPRINT("Create new 'freeldr.ini'\n"); 1556 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1557 if (!NT_SUCCESS(Status)) 1558 { 1559 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status 0x%08lx)\n", Status); 1560 return Status; 1561 } 1562 1563 /* Install FAT12 bootsector */ 1564 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1565 1566 DPRINT1("Install FAT12 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1567 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat12BootCode); 1568 if (!NT_SUCCESS(Status)) 1569 { 1570 DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status 0x%08lx)\n", Status); 1571 return Status; 1572 } 1573 } 1574 1575 return Status; 1576} 1577 1578 1579NTSTATUS 1580GetDeviceInfo_UStr( 1581 _In_opt_ PCUNICODE_STRING DeviceName, 1582 _In_opt_ HANDLE DeviceHandle, 1583 _Out_ PFILE_FS_DEVICE_INFORMATION DeviceInfo) 1584{ 1585 NTSTATUS Status; 1586 IO_STATUS_BLOCK IoStatusBlock; 1587 1588 if (DeviceName && DeviceHandle) 1589 return STATUS_INVALID_PARAMETER_MIX; 1590 1591 /* Open the device if a name has been given; 1592 * otherwise just use the provided handle. */ 1593 if (DeviceName) 1594 { 1595 Status = pOpenDeviceEx_UStr(DeviceName, &DeviceHandle, 1596 FILE_READ_ATTRIBUTES, 1597 FILE_SHARE_READ | FILE_SHARE_WRITE); 1598 if (!NT_SUCCESS(Status)) 1599 { 1600 DPRINT1("Cannot open device '%wZ' (Status 0x%08lx)\n", 1601 DeviceName, Status); 1602 return Status; 1603 } 1604 } 1605 1606 /* Query the device */ 1607 Status = NtQueryVolumeInformationFile(DeviceHandle, 1608 &IoStatusBlock, 1609 DeviceInfo, 1610 sizeof(*DeviceInfo), 1611 FileFsDeviceInformation); 1612 if (!NT_SUCCESS(Status)) 1613 DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status); 1614 1615 /* Close the device if we've opened it */ 1616 if (DeviceName) 1617 NtClose(DeviceHandle); 1618 1619 return Status; 1620} 1621 1622NTSTATUS 1623GetDeviceInfo( 1624 _In_opt_ PCWSTR DeviceName, 1625 _In_opt_ HANDLE DeviceHandle, 1626 _Out_ PFILE_FS_DEVICE_INFORMATION DeviceInfo) 1627{ 1628 UNICODE_STRING DeviceNameU; 1629 1630 if (DeviceName && DeviceHandle) 1631 return STATUS_INVALID_PARAMETER_MIX; 1632 1633 if (DeviceName) 1634 RtlInitUnicodeString(&DeviceNameU, DeviceName); 1635 1636 return GetDeviceInfo_UStr(DeviceName ? &DeviceNameU : NULL, 1637 DeviceName ? NULL : DeviceHandle, 1638 DeviceInfo); 1639} 1640 1641 1642/** 1643 * @brief 1644 * Installs FreeLoader on the system and configure the boot entries. 1645 * 1646 * @todo 1647 * Split this function into just the InstallBootManager, and a separate one 1648 * for just the boot entries. 1649 * 1650 * @param[in] ArchType 1651 * The target architecture. 1652 * 1653 * @param[in] SystemRootPath 1654 * The system partition path, where the FreeLdr boot manager and its 1655 * settings are saved to. 1656 * 1657 * @param[in] SourceRootPath 1658 * The installation source, where to copy the FreeLdr boot manager from. 1659 * 1660 * @param[in] DestinationArcPath 1661 * The ReactOS installation path in ARC format. 1662 * 1663 * @param[in] Options 1664 * For BIOS-based PCs: 1665 * LOBYTE: 1666 * 0: Install only on VBR; 1667 * 1: Install on both VBR and MBR. 1668 * 2: Install on removable disk. 1669 * 1670 * @return An NTSTATUS code indicating success or failure. 1671 **/ 1672NTSTATUS 1673NTAPI 1674InstallBootManagerAndBootEntries( 1675 _In_ ARCHITECTURE_TYPE ArchType, 1676 _In_ PCUNICODE_STRING SystemRootPath, 1677 _In_ PCUNICODE_STRING SourceRootPath, 1678 _In_ PCUNICODE_STRING DestinationArcPath, 1679 _In_ ULONG_PTR Options) 1680{ 1681 NTSTATUS Status; 1682 HANDLE DeviceHandle; 1683 FILE_FS_DEVICE_INFORMATION DeviceInfo; 1684 ULONG DiskNumber; 1685 PARTITION_STYLE PartitionStyle; 1686 BOOLEAN IsSuperFloppy; 1687 WCHAR FileSystem[MAX_PATH+1]; 1688 1689 /* Remove any trailing backslash if needed */ 1690 UNICODE_STRING RootPartition = *SystemRootPath; 1691 TrimTrailingPathSeparators_UStr(&RootPartition); 1692 1693 /* Open the volume */ 1694 Status = pOpenDeviceEx_UStr(&RootPartition, &DeviceHandle, 1695 GENERIC_READ, 1696 FILE_SHARE_READ | FILE_SHARE_WRITE); 1697 if (!NT_SUCCESS(Status)) 1698 { 1699 DPRINT1("Cannot open %wZ for bootloader installation (Status 0x%08lx)\n", 1700 &RootPartition, Status); 1701 return Status; 1702 } 1703 1704 /* Retrieve the volume file system (it will also be mounted) */ 1705 Status = GetFileSystemName_UStr(NULL, DeviceHandle, 1706 FileSystem, sizeof(FileSystem)); 1707 if (!NT_SUCCESS(Status) || !*FileSystem) 1708 { 1709 DPRINT1("GetFileSystemName() failed (Status 0x%08lx)\n", Status); 1710 goto Quit; 1711 } 1712 1713 /* Retrieve the device type and characteristics */ 1714 Status = GetDeviceInfo_UStr(NULL, DeviceHandle, &DeviceInfo); 1715 if (!NT_SUCCESS(Status)) 1716 { 1717 DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status); 1718 goto Quit; 1719 } 1720 1721 /* Ignore volumes that are NOT on usual disks */ 1722 if (DeviceInfo.DeviceType != FILE_DEVICE_DISK /*&& 1723 DeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK*/) 1724 { 1725 DPRINT1("Invalid volume; device type %lu\n", DeviceInfo.DeviceType); 1726 Status = STATUS_INVALID_DEVICE_REQUEST; 1727 goto Quit; 1728 } 1729 1730 1731 /* Check whether this is a floppy or a partitionable device */ 1732 if (DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) 1733 { 1734 /* Floppies don't have partitions */ 1735 // NOTE: See ntoskrnl/io/iomgr/rawfs.c!RawQueryFsSizeInfo() 1736 DiskNumber = ULONG_MAX; 1737 PartitionStyle = PARTITION_STYLE_MBR; 1738 IsSuperFloppy = TRUE; 1739 } 1740 else 1741 { 1742 IO_STATUS_BLOCK IoStatusBlock; 1743 STORAGE_DEVICE_NUMBER DeviceNumber; 1744 1745 /* The maximum information a DISK_GEOMETRY_EX dynamic structure can contain */ 1746 typedef struct _DISK_GEOMETRY_EX_INTERNAL 1747 { 1748 DISK_GEOMETRY Geometry; 1749 LARGE_INTEGER DiskSize; 1750 DISK_PARTITION_INFO Partition; 1751 /* Followed by: DISK_DETECTION_INFO Detection; unused here */ 1752 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL; 1753 1754 DISK_GEOMETRY_EX_INTERNAL DiskGeoEx; 1755 PARTITION_INFORMATION PartitionInfo; 1756 1757 /* Retrieve the disk number. NOTE: Fails for floppy disks. */ 1758 Status = NtDeviceIoControlFile(DeviceHandle, 1759 NULL, NULL, NULL, 1760 &IoStatusBlock, 1761 IOCTL_STORAGE_GET_DEVICE_NUMBER, 1762 NULL, 0, 1763 &DeviceNumber, sizeof(DeviceNumber)); 1764 if (!NT_SUCCESS(Status)) 1765 goto Quit; /* This may be a dynamic volume, which is unsupported */ 1766 ASSERT(DeviceNumber.DeviceType == DeviceInfo.DeviceType); 1767 if (DeviceNumber.DeviceNumber == ULONG_MAX) 1768 { 1769 DPRINT1("Invalid disk number reported, bail out\n"); 1770 Status = STATUS_NOT_FOUND; 1771 goto Quit; 1772 } 1773 1774 /* Retrieve the drive geometry. NOTE: Fails for floppy disks; 1775 * use IOCTL_DISK_GET_DRIVE_GEOMETRY instead. */ 1776 Status = NtDeviceIoControlFile(DeviceHandle, 1777 NULL, NULL, NULL, 1778 &IoStatusBlock, 1779 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 1780 NULL, 0, 1781 &DiskGeoEx, 1782 sizeof(DiskGeoEx)); 1783 if (!NT_SUCCESS(Status)) 1784 { 1785 DPRINT1("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed (Status 0x%08lx)\n", Status); 1786 goto Quit; 1787 } 1788 1789 /* 1790 * Retrieve the volume's partition information. 1791 * NOTE: Fails for floppy disks. 1792 * 1793 * NOTE: We can use the non-EX IOCTL because the super-floppy test will 1794 * fail anyway if the disk is NOT MBR-partitioned. (If the disk is GPT, 1795 * the IOCTL would return only the MBR protective partition, but the 1796 * super-floppy test would fail due to the wrong partitioning style.) 1797 */ 1798 Status = NtDeviceIoControlFile(DeviceHandle, 1799 NULL, NULL, NULL, 1800 &IoStatusBlock, 1801 IOCTL_DISK_GET_PARTITION_INFO, 1802 NULL, 0, 1803 &PartitionInfo, 1804 sizeof(PartitionInfo)); 1805 if (!NT_SUCCESS(Status)) 1806 { 1807 DPRINT1("IOCTL_DISK_GET_PARTITION_INFO failed (Status 0x%08lx)\n", Status); 1808 goto Quit; 1809 } 1810 1811 DiskNumber = DeviceNumber.DeviceNumber; 1812 PartitionStyle = DiskGeoEx.Partition.PartitionStyle; 1813 IsSuperFloppy = IsDiskSuperFloppy2(&DiskGeoEx.Partition, 1814 (PULONGLONG)&DiskGeoEx.DiskSize.QuadPart, 1815 &PartitionInfo); 1816 } 1817 1818 Status = InstallBootManagerAndBootEntriesWorker( 1819 ArchType, SystemRootPath, 1820 DiskNumber, PartitionStyle, IsSuperFloppy, FileSystem, 1821 SourceRootPath, DestinationArcPath, Options); 1822 1823Quit: 1824 NtClose(DeviceHandle); 1825 return Status; 1826} 1827 1828NTSTATUS 1829NTAPI 1830InstallBootcodeToRemovable( 1831 _In_ ARCHITECTURE_TYPE ArchType, 1832 _In_ PCUNICODE_STRING RemovableRootPath, 1833 _In_ PCUNICODE_STRING SourceRootPath, 1834 _In_ PCUNICODE_STRING DestinationArcPath) 1835{ 1836 NTSTATUS Status; 1837 FILE_FS_DEVICE_INFORMATION DeviceInfo; 1838 PCWSTR FileSystemName; 1839 BOOLEAN IsFloppy; 1840 1841 /* Remove any trailing backslash if needed */ 1842 UNICODE_STRING RootDrive = *RemovableRootPath; 1843 TrimTrailingPathSeparators_UStr(&RootDrive); 1844 1845 /* Verify that the removable disk is accessible */ 1846 if (!DoesDirExist(NULL, RemovableRootPath->Buffer)) 1847 return STATUS_DEVICE_NOT_READY; 1848 1849 /* Retrieve the device type and characteristics */ 1850 Status = GetDeviceInfo_UStr(&RootDrive, NULL, &DeviceInfo); 1851 if (!NT_SUCCESS(Status)) 1852 { 1853 static const UNICODE_STRING DeviceFloppy = RTL_CONSTANT_STRING(L"\\Device\\Floppy"); 1854 1855 DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status); 1856 1857 /* Definitively fail if the device is not a floppy */ 1858 if (!RtlPrefixUnicodeString(&DeviceFloppy, &RootDrive, TRUE)) 1859 return Status; /* We cannot cope with a failure */ 1860 1861 /* Try to fall back to something "sane" if the device may be a floppy */ 1862 DeviceInfo.DeviceType = FILE_DEVICE_DISK; 1863 DeviceInfo.Characteristics = FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE; 1864 } 1865 1866 /* Ignore volumes that are NOT on usual disks */ 1867 if (DeviceInfo.DeviceType != FILE_DEVICE_DISK /*&& 1868 DeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK*/) 1869 { 1870 DPRINT1("Invalid volume; device type %lu\n", DeviceInfo.DeviceType); 1871 return STATUS_INVALID_DEVICE_REQUEST; 1872 } 1873 1874 /* Fail if the disk is not removable */ 1875 if (!(DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)) 1876 { 1877 DPRINT1("Device is NOT removable!\n"); 1878 return STATUS_INVALID_DEVICE_REQUEST; 1879 } 1880 1881 /* Check whether this is a floppy or another removable device */ 1882 IsFloppy = !!(DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE); 1883 1884 /* Use FAT32, unless the device is a floppy disk */ 1885 FileSystemName = (IsFloppy ? L"FAT" : L"FAT32"); 1886 1887 /* Format the removable disk */ 1888 Status = FormatFileSystem_UStr(&RootDrive, 1889 FileSystemName, 1890 (IsFloppy ? FMIFS_FLOPPY : FMIFS_REMOVABLE), 1891 NULL, 1892 TRUE, 1893 0, 1894 NULL); 1895 if (!NT_SUCCESS(Status)) 1896 { 1897 if (Status == STATUS_NOT_SUPPORTED) 1898 DPRINT1("%s FS non-existent on this system!\n", FileSystemName); 1899 else 1900 DPRINT1("FormatFileSystem(%s) failed (Status 0x%08lx)\n", FileSystemName, Status); 1901 return Status; 1902 } 1903 1904 /* Copy FreeLoader to the removable disk and save the boot entries */ 1905 Status = InstallBootManagerAndBootEntries(ArchType, 1906 RemovableRootPath, 1907 SourceRootPath, 1908 DestinationArcPath, 1909 2 /* Install on removable media */); 1910 if (!NT_SUCCESS(Status)) 1911 DPRINT1("InstallBootManagerAndBootEntries() failed (Status 0x%08lx)\n", Status); 1912 return Status; 1913} 1914 1915/* EOF */