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