1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Setup Library 4 * FILE: base/setup/lib/bootsup.c 5 * PURPOSE: Bootloader support functions 6 * PROGRAMMERS: ... 7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "precomp.h" 13 14 #include "bldrsup.h" 15 #include "filesup.h" 16 #include "partlist.h" 17 #include "bootcode.h" 18 #include "fsutil.h" 19 20 #include "setuplib.h" // HAXX for IsUnattendedSetup!! 21 22 #include "bootsup.h" 23 24 #define NDEBUG 25 #include <debug.h> 26 27 /* 28 * BIG FIXME!! 29 * =========== 30 * 31 * bootsup.c can deal with MBR code (actually it'll have at some point 32 * to share or give it to partlist.c, because when we'll support GPT disks, 33 * things will change a bit). 34 * And, bootsup.c can manage initializing / adding boot entries into NTLDR 35 * and FREELDR, and installing the latter, and saving the old MBR / boot 36 * sectors in files. 37 */ 38 39 /* FUNCTIONS ****************************************************************/ 40 41 static VOID 42 TrimTrailingPathSeparators_UStr( 43 IN OUT PUNICODE_STRING UnicodeString) 44 { 45 while (UnicodeString->Length >= sizeof(WCHAR) && 46 UnicodeString->Buffer[UnicodeString->Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 47 { 48 UnicodeString->Length -= sizeof(WCHAR); 49 } 50 } 51 52 53 static VOID 54 CreateFreeLoaderReactOSEntries( 55 IN PVOID BootStoreHandle, 56 IN PCWSTR ArcPath) 57 { 58 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 59 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 60 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 61 BOOT_STORE_OPTIONS BootOptions; 62 63 BootEntry->Version = FreeLdr; 64 BootEntry->BootFilePath = NULL; 65 66 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 67 RtlCopyMemory(Options->Signature, 68 NTOS_OPTIONS_SIGNATURE, 69 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 70 71 Options->OsLoadPath = ArcPath; 72 73 /* ReactOS */ 74 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS"); 75 BootEntry->FriendlyName = L"\"ReactOS\""; 76 Options->OsLoadOptions = NULL; // L""; 77 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS")); 78 79 /* ReactOS_Debug */ 80 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Debug"); 81 BootEntry->FriendlyName = L"\"ReactOS (Debug)\""; 82 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS"; 83 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Debug")); 84 85 #ifdef _WINKD_ 86 /* ReactOS_VBoxDebug */ 87 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_VBoxDebug"); 88 BootEntry->FriendlyName = L"\"ReactOS (VBox Debug)\""; 89 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=VBOX /SOS"; 90 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_VBoxDebug")); 91 #endif 92 #if DBG 93 #ifndef _WINKD_ 94 /* ReactOS_KdSerial */ 95 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial"); 96 BootEntry->FriendlyName = L"\"ReactOS (RosDbg)\""; 97 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /KDSERIAL"; 98 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_KdSerial")); 99 #endif 100 101 /* ReactOS_Screen */ 102 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Screen"); 103 BootEntry->FriendlyName = L"\"ReactOS (Screen)\""; 104 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=SCREEN /SOS"; 105 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Screen")); 106 107 /* ReactOS_LogFile */ 108 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_LogFile"); 109 BootEntry->FriendlyName = L"\"ReactOS (Log file)\""; 110 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=FILE /SOS"; 111 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_LogFile")); 112 113 /* ReactOS_Ram */ 114 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Ram"); 115 BootEntry->FriendlyName = L"\"ReactOS (RAM Disk)\""; 116 Options->OsLoadPath = L"ramdisk(0)\\ReactOS"; 117 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /RDPATH=reactos.img /RDIMAGEOFFSET=32256"; 118 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Ram")); 119 120 /* ReactOS_EMS */ 121 // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_EMS"); 122 BootEntry->FriendlyName = L"\"ReactOS (Emergency Management Services)\""; 123 Options->OsLoadPath = ArcPath; 124 Options->OsLoadOptions = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /redirect=com2 /redirectbaudrate=115200"; 125 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_EMS")); 126 #endif 127 128 129 #if DBG 130 if (IsUnattendedSetup) 131 { 132 /* DefaultOS=ReactOS */ 133 #ifndef _WINKD_ 134 BootOptions.CurrentBootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial"); 135 #else 136 BootOptions.CurrentBootEntryKey = MAKESTRKEY(L"ReactOS_Debug"); 137 #endif 138 } 139 else 140 #endif 141 { 142 /* DefaultOS=ReactOS */ 143 BootOptions.CurrentBootEntryKey = MAKESTRKEY(L"ReactOS"); 144 } 145 146 #if DBG 147 if (IsUnattendedSetup) 148 #endif 149 { 150 /* Timeout=0 for unattended or non debug */ 151 BootOptions.Timeout = 0; 152 } 153 #if DBG 154 else 155 { 156 /* Timeout=10 */ 157 BootOptions.Timeout = 10; 158 } 159 #endif 160 161 BootOptions.Version = FreeLdr; 162 SetBootStoreOptions(BootStoreHandle, &BootOptions, 2 | 1); 163 } 164 165 static NTSTATUS 166 CreateFreeLoaderIniForReactOS( 167 IN PCWSTR IniPath, 168 IN PCWSTR ArcPath) 169 { 170 NTSTATUS Status; 171 PVOID BootStoreHandle; 172 173 /* Initialize the INI file and create the common FreeLdr sections */ 174 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, TRUE); 175 if (!NT_SUCCESS(Status)) 176 return Status; 177 178 /* Add the ReactOS entries */ 179 CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath); 180 181 /* Close the INI file */ 182 CloseBootStore(BootStoreHandle); 183 return STATUS_SUCCESS; 184 } 185 186 static NTSTATUS 187 CreateFreeLoaderIniForReactOSAndBootSector( 188 IN PCWSTR IniPath, 189 IN PCWSTR ArcPath, 190 IN PCWSTR Section, 191 IN PCWSTR Description, 192 IN PCWSTR BootDrive, 193 IN PCWSTR BootPartition, 194 IN PCWSTR BootSector) 195 { 196 NTSTATUS Status; 197 PVOID BootStoreHandle; 198 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(BOOT_SECTOR_OPTIONS)]; 199 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 200 PBOOT_SECTOR_OPTIONS Options = (PBOOT_SECTOR_OPTIONS)&BootEntry->OsOptions; 201 202 /* Initialize the INI file and create the common FreeLdr sections */ 203 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, TRUE); 204 if (!NT_SUCCESS(Status)) 205 return Status; 206 207 /* Add the ReactOS entries */ 208 CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath); 209 210 BootEntry->Version = FreeLdr; 211 BootEntry->BootFilePath = NULL; 212 213 BootEntry->OsOptionsLength = sizeof(BOOT_SECTOR_OPTIONS); 214 RtlCopyMemory(Options->Signature, 215 BOOT_SECTOR_OPTIONS_SIGNATURE, 216 RTL_FIELD_SIZE(BOOT_SECTOR_OPTIONS, Signature)); 217 218 Options->Drive = BootDrive; 219 Options->Partition = BootPartition; 220 Options->BootSectorFileName = BootSector; 221 222 // BootEntry->BootEntryKey = MAKESTRKEY(Section); 223 BootEntry->FriendlyName = Description; 224 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Section)); 225 226 /* Close the INI file */ 227 CloseBootStore(BootStoreHandle); 228 return STATUS_SUCCESS; 229 } 230 231 // 232 // I think this function can be generalizable as: 233 // "find the corresponding 'ReactOS' boot entry in this loader config file 234 // (here abstraction comes there), and if none, add a new one". 235 // 236 237 typedef struct _ENUM_REACTOS_ENTRIES_DATA 238 { 239 ULONG i; 240 BOOLEAN UseExistingEntry; 241 PCWSTR ArcPath; 242 WCHAR SectionName[80]; 243 WCHAR OsName[80]; 244 } ENUM_REACTOS_ENTRIES_DATA, *PENUM_REACTOS_ENTRIES_DATA; 245 246 // PENUM_BOOT_ENTRIES_ROUTINE 247 static NTSTATUS 248 NTAPI 249 EnumerateReactOSEntries( 250 IN BOOT_STORE_TYPE Type, 251 IN PBOOT_STORE_ENTRY BootEntry, 252 IN PVOID Parameter OPTIONAL) 253 { 254 NTSTATUS Status; 255 PENUM_REACTOS_ENTRIES_DATA Data = (PENUM_REACTOS_ENTRIES_DATA)Parameter; 256 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 257 WCHAR SystemPath[MAX_PATH]; 258 259 /* We have a boot entry */ 260 261 /* Check for supported boot type "Windows2003" */ 262 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) || 263 RtlCompareMemory(&BootEntry->OsOptions /* Signature */, 264 NTOS_OPTIONS_SIGNATURE, 265 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) != 266 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) 267 { 268 /* This is not a ReactOS entry */ 269 // DPRINT(" An installation '%S' of unsupported type '%S'\n", 270 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a"); 271 DPRINT(" An installation '%S' of unsupported type %lu\n", 272 BootEntry->FriendlyName, BootEntry->OsOptionsLength); 273 /* Continue the enumeration */ 274 goto SkipThisEntry; 275 } 276 277 /* BootType is Windows2003, now check OsLoadPath */ 278 if (!Options->OsLoadPath || !*Options->OsLoadPath) 279 { 280 /* Certainly not a ReactOS installation */ 281 DPRINT1(" A Win2k3 install '%S' without an ARC path?!\n", BootEntry->FriendlyName); 282 /* Continue the enumeration */ 283 goto SkipThisEntry; 284 } 285 286 if (_wcsicmp(Options->OsLoadPath, Data->ArcPath) != 0) 287 { 288 /* Not found, retry with a quoted path */ 289 Status = RtlStringCchPrintfW(SystemPath, ARRAYSIZE(SystemPath), L"\"%s\"", Data->ArcPath); 290 if (!NT_SUCCESS(Status) || _wcsicmp(Options->OsLoadPath, SystemPath) != 0) 291 { 292 /* 293 * This entry is a ReactOS entry, but the SystemRoot 294 * does not match the one we are looking for. 295 */ 296 /* Continue the enumeration */ 297 goto SkipThisEntry; 298 } 299 } 300 301 DPRINT(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n", 302 BootEntry->FriendlyName, Options->OsLoadPath); 303 // DPRINT(" Found a Win2k3 install '%S' with ARC path '%S'\n", 304 // BootEntry->FriendlyName, Options->OsLoadPath); 305 306 DPRINT("EnumerateReactOSEntries: OsLoadPath: '%S'\n", Options->OsLoadPath); 307 308 Data->UseExistingEntry = TRUE; 309 RtlStringCchCopyW(Data->OsName, ARRAYSIZE(Data->OsName), BootEntry->FriendlyName); 310 311 /* We have found our entry, stop the enumeration now! */ 312 return STATUS_NO_MORE_ENTRIES; 313 314 SkipThisEntry: 315 Data->UseExistingEntry = FALSE; 316 if (Type == FreeLdr && wcscmp(Data->SectionName, (PWSTR)BootEntry->BootEntryKey)== 0) 317 { 318 RtlStringCchPrintfW(Data->SectionName, ARRAYSIZE(Data->SectionName), 319 L"ReactOS_%lu", Data->i); 320 RtlStringCchPrintfW(Data->OsName, ARRAYSIZE(Data->OsName), 321 L"\"ReactOS %lu\"", Data->i); 322 Data->i++; 323 } 324 return STATUS_SUCCESS; 325 } 326 327 static 328 NTSTATUS 329 UpdateFreeLoaderIni( 330 IN PCWSTR IniPath, 331 IN PCWSTR ArcPath) 332 { 333 NTSTATUS Status; 334 PVOID BootStoreHandle; 335 ENUM_REACTOS_ENTRIES_DATA Data; 336 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 337 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 338 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 339 340 /* Open the INI file */ 341 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, /*TRUE*/ FALSE); 342 if (!NT_SUCCESS(Status)) 343 return Status; 344 345 /* Find an existing usable or an unused section name */ 346 Data.UseExistingEntry = TRUE; 347 Data.i = 1; 348 Data.ArcPath = ArcPath; 349 RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS"); 350 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\""); 351 352 // 353 // FIXME: We temporarily use EnumerateBootStoreEntries, until 354 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented. 355 // 356 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data); 357 358 /* Create a new "ReactOS" entry if there is none already existing that suits us */ 359 if (!Data.UseExistingEntry) 360 { 361 // RtlStringCchPrintfW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS_%lu", Data.i); 362 // RtlStringCchPrintfW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS %lu\"", Data.i); 363 364 BootEntry->Version = FreeLdr; 365 BootEntry->BootFilePath = NULL; 366 367 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 368 RtlCopyMemory(Options->Signature, 369 NTOS_OPTIONS_SIGNATURE, 370 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 371 372 Options->OsLoadPath = ArcPath; 373 374 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName); 375 BootEntry->FriendlyName = Data.OsName; 376 Options->OsLoadOptions = NULL; // L""; 377 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Data.SectionName)); 378 } 379 380 /* Close the INI file */ 381 CloseBootStore(BootStoreHandle); 382 return STATUS_SUCCESS; 383 } 384 385 static 386 NTSTATUS 387 UpdateBootIni( 388 IN PCWSTR IniPath, 389 IN PCWSTR EntryName, // ~= ArcPath 390 IN PCWSTR EntryValue) 391 { 392 NTSTATUS Status; 393 PVOID BootStoreHandle; 394 ENUM_REACTOS_ENTRIES_DATA Data; 395 396 // NOTE: Technically it would be "BootSector"... 397 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 398 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 399 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 400 401 /* Open the INI file */ 402 Status = OpenBootStore(&BootStoreHandle, IniPath, NtLdr, FALSE); 403 if (!NT_SUCCESS(Status)) 404 return Status; 405 406 /* Find an existing usable or an unused section name */ 407 Data.UseExistingEntry = TRUE; 408 // Data.i = 1; 409 Data.ArcPath = EntryName; 410 // RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS"); 411 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\""); 412 413 // 414 // FIXME: We temporarily use EnumerateBootStoreEntries, until 415 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented. 416 // 417 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data); 418 419 /* If either the key was not found, or contains something else, add a new one */ 420 if (!Data.UseExistingEntry /* || 421 ( (Status == STATUS_NO_MORE_ENTRIES) && wcscmp(Data.OsName, EntryValue) ) */) 422 { 423 BootEntry->Version = NtLdr; 424 BootEntry->BootFilePath = NULL; 425 426 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 427 RtlCopyMemory(Options->Signature, 428 NTOS_OPTIONS_SIGNATURE, 429 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 430 431 Options->OsLoadPath = EntryName; 432 433 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName); 434 // BootEntry->FriendlyName = Data.OsName; 435 BootEntry->FriendlyName = EntryValue; 436 Options->OsLoadOptions = NULL; // L""; 437 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(0 /*Data.SectionName*/)); 438 } 439 440 /* Close the INI file */ 441 CloseBootStore(BootStoreHandle); 442 return STATUS_SUCCESS; // Status; 443 } 444 445 446 static 447 BOOLEAN 448 IsThereAValidBootSector( 449 IN PCWSTR RootPath) 450 { 451 /* 452 * We first demand that the bootsector has a valid signature at its end. 453 * We then check the first 3 bytes (as a ULONG) of the bootsector for a 454 * potential "valid" instruction (the BIOS starts execution of the bootsector 455 * at its beginning). Currently this criterium is that this ULONG must be 456 * non-zero. If both these tests pass, then the bootsector is valid; otherwise 457 * it is invalid and certainly needs to be overwritten. 458 */ 459 460 BOOLEAN IsValid = FALSE; 461 NTSTATUS Status; 462 UNICODE_STRING RootPartition; 463 BOOTCODE BootSector = {0}; 464 465 /* Allocate and read the root partition bootsector. 466 * Remove any trailing backslash if needed. */ 467 RtlInitUnicodeString(&RootPartition, RootPath); 468 TrimTrailingPathSeparators_UStr(&RootPartition); 469 Status = ReadBootCodeFromFile(&BootSector, &RootPartition, SECTORSIZE); 470 if (!NT_SUCCESS(Status)) 471 return FALSE; 472 473 /* Check for the existence of the bootsector signature */ 474 IsValid = (*(PUSHORT)((PUCHAR)BootSector.BootCode + 0x1FE) == 0xAA55); 475 if (IsValid) 476 { 477 /* Check for the first instruction encoded on three bytes */ 478 IsValid = (((*(PULONG)BootSector.BootCode) & 0x00FFFFFF) != 0x00000000); 479 } 480 481 /* Free the bootsector and return */ 482 FreeBootCode(&BootSector); 483 return IsValid; 484 } 485 486 static 487 NTSTATUS 488 SaveBootSector( 489 IN PCWSTR RootPath, 490 IN PCWSTR DstPath, 491 IN ULONG Length) 492 { 493 NTSTATUS Status; 494 UNICODE_STRING Name; 495 OBJECT_ATTRIBUTES ObjectAttributes; 496 IO_STATUS_BLOCK IoStatusBlock; 497 HANDLE FileHandle; 498 // LARGE_INTEGER FileOffset; 499 BOOTCODE BootSector = {0}; 500 501 /* Allocate and read the root partition bootsector. 502 * Remove any trailing backslash if needed. */ 503 RtlInitUnicodeString(&Name, RootPath); 504 TrimTrailingPathSeparators_UStr(&Name); 505 Status = ReadBootCodeFromFile(&BootSector, &Name, Length); 506 if (!NT_SUCCESS(Status)) 507 return Status; 508 509 /* Write the bootsector to DstPath */ 510 RtlInitUnicodeString(&Name, DstPath); 511 InitializeObjectAttributes(&ObjectAttributes, 512 &Name, 513 OBJ_CASE_INSENSITIVE, 514 NULL, 515 NULL); 516 517 Status = NtCreateFile(&FileHandle, 518 GENERIC_WRITE | SYNCHRONIZE, 519 &ObjectAttributes, 520 &IoStatusBlock, 521 NULL, 522 FILE_ATTRIBUTE_NORMAL, 523 0, 524 FILE_SUPERSEDE, 525 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, 526 NULL, 527 0); 528 if (!NT_SUCCESS(Status)) 529 { 530 FreeBootCode(&BootSector); 531 return Status; 532 } 533 534 Status = NtWriteFile(FileHandle, 535 NULL, 536 NULL, 537 NULL, 538 &IoStatusBlock, 539 BootSector.BootCode, 540 BootSector.Length, 541 NULL, 542 NULL); 543 NtClose(FileHandle); 544 545 /* Free the bootsector and return */ 546 FreeBootCode(&BootSector); 547 return Status; 548 } 549 550 551 static 552 NTSTATUS 553 InstallBootCodeToDisk( 554 IN PCWSTR SrcPath, 555 IN PCWSTR RootPath, 556 IN PFS_INSTALL_BOOTCODE InstallBootCode) 557 { 558 NTSTATUS Status, LockStatus; 559 UNICODE_STRING Name; 560 OBJECT_ATTRIBUTES ObjectAttributes; 561 IO_STATUS_BLOCK IoStatusBlock; 562 HANDLE PartitionHandle; 563 564 /* 565 * Open the root partition from which the bootcode (MBR, VBR) parameters 566 * will be obtained; this is also where we will write the updated bootcode. 567 * Remove any trailing backslash if needed. 568 */ 569 RtlInitUnicodeString(&Name, RootPath); 570 TrimTrailingPathSeparators_UStr(&Name); 571 572 InitializeObjectAttributes(&ObjectAttributes, 573 &Name, 574 OBJ_CASE_INSENSITIVE, 575 NULL, 576 NULL); 577 578 Status = NtOpenFile(&PartitionHandle, 579 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 580 &ObjectAttributes, 581 &IoStatusBlock, 582 FILE_SHARE_READ | FILE_SHARE_WRITE, 583 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); 584 if (!NT_SUCCESS(Status)) 585 return Status; 586 587 /* Lock the volume */ 588 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); 589 if (!NT_SUCCESS(LockStatus)) 590 { 591 DPRINT1("Unable to lock the volume before installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 592 } 593 594 /* Install the bootcode (MBR, VBR) */ 595 Status = InstallBootCode(SrcPath, PartitionHandle, PartitionHandle); 596 597 /* dismount & Unlock the volume */ 598 if (NT_SUCCESS(LockStatus)) 599 { 600 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); 601 if (!NT_SUCCESS(LockStatus)) 602 { 603 DPRINT1("Unable to dismount the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 604 } 605 606 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); 607 if (!NT_SUCCESS(LockStatus)) 608 { 609 DPRINT1("Unable to unlock the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 610 } 611 } 612 613 /* Close the partition */ 614 NtClose(PartitionHandle); 615 616 return Status; 617 } 618 619 static 620 NTSTATUS 621 InstallBootCodeToFile( 622 IN PCWSTR SrcPath, 623 IN PCWSTR DstPath, 624 IN PCWSTR RootPath, 625 IN PFS_INSTALL_BOOTCODE InstallBootCode) 626 { 627 NTSTATUS Status; 628 UNICODE_STRING Name; 629 OBJECT_ATTRIBUTES ObjectAttributes; 630 IO_STATUS_BLOCK IoStatusBlock; 631 HANDLE PartitionHandle, FileHandle; 632 633 /* 634 * Open the root partition from which the bootcode (MBR, VBR) 635 * parameters will be obtained. 636 * 637 * FIXME? It might be possible that we need to also open it for writing 638 * access in case we really need to still write the second portion of 639 * the boot sector ???? 640 * 641 * Remove any trailing backslash if needed. 642 */ 643 RtlInitUnicodeString(&Name, RootPath); 644 TrimTrailingPathSeparators_UStr(&Name); 645 646 InitializeObjectAttributes(&ObjectAttributes, 647 &Name, 648 OBJ_CASE_INSENSITIVE, 649 NULL, 650 NULL); 651 652 Status = NtOpenFile(&PartitionHandle, 653 GENERIC_READ | SYNCHRONIZE, 654 &ObjectAttributes, 655 &IoStatusBlock, 656 FILE_SHARE_READ | FILE_SHARE_WRITE, 657 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); 658 if (!NT_SUCCESS(Status)) 659 return Status; 660 661 /* Open or create the file where the new bootsector will be saved */ 662 RtlInitUnicodeString(&Name, DstPath); 663 InitializeObjectAttributes(&ObjectAttributes, 664 &Name, 665 OBJ_CASE_INSENSITIVE, 666 NULL, 667 NULL); 668 669 Status = NtCreateFile(&FileHandle, 670 GENERIC_WRITE | SYNCHRONIZE, 671 &ObjectAttributes, 672 &IoStatusBlock, 673 NULL, 674 FILE_ATTRIBUTE_NORMAL, 675 0, 676 FILE_SUPERSEDE, // FILE_OVERWRITE_IF 677 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, 678 NULL, 679 0); 680 if (!NT_SUCCESS(Status)) 681 { 682 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status); 683 NtClose(PartitionHandle); 684 return Status; 685 } 686 687 /* Install the bootcode (MBR, VBR) */ 688 Status = InstallBootCode(SrcPath, FileHandle, PartitionHandle); 689 690 /* Close the file and the partition */ 691 NtClose(FileHandle); 692 NtClose(PartitionHandle); 693 694 return Status; 695 } 696 697 698 static 699 NTSTATUS 700 InstallMbrBootCode( 701 IN PCWSTR SrcPath, // MBR source file (on the installation medium) 702 IN HANDLE DstPath, // Where to save the bootsector built from the source + disk information 703 IN HANDLE DiskHandle) // Disk holding the (old) MBR information 704 { 705 NTSTATUS Status; 706 UNICODE_STRING Name; 707 IO_STATUS_BLOCK IoStatusBlock; 708 LARGE_INTEGER FileOffset; 709 BOOTCODE OrigBootSector = {0}; 710 BOOTCODE NewBootSector = {0}; 711 712 C_ASSERT(sizeof(PARTITION_SECTOR) == SECTORSIZE); 713 714 /* Allocate and read the current original MBR bootsector */ 715 Status = ReadBootCodeByHandle(&OrigBootSector, 716 DiskHandle, 717 sizeof(PARTITION_SECTOR)); 718 if (!NT_SUCCESS(Status)) 719 return Status; 720 721 /* Allocate and read the new bootsector from SrcPath */ 722 RtlInitUnicodeString(&Name, SrcPath); 723 Status = ReadBootCodeFromFile(&NewBootSector, 724 &Name, 725 sizeof(PARTITION_SECTOR)); 726 if (!NT_SUCCESS(Status)) 727 { 728 FreeBootCode(&OrigBootSector); 729 return Status; 730 } 731 732 /* 733 * Copy the disk signature, the reserved fields and 734 * the partition table from the old MBR to the new one. 735 */ 736 RtlCopyMemory(&((PPARTITION_SECTOR)NewBootSector.BootCode)->Signature, 737 &((PPARTITION_SECTOR)OrigBootSector.BootCode)->Signature, 738 sizeof(PARTITION_SECTOR) - 739 FIELD_OFFSET(PARTITION_SECTOR, Signature) 740 /* Length of partition table */); 741 742 /* Free the original bootsector */ 743 FreeBootCode(&OrigBootSector); 744 745 /* Write the new bootsector to DstPath */ 746 FileOffset.QuadPart = 0ULL; 747 Status = NtWriteFile(DstPath, 748 NULL, 749 NULL, 750 NULL, 751 &IoStatusBlock, 752 NewBootSector.BootCode, 753 NewBootSector.Length, 754 &FileOffset, 755 NULL); 756 757 /* Free the new bootsector */ 758 FreeBootCode(&NewBootSector); 759 760 return Status; 761 } 762 763 NTSTATUS 764 InstallMbrBootCodeToDisk( 765 IN PUNICODE_STRING SystemRootPath, 766 IN PUNICODE_STRING SourceRootPath, 767 IN PCWSTR DestinationDevicePathBuffer) 768 { 769 NTSTATUS Status; 770 WCHAR SourceMbrPathBuffer[MAX_PATH]; 771 WCHAR DstPath[MAX_PATH]; 772 773 #if 0 774 /* 775 * The DestinationDevicePathBuffer parameter has been built with 776 * the following instruction by the caller; I'm not yet sure whether 777 * I actually want this function to build the path instead, hence 778 * I keep this code here but disabled for now... 779 */ 780 WCHAR DestinationDevicePathBuffer[MAX_PATH]; 781 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer), 782 L"\\Device\\Harddisk%d\\Partition0", 783 DiskNumber); 784 #endif 785 786 CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, 787 SourceRootPath->Buffer, L"\\loader\\dosmbr.bin"); 788 789 if (IsThereAValidBootSector(DestinationDevicePathBuffer)) 790 { 791 /* Save current MBR */ 792 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, 793 SystemRootPath->Buffer, L"mbr.old"); 794 795 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath); 796 Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR)); 797 if (!NT_SUCCESS(Status)) 798 { 799 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 800 // Don't care if we succeeded or not saving the old MBR, just go ahead. 801 } 802 } 803 804 DPRINT1("Install MBR bootcode: %S ==> %S\n", 805 SourceMbrPathBuffer, DestinationDevicePathBuffer); 806 807 /* Install the MBR */ 808 return InstallBootCodeToDisk(SourceMbrPathBuffer, 809 DestinationDevicePathBuffer, 810 InstallMbrBootCode); 811 } 812 813 814 static 815 NTSTATUS 816 InstallFatBootcodeToPartition( 817 IN PUNICODE_STRING SystemRootPath, 818 IN PUNICODE_STRING SourceRootPath, 819 IN PUNICODE_STRING DestinationArcPath, 820 IN PCWSTR FileSystemName) 821 { 822 NTSTATUS Status; 823 BOOLEAN DoesFreeLdrExist; 824 WCHAR SrcPath[MAX_PATH]; 825 WCHAR DstPath[MAX_PATH]; 826 827 /* FAT or FAT32 partition */ 828 DPRINT("System path: '%wZ'\n", SystemRootPath); 829 830 /* Copy FreeLoader to the system partition, always overwriting the older version */ 831 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 832 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); 833 834 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 835 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 836 if (!NT_SUCCESS(Status)) 837 { 838 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 839 return Status; 840 } 841 842 /* Prepare for possibly updating 'freeldr.ini' */ 843 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 844 if (DoesFreeLdrExist) 845 { 846 /* Update existing 'freeldr.ini' */ 847 DPRINT1("Update existing 'freeldr.ini'\n"); 848 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 849 if (!NT_SUCCESS(Status)) 850 { 851 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 852 return Status; 853 } 854 } 855 856 /* Check for NT and other bootloaders */ 857 858 // FIXME: Check for Vista+ bootloader! 859 /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/ 860 /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/ 861 if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE || 862 DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE) 863 { 864 /* Search root directory for 'NTLDR' and 'BOOT.INI' */ 865 DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n"); 866 867 /* Create or update 'freeldr.ini' */ 868 if (DoesFreeLdrExist == FALSE) 869 { 870 /* Create new 'freeldr.ini' */ 871 DPRINT1("Create new 'freeldr.ini'\n"); 872 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 873 if (!NT_SUCCESS(Status)) 874 { 875 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 876 return Status; 877 } 878 879 /* Install new bootcode into a file */ 880 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"bootsect.ros"); 881 882 if (wcsicmp(FileSystemName, L"FAT32") == 0) 883 { 884 /* Install FAT32 bootcode */ 885 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin"); 886 887 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath); 888 Status = InstallBootCodeToFile(SrcPath, DstPath, 889 SystemRootPath->Buffer, 890 InstallFat32BootCode); 891 if (!NT_SUCCESS(Status)) 892 { 893 DPRINT1("InstallBootCodeToFile(FAT32) failed (Status %lx)\n", Status); 894 return Status; 895 } 896 } 897 else // if (wcsicmp(FileSystemName, L"FAT") == 0) 898 { 899 /* Install FAT16 bootcode */ 900 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 901 902 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, DstPath); 903 Status = InstallBootCodeToFile(SrcPath, DstPath, 904 SystemRootPath->Buffer, 905 InstallFat16BootCode); 906 if (!NT_SUCCESS(Status)) 907 { 908 DPRINT1("InstallBootCodeToFile(FAT16) failed (Status %lx)\n", Status); 909 return Status; 910 } 911 } 912 } 913 914 /* Update 'boot.ini' */ 915 /* Windows' NTLDR loads an external bootsector file when the specified drive 916 letter is C:, otherwise it will interpret it as a boot DOS path specifier. */ 917 DPRINT1("Update 'boot.ini'\n"); 918 Status = UpdateBootIni(SystemRootPath->Buffer, 919 L"C:\\bootsect.ros", 920 L"\"ReactOS\""); 921 if (!NT_SUCCESS(Status)) 922 { 923 DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status); 924 return Status; 925 } 926 } 927 else 928 { 929 /* Non-NT bootloaders: install our own bootloader */ 930 931 PCWSTR Section; 932 PCWSTR Description; 933 PCWSTR BootDrive; 934 PCWSTR BootPartition; 935 PCWSTR BootSector; 936 937 /* Search for COMPAQ MS-DOS 1.x (1.11, 1.12, based on MS-DOS 1.25) boot loader */ 938 if (DoesFileExist_2(SystemRootPath->Buffer, L"IOSYS.COM") == TRUE || 939 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.COM") == TRUE) 940 { 941 DPRINT1("Found COMPAQ MS-DOS 1.x (1.11, 1.12) / MS-DOS 1.25 boot loader\n"); 942 943 Section = L"CPQDOS"; 944 Description = L"\"COMPAQ MS-DOS 1.x / MS-DOS 1.25\""; 945 BootDrive = L"hd0"; 946 BootPartition = L"1"; 947 BootSector = L"BOOTSECT.DOS"; 948 } 949 else 950 /* Search for Microsoft DOS or Windows 9x boot loader */ 951 if (DoesFileExist_2(SystemRootPath->Buffer, L"IO.SYS") == TRUE || 952 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.SYS") == TRUE) 953 // WINBOOT.SYS 954 { 955 DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n"); 956 957 Section = L"MSDOS"; 958 Description = L"\"MS-DOS/Windows\""; 959 BootDrive = L"hd0"; 960 BootPartition = L"1"; 961 BootSector = L"BOOTSECT.DOS"; 962 } 963 else 964 /* Search for IBM PC-DOS or DR-DOS 5.x boot loader */ 965 if (DoesFileExist_2(SystemRootPath->Buffer, L"IBMIO.COM" ) == TRUE || // Some people refer to this file instead of IBMBIO.COM... 966 DoesFileExist_2(SystemRootPath->Buffer, L"IBMBIO.COM") == TRUE || 967 DoesFileExist_2(SystemRootPath->Buffer, L"IBMDOS.COM") == TRUE) 968 { 969 DPRINT1("Found IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\n"); 970 971 Section = L"IBMDOS"; 972 Description = L"\"IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\""; 973 BootDrive = L"hd0"; 974 BootPartition = L"1"; 975 BootSector = L"BOOTSECT.DOS"; 976 } 977 else 978 /* Search for DR-DOS 3.x boot loader */ 979 if (DoesFileExist_2(SystemRootPath->Buffer, L"DRBIOS.SYS") == TRUE || 980 DoesFileExist_2(SystemRootPath->Buffer, L"DRBDOS.SYS") == TRUE) 981 { 982 DPRINT1("Found DR-DOS 3.x\n"); 983 984 Section = L"DRDOS"; 985 Description = L"\"DR-DOS 3.x\""; 986 BootDrive = L"hd0"; 987 BootPartition = L"1"; 988 BootSector = L"BOOTSECT.DOS"; 989 } 990 else 991 /* Search for Dell Real-Mode Kernel (DRMK) OS */ 992 if (DoesFileExist_2(SystemRootPath->Buffer, L"DELLBIO.BIN") == TRUE || 993 DoesFileExist_2(SystemRootPath->Buffer, L"DELLRMK.BIN") == TRUE) 994 { 995 DPRINT1("Found Dell Real-Mode Kernel OS\n"); 996 997 Section = L"DRMK"; 998 Description = L"\"Dell Real-Mode Kernel OS\""; 999 BootDrive = L"hd0"; 1000 BootPartition = L"1"; 1001 BootSector = L"BOOTSECT.DOS"; 1002 } 1003 else 1004 /* Search for MS OS/2 1.x */ 1005 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT.COM") == TRUE || 1006 DoesFileExist_2(SystemRootPath->Buffer, L"OS2BIO.COM" ) == TRUE || 1007 DoesFileExist_2(SystemRootPath->Buffer, L"OS2DOS.COM" ) == TRUE) 1008 { 1009 DPRINT1("Found MS OS/2 1.x\n"); 1010 1011 Section = L"MSOS2"; 1012 Description = L"\"MS OS/2 1.x\""; 1013 BootDrive = L"hd0"; 1014 BootPartition = L"1"; 1015 BootSector = L"BOOTSECT.OS2"; 1016 } 1017 else 1018 /* Search for MS or IBM OS/2 */ 1019 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT") == TRUE || 1020 DoesFileExist_2(SystemRootPath->Buffer, L"OS2LDR" ) == TRUE || 1021 DoesFileExist_2(SystemRootPath->Buffer, L"OS2KRNL") == TRUE) 1022 { 1023 DPRINT1("Found MS/IBM OS/2\n"); 1024 1025 Section = L"IBMOS2"; 1026 Description = L"\"MS/IBM OS/2\""; 1027 BootDrive = L"hd0"; 1028 BootPartition = L"1"; 1029 BootSector = L"BOOTSECT.OS2"; 1030 } 1031 else 1032 /* Search for FreeDOS boot loader */ 1033 if (DoesFileExist_2(SystemRootPath->Buffer, L"kernel.sys") == TRUE) 1034 { 1035 DPRINT1("Found FreeDOS boot loader\n"); 1036 1037 Section = L"FDOS"; 1038 Description = L"\"FreeDOS\""; 1039 BootDrive = L"hd0"; 1040 BootPartition = L"1"; 1041 BootSector = L"BOOTSECT.DOS"; 1042 } 1043 else 1044 { 1045 /* No or unknown boot loader */ 1046 DPRINT1("No or unknown boot loader found\n"); 1047 1048 Section = L"Unknown"; 1049 Description = L"\"Unknown Operating System\""; 1050 BootDrive = L"hd0"; 1051 BootPartition = L"1"; 1052 BootSector = L"BOOTSECT.OLD"; 1053 } 1054 1055 /* Create or update 'freeldr.ini' */ 1056 if (DoesFreeLdrExist == FALSE) 1057 { 1058 /* Create new 'freeldr.ini' */ 1059 DPRINT1("Create new 'freeldr.ini'\n"); 1060 1061 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1062 { 1063 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1064 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1065 Section, Description, 1066 BootDrive, BootPartition, BootSector); 1067 if (!NT_SUCCESS(Status)) 1068 { 1069 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1070 return Status; 1071 } 1072 1073 /* Save current bootsector */ 1074 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1075 1076 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1077 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE); 1078 if (!NT_SUCCESS(Status)) 1079 { 1080 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1081 return Status; 1082 } 1083 } 1084 else 1085 { 1086 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1087 if (!NT_SUCCESS(Status)) 1088 { 1089 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1090 return Status; 1091 } 1092 } 1093 1094 /* Install new bootsector on the disk */ 1095 if (wcsicmp(FileSystemName, L"FAT32") == 0) 1096 { 1097 /* Install FAT32 bootcode */ 1098 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin"); 1099 1100 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1101 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat32BootCode); 1102 DPRINT1("Status: 0x%08X\n", Status); 1103 if (!NT_SUCCESS(Status)) 1104 { 1105 DPRINT1("InstallBootCodeToDisk(FAT32) failed (Status %lx)\n", Status); 1106 return Status; 1107 } 1108 } 1109 else // if (wcsicmp(FileSystemName, L"FAT") == 0) 1110 { 1111 /* Install FAT16 bootcode */ 1112 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1113 1114 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1115 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat16BootCode); 1116 if (!NT_SUCCESS(Status)) 1117 { 1118 DPRINT1("InstallBootCodeToDisk(FAT16) failed (Status %lx)\n", Status); 1119 return Status; 1120 } 1121 } 1122 } 1123 } 1124 1125 return STATUS_SUCCESS; 1126 } 1127 1128 static 1129 NTSTATUS 1130 InstallBtrfsBootcodeToPartition( 1131 IN PUNICODE_STRING SystemRootPath, 1132 IN PUNICODE_STRING SourceRootPath, 1133 IN PUNICODE_STRING DestinationArcPath) 1134 { 1135 NTSTATUS Status; 1136 BOOLEAN DoesFreeLdrExist; 1137 WCHAR SrcPath[MAX_PATH]; 1138 WCHAR DstPath[MAX_PATH]; 1139 1140 /* BTRFS partition */ 1141 DPRINT("System path: '%wZ'\n", SystemRootPath); 1142 1143 /* Copy FreeLoader to the system partition, always overwriting the older version */ 1144 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 1145 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); 1146 1147 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 1148 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 1149 if (!NT_SUCCESS(Status)) 1150 { 1151 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 1152 return Status; 1153 } 1154 1155 /* Prepare for possibly updating 'freeldr.ini' */ 1156 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 1157 if (DoesFreeLdrExist) 1158 { 1159 /* Update existing 'freeldr.ini' */ 1160 DPRINT1("Update existing 'freeldr.ini'\n"); 1161 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1162 if (!NT_SUCCESS(Status)) 1163 { 1164 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 1165 return Status; 1166 } 1167 } 1168 1169 /* Check for *nix bootloaders */ 1170 1171 /* Create or update 'freeldr.ini' */ 1172 if (DoesFreeLdrExist == FALSE) 1173 { 1174 /* Create new 'freeldr.ini' */ 1175 DPRINT1("Create new 'freeldr.ini'\n"); 1176 1177 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */ 1178 DPRINT1("*nix or unknown boot loader found\n"); 1179 1180 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1181 { 1182 PCWSTR BootSector = L"BOOTSECT.OLD"; 1183 1184 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1185 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1186 L"Linux", L"\"Linux\"", 1187 L"hd0", L"1", BootSector); 1188 if (!NT_SUCCESS(Status)) 1189 { 1190 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1191 return Status; 1192 } 1193 1194 /* Save current bootsector */ 1195 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1196 1197 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1198 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, BTRFS_BOOTSECTOR_SIZE); 1199 if (!NT_SUCCESS(Status)) 1200 { 1201 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1202 return Status; 1203 } 1204 } 1205 else 1206 { 1207 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1208 if (!NT_SUCCESS(Status)) 1209 { 1210 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1211 return Status; 1212 } 1213 } 1214 1215 /* Install new bootsector on the disk */ 1216 /* Install BTRFS bootcode */ 1217 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin"); 1218 1219 DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1220 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallBtrfsBootCode); 1221 if (!NT_SUCCESS(Status)) 1222 { 1223 DPRINT1("InstallBootCodeToDisk(BTRFS) failed (Status %lx)\n", Status); 1224 return Status; 1225 } 1226 } 1227 1228 return STATUS_SUCCESS; 1229 } 1230 1231 1232 NTSTATUS 1233 InstallVBRToPartition( 1234 IN PUNICODE_STRING SystemRootPath, 1235 IN PUNICODE_STRING SourceRootPath, 1236 IN PUNICODE_STRING DestinationArcPath, 1237 IN PCWSTR FileSystemName) 1238 { 1239 if (wcsicmp(FileSystemName, L"FAT") == 0 || 1240 wcsicmp(FileSystemName, L"FAT32") == 0) 1241 { 1242 return InstallFatBootcodeToPartition(SystemRootPath, 1243 SourceRootPath, 1244 DestinationArcPath, 1245 FileSystemName); 1246 } 1247 /* 1248 else if (wcsicmp(FileSystemName, L"NTFS") == 0) 1249 { 1250 DPRINT1("Partitions of type NTFS or HPFS are not supported yet!\n"); 1251 return STATUS_NOT_SUPPORTED; 1252 } 1253 */ 1254 else if (wcsicmp(FileSystemName, L"BTRFS") == 0) 1255 { 1256 return InstallBtrfsBootcodeToPartition(SystemRootPath, 1257 SourceRootPath, 1258 DestinationArcPath); 1259 } 1260 /* 1261 else if (wcsicmp(FileSystemName, L"EXT2") == 0 || 1262 wcsicmp(FileSystemName, L"EXT3") == 0 || 1263 wcsicmp(FileSystemName, L"EXT4") == 0) 1264 { 1265 return STATUS_NOT_SUPPORTED; 1266 } 1267 */ 1268 else 1269 { 1270 /* Unknown file system */ 1271 DPRINT1("Unknown file system '%S'\n", FileSystemName); 1272 } 1273 1274 return STATUS_NOT_SUPPORTED; 1275 } 1276 1277 1278 NTSTATUS 1279 InstallFatBootcodeToFloppy( 1280 IN PUNICODE_STRING SourceRootPath, 1281 IN PUNICODE_STRING DestinationArcPath) 1282 { 1283 static const PCWSTR FloppyDevice = L"\\Device\\Floppy0\\"; 1284 1285 NTSTATUS Status; 1286 WCHAR SrcPath[MAX_PATH]; 1287 WCHAR DstPath[MAX_PATH]; 1288 1289 /* Verify that the floppy disk is accessible */ 1290 if (DoesDirExist(NULL, FloppyDevice) == FALSE) 1291 return STATUS_DEVICE_NOT_READY; 1292 1293 /* Format the floppy disk */ 1294 // FormatPartition(...) 1295 Status = FormatFileSystem(FloppyDevice, 1296 L"FAT", 1297 FMIFS_FLOPPY, 1298 NULL, 1299 TRUE, 1300 0, 1301 NULL); 1302 if (!NT_SUCCESS(Status)) 1303 { 1304 if (Status == STATUS_NOT_SUPPORTED) 1305 DPRINT1("FAT FS non existent on this system?!\n"); 1306 else 1307 DPRINT1("VfatFormat() failed (Status %lx)\n", Status); 1308 1309 return Status; 1310 } 1311 1312 /* Copy FreeLoader to the boot partition */ 1313 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 1314 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice, L"freeldr.sys"); 1315 1316 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 1317 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 1318 if (!NT_SUCCESS(Status)) 1319 { 1320 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 1321 return Status; 1322 } 1323 1324 /* Create new 'freeldr.ini' */ 1325 DPRINT("Create new 'freeldr.ini'\n"); 1326 Status = CreateFreeLoaderIniForReactOS(FloppyDevice, DestinationArcPath->Buffer); 1327 if (!NT_SUCCESS(Status)) 1328 { 1329 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1330 return Status; 1331 } 1332 1333 /* Install FAT12 boosector */ 1334 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1335 CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice); 1336 1337 DPRINT("Install FAT12 bootcode: %S ==> %S\n", SrcPath, DstPath); 1338 Status = InstallBootCodeToDisk(SrcPath, DstPath, InstallFat12BootCode); 1339 if (!NT_SUCCESS(Status)) 1340 { 1341 DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status %lx)\n", Status); 1342 return Status; 1343 } 1344 1345 return STATUS_SUCCESS; 1346 } 1347 1348 /* EOF */ 1349