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 = L"/FASTDETECT"; 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 /* DefaultOS=ReactOS */ 130 #if DBG && !defined(_WINKD_) 131 if (IsUnattendedSetup) 132 { 133 BootOptions.NextBootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial"); 134 } 135 else 136 #endif 137 { 138 #if DBG 139 BootOptions.NextBootEntryKey = MAKESTRKEY(L"ReactOS_Debug"); 140 #else 141 BootOptions.NextBootEntryKey = MAKESTRKEY(L"ReactOS"); 142 #endif 143 } 144 145 #if DBG 146 if (IsUnattendedSetup) 147 #endif 148 { 149 /* Timeout=0 for unattended or non debug */ 150 BootOptions.Timeout = 0; 151 } 152 #if DBG 153 else 154 { 155 /* Timeout=10 */ 156 BootOptions.Timeout = 10; 157 } 158 #endif 159 160 SetBootStoreOptions(BootStoreHandle, &BootOptions, 161 BOOT_OPTIONS_TIMEOUT | BOOT_OPTIONS_NEXT_BOOTENTRY_KEY); 162 } 163 164 static NTSTATUS 165 CreateFreeLoaderIniForReactOS( 166 IN PCWSTR IniPath, 167 IN PCWSTR ArcPath) 168 { 169 NTSTATUS Status; 170 PVOID BootStoreHandle; 171 172 /* Initialize the INI file and create the common FreeLdr sections */ 173 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, 174 BS_CreateAlways /* BS_OpenAlways */, BS_ReadWriteAccess); 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 BootPath, 193 IN PCWSTR BootSector) 194 { 195 NTSTATUS Status; 196 PVOID BootStoreHandle; 197 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(BOOTSECTOR_OPTIONS)]; 198 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 199 PBOOTSECTOR_OPTIONS Options = (PBOOTSECTOR_OPTIONS)&BootEntry->OsOptions; 200 WCHAR BootPathBuffer[MAX_PATH] = L""; 201 202 /* Since the BootPath given here is in NT format 203 * (not ARC), we need to hack-generate a mapping */ 204 ULONG DiskNumber = 0, PartitionNumber = 0; 205 PCWSTR PathComponent = NULL; 206 207 /* From the NT path, compute the disk, partition and path components */ 208 // NOTE: this function doesn't support stuff like \Device\FloppyX ... 209 if (NtPathToDiskPartComponents(BootPath, &DiskNumber, &PartitionNumber, &PathComponent)) 210 { 211 DPRINT1("BootPath = '%S' points to disk #%d, partition #%d, path '%S'\n", 212 BootPath, DiskNumber, PartitionNumber, PathComponent); 213 214 /* HACK-build a possible ARC path: 215 * Hard disk path: multi(0)disk(0)rdisk(x)partition(y)[\path] */ 216 RtlStringCchPrintfW(BootPathBuffer, _countof(BootPathBuffer), 217 L"multi(0)disk(0)rdisk(%lu)partition(%lu)", 218 DiskNumber, PartitionNumber); 219 if (PathComponent && *PathComponent && 220 (PathComponent[0] != L'\\' || PathComponent[1])) 221 { 222 RtlStringCchCatW(BootPathBuffer, _countof(BootPathBuffer), 223 PathComponent); 224 } 225 } 226 else 227 { 228 PCWSTR Path = BootPath; 229 230 if ((_wcsnicmp(Path, L"\\Device\\Floppy", 14) == 0) && 231 (Path += 14) && iswdigit(*Path)) 232 { 233 DiskNumber = wcstoul(Path, (PWSTR*)&PathComponent, 10); 234 if (PathComponent && *PathComponent && *PathComponent != L'\\') 235 PathComponent = NULL; 236 237 /* HACK-build a possible ARC path: 238 * Floppy disk path: multi(0)disk(0)fdisk(x)[\path] */ 239 RtlStringCchPrintfW(BootPathBuffer, _countof(BootPathBuffer), 240 L"multi(0)disk(0)fdisk(%lu)", DiskNumber); 241 if (PathComponent && *PathComponent && 242 (PathComponent[0] != L'\\' || PathComponent[1])) 243 { 244 RtlStringCchCatW(BootPathBuffer, _countof(BootPathBuffer), 245 PathComponent); 246 } 247 } 248 else 249 { 250 /* HACK: Just keep the unresolved NT path and hope for the best... */ 251 252 /* Remove any trailing backslash if needed */ 253 UNICODE_STRING RootPartition; 254 RtlInitUnicodeString(&RootPartition, BootPath); 255 TrimTrailingPathSeparators_UStr(&RootPartition); 256 257 /* RootPartition is BootPath without counting any trailing 258 * path separator. Because of this, we need to copy the string 259 * in the buffer, instead of just using a pointer to it. */ 260 RtlStringCchPrintfW(BootPathBuffer, _countof(BootPathBuffer), 261 L"%wZ", &RootPartition); 262 263 DPRINT1("Unhandled NT path '%S'\n", BootPath); 264 } 265 } 266 267 /* Initialize the INI file and create the common FreeLdr sections */ 268 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, 269 BS_CreateAlways /* BS_OpenAlways */, BS_ReadWriteAccess); 270 if (!NT_SUCCESS(Status)) 271 return Status; 272 273 /* Add the ReactOS entries */ 274 CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath); 275 276 BootEntry->Version = FreeLdr; 277 BootEntry->BootFilePath = NULL; 278 279 BootEntry->OsOptionsLength = sizeof(BOOTSECTOR_OPTIONS); 280 RtlCopyMemory(Options->Signature, 281 BOOTSECTOR_OPTIONS_SIGNATURE, 282 RTL_FIELD_SIZE(BOOTSECTOR_OPTIONS, Signature)); 283 284 Options->BootPath = BootPathBuffer; 285 Options->FileName = BootSector; 286 287 // BootEntry->BootEntryKey = MAKESTRKEY(Section); 288 BootEntry->FriendlyName = Description; 289 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Section)); 290 291 /* Close the INI file */ 292 CloseBootStore(BootStoreHandle); 293 return STATUS_SUCCESS; 294 } 295 296 // 297 // I think this function can be generalizable as: 298 // "find the corresponding 'ReactOS' boot entry in this loader config file 299 // (here abstraction comes there), and if none, add a new one". 300 // 301 302 typedef struct _ENUM_REACTOS_ENTRIES_DATA 303 { 304 ULONG i; 305 BOOLEAN UseExistingEntry; 306 PCWSTR ArcPath; 307 WCHAR SectionName[80]; 308 WCHAR OsName[80]; 309 } ENUM_REACTOS_ENTRIES_DATA, *PENUM_REACTOS_ENTRIES_DATA; 310 311 // PENUM_BOOT_ENTRIES_ROUTINE 312 static NTSTATUS 313 NTAPI 314 EnumerateReactOSEntries( 315 IN BOOT_STORE_TYPE Type, 316 IN PBOOT_STORE_ENTRY BootEntry, 317 IN PVOID Parameter OPTIONAL) 318 { 319 NTSTATUS Status; 320 PENUM_REACTOS_ENTRIES_DATA Data = (PENUM_REACTOS_ENTRIES_DATA)Parameter; 321 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 322 WCHAR SystemPath[MAX_PATH]; 323 324 /* We have a boot entry */ 325 326 /* Check for supported boot type "Windows2003" */ 327 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) || 328 RtlCompareMemory(&BootEntry->OsOptions /* Signature */, 329 NTOS_OPTIONS_SIGNATURE, 330 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) != 331 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) 332 { 333 /* This is not a ReactOS entry */ 334 // DPRINT(" An installation '%S' of unsupported type '%S'\n", 335 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a"); 336 DPRINT(" An installation '%S' of unsupported type %lu\n", 337 BootEntry->FriendlyName, BootEntry->OsOptionsLength); 338 /* Continue the enumeration */ 339 goto SkipThisEntry; 340 } 341 342 /* BootType is Windows2003, now check OsLoadPath */ 343 if (!Options->OsLoadPath || !*Options->OsLoadPath) 344 { 345 /* Certainly not a ReactOS installation */ 346 DPRINT1(" A Win2k3 install '%S' without an ARC path?!\n", BootEntry->FriendlyName); 347 /* Continue the enumeration */ 348 goto SkipThisEntry; 349 } 350 351 if (_wcsicmp(Options->OsLoadPath, Data->ArcPath) != 0) 352 { 353 /* Not found, retry with a quoted path */ 354 Status = RtlStringCchPrintfW(SystemPath, ARRAYSIZE(SystemPath), L"\"%s\"", Data->ArcPath); 355 if (!NT_SUCCESS(Status) || _wcsicmp(Options->OsLoadPath, SystemPath) != 0) 356 { 357 /* 358 * This entry is a ReactOS entry, but the SystemRoot 359 * does not match the one we are looking for. 360 */ 361 /* Continue the enumeration */ 362 goto SkipThisEntry; 363 } 364 } 365 366 DPRINT(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n", 367 BootEntry->FriendlyName, Options->OsLoadPath); 368 // DPRINT(" Found a Win2k3 install '%S' with ARC path '%S'\n", 369 // BootEntry->FriendlyName, Options->OsLoadPath); 370 371 DPRINT("EnumerateReactOSEntries: OsLoadPath: '%S'\n", Options->OsLoadPath); 372 373 Data->UseExistingEntry = TRUE; 374 RtlStringCchCopyW(Data->OsName, ARRAYSIZE(Data->OsName), BootEntry->FriendlyName); 375 376 /* We have found our entry, stop the enumeration now! */ 377 return STATUS_NO_MORE_ENTRIES; 378 379 SkipThisEntry: 380 Data->UseExistingEntry = FALSE; 381 if (Type == FreeLdr && wcscmp(Data->SectionName, (PWSTR)BootEntry->BootEntryKey)== 0) 382 { 383 RtlStringCchPrintfW(Data->SectionName, ARRAYSIZE(Data->SectionName), 384 L"ReactOS_%lu", Data->i); 385 RtlStringCchPrintfW(Data->OsName, ARRAYSIZE(Data->OsName), 386 L"\"ReactOS %lu\"", Data->i); 387 Data->i++; 388 } 389 return STATUS_SUCCESS; 390 } 391 392 static 393 NTSTATUS 394 UpdateFreeLoaderIni( 395 IN PCWSTR IniPath, 396 IN PCWSTR ArcPath) 397 { 398 NTSTATUS Status; 399 PVOID BootStoreHandle; 400 ENUM_REACTOS_ENTRIES_DATA Data; 401 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 402 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 403 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 404 405 /* Open the INI file */ 406 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, 407 BS_OpenExisting /* BS_OpenAlways */, BS_ReadWriteAccess); 408 if (!NT_SUCCESS(Status)) 409 return Status; 410 411 /* Find an existing usable or an unused section name */ 412 Data.UseExistingEntry = TRUE; 413 Data.i = 1; 414 Data.ArcPath = ArcPath; 415 RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS"); 416 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\""); 417 418 // 419 // FIXME: We temporarily use EnumerateBootStoreEntries, until 420 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented. 421 // 422 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data); 423 424 /* Create a new "ReactOS" entry if there is none already existing that suits us */ 425 if (!Data.UseExistingEntry) 426 { 427 // RtlStringCchPrintfW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS_%lu", Data.i); 428 // RtlStringCchPrintfW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS %lu\"", Data.i); 429 430 BootEntry->Version = FreeLdr; 431 BootEntry->BootFilePath = NULL; 432 433 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 434 RtlCopyMemory(Options->Signature, 435 NTOS_OPTIONS_SIGNATURE, 436 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 437 438 Options->OsLoadPath = ArcPath; 439 440 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName); 441 BootEntry->FriendlyName = Data.OsName; 442 Options->OsLoadOptions = NULL; // L""; 443 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Data.SectionName)); 444 } 445 446 /* Close the INI file */ 447 CloseBootStore(BootStoreHandle); 448 return STATUS_SUCCESS; 449 } 450 451 static 452 NTSTATUS 453 UpdateBootIni( 454 IN PCWSTR IniPath, 455 IN PCWSTR EntryName, // ~= ArcPath 456 IN PCWSTR EntryValue) 457 { 458 NTSTATUS Status; 459 PVOID BootStoreHandle; 460 ENUM_REACTOS_ENTRIES_DATA Data; 461 462 // NOTE: Technically it would be "BootSector"... 463 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; 464 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; 465 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; 466 467 /* Open the INI file */ 468 Status = OpenBootStore(&BootStoreHandle, IniPath, NtLdr, 469 BS_OpenExisting /* BS_OpenAlways */, BS_ReadWriteAccess); 470 if (!NT_SUCCESS(Status)) 471 return Status; 472 473 /* Find an existing usable or an unused section name */ 474 Data.UseExistingEntry = TRUE; 475 // Data.i = 1; 476 Data.ArcPath = EntryName; 477 // RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS"); 478 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\""); 479 480 // 481 // FIXME: We temporarily use EnumerateBootStoreEntries, until 482 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented. 483 // 484 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data); 485 486 /* If either the key was not found, or contains something else, add a new one */ 487 if (!Data.UseExistingEntry /* || 488 ( (Status == STATUS_NO_MORE_ENTRIES) && wcscmp(Data.OsName, EntryValue) ) */) 489 { 490 BootEntry->Version = NtLdr; 491 BootEntry->BootFilePath = NULL; 492 493 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS); 494 RtlCopyMemory(Options->Signature, 495 NTOS_OPTIONS_SIGNATURE, 496 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)); 497 498 Options->OsLoadPath = EntryName; 499 500 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName); 501 // BootEntry->FriendlyName = Data.OsName; 502 BootEntry->FriendlyName = EntryValue; 503 Options->OsLoadOptions = NULL; // L""; 504 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(0 /*Data.SectionName*/)); 505 } 506 507 /* Close the INI file */ 508 CloseBootStore(BootStoreHandle); 509 return STATUS_SUCCESS; // Status; 510 } 511 512 513 static 514 BOOLEAN 515 IsThereAValidBootSector( 516 IN PCWSTR RootPath) 517 { 518 /* 519 * We first demand that the bootsector has a valid signature at its end. 520 * We then check the first 3 bytes (as a ULONG) of the bootsector for a 521 * potential "valid" instruction (the BIOS starts execution of the bootsector 522 * at its beginning). Currently this criterium is that this ULONG must be 523 * non-zero. If both these tests pass, then the bootsector is valid; otherwise 524 * it is invalid and certainly needs to be overwritten. 525 */ 526 527 BOOLEAN IsValid = FALSE; 528 NTSTATUS Status; 529 UNICODE_STRING RootPartition; 530 BOOTCODE BootSector = {0}; 531 532 /* Allocate and read the root partition bootsector. 533 * Remove any trailing backslash if needed. */ 534 RtlInitUnicodeString(&RootPartition, RootPath); 535 TrimTrailingPathSeparators_UStr(&RootPartition); 536 Status = ReadBootCodeFromFile(&BootSector, &RootPartition, SECTORSIZE); 537 if (!NT_SUCCESS(Status)) 538 return FALSE; 539 540 /* Check for the existence of the bootsector signature */ 541 IsValid = (*(PUSHORT)((PUCHAR)BootSector.BootCode + 0x1FE) == 0xAA55); 542 if (IsValid) 543 { 544 /* Check for the first instruction encoded on three bytes */ 545 IsValid = (((*(PULONG)BootSector.BootCode) & 0x00FFFFFF) != 0x00000000); 546 } 547 548 /* Free the bootsector and return */ 549 FreeBootCode(&BootSector); 550 return IsValid; 551 } 552 553 static 554 NTSTATUS 555 SaveBootSector( 556 IN PCWSTR RootPath, 557 IN PCWSTR DstPath, 558 IN ULONG Length) 559 { 560 NTSTATUS Status; 561 UNICODE_STRING Name; 562 OBJECT_ATTRIBUTES ObjectAttributes; 563 IO_STATUS_BLOCK IoStatusBlock; 564 HANDLE FileHandle; 565 // LARGE_INTEGER FileOffset; 566 BOOTCODE BootSector = {0}; 567 568 /* Allocate and read the root partition bootsector. 569 * Remove any trailing backslash if needed. */ 570 RtlInitUnicodeString(&Name, RootPath); 571 TrimTrailingPathSeparators_UStr(&Name); 572 Status = ReadBootCodeFromFile(&BootSector, &Name, Length); 573 if (!NT_SUCCESS(Status)) 574 return Status; 575 576 /* Write the bootsector to DstPath */ 577 RtlInitUnicodeString(&Name, DstPath); 578 InitializeObjectAttributes(&ObjectAttributes, 579 &Name, 580 OBJ_CASE_INSENSITIVE, 581 NULL, 582 NULL); 583 584 Status = NtCreateFile(&FileHandle, 585 GENERIC_WRITE | SYNCHRONIZE, 586 &ObjectAttributes, 587 &IoStatusBlock, 588 NULL, 589 FILE_ATTRIBUTE_NORMAL, 590 0, 591 FILE_SUPERSEDE, 592 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, 593 NULL, 594 0); 595 if (!NT_SUCCESS(Status)) 596 { 597 FreeBootCode(&BootSector); 598 return Status; 599 } 600 601 Status = NtWriteFile(FileHandle, 602 NULL, 603 NULL, 604 NULL, 605 &IoStatusBlock, 606 BootSector.BootCode, 607 BootSector.Length, 608 NULL, 609 NULL); 610 NtClose(FileHandle); 611 612 /* Free the bootsector and return */ 613 FreeBootCode(&BootSector); 614 return Status; 615 } 616 617 618 static 619 NTSTATUS 620 InstallBootCodeToDisk( 621 IN PCWSTR SrcPath, 622 IN PCWSTR RootPath, 623 IN PFS_INSTALL_BOOTCODE InstallBootCode) 624 { 625 NTSTATUS Status, LockStatus; 626 UNICODE_STRING Name; 627 OBJECT_ATTRIBUTES ObjectAttributes; 628 IO_STATUS_BLOCK IoStatusBlock; 629 HANDLE PartitionHandle; 630 631 /* 632 * Open the root partition from which the bootcode (MBR, VBR) parameters 633 * will be obtained; this is also where we will write the updated bootcode. 634 * Remove any trailing backslash if needed. 635 */ 636 RtlInitUnicodeString(&Name, RootPath); 637 TrimTrailingPathSeparators_UStr(&Name); 638 639 InitializeObjectAttributes(&ObjectAttributes, 640 &Name, 641 OBJ_CASE_INSENSITIVE, 642 NULL, 643 NULL); 644 645 Status = NtOpenFile(&PartitionHandle, 646 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 647 &ObjectAttributes, 648 &IoStatusBlock, 649 FILE_SHARE_READ | FILE_SHARE_WRITE, 650 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); 651 if (!NT_SUCCESS(Status)) 652 return Status; 653 654 /* Lock the volume */ 655 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); 656 if (!NT_SUCCESS(LockStatus)) 657 { 658 DPRINT1("Unable to lock the volume before installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 659 } 660 661 /* Install the bootcode (MBR, VBR) */ 662 Status = InstallBootCode(SrcPath, PartitionHandle, PartitionHandle); 663 664 /* dismount & Unlock the volume */ 665 if (NT_SUCCESS(LockStatus)) 666 { 667 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); 668 if (!NT_SUCCESS(LockStatus)) 669 { 670 DPRINT1("Unable to dismount the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 671 } 672 673 LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); 674 if (!NT_SUCCESS(LockStatus)) 675 { 676 DPRINT1("Unable to unlock the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus); 677 } 678 } 679 680 /* Close the partition */ 681 NtClose(PartitionHandle); 682 683 return Status; 684 } 685 686 static 687 NTSTATUS 688 InstallBootCodeToFile( 689 IN PCWSTR SrcPath, 690 IN PCWSTR DstPath, 691 IN PCWSTR RootPath, 692 IN PFS_INSTALL_BOOTCODE InstallBootCode) 693 { 694 NTSTATUS Status; 695 UNICODE_STRING Name; 696 OBJECT_ATTRIBUTES ObjectAttributes; 697 IO_STATUS_BLOCK IoStatusBlock; 698 HANDLE PartitionHandle, FileHandle; 699 700 /* 701 * Open the root partition from which the bootcode (MBR, VBR) 702 * parameters will be obtained. 703 * 704 * FIXME? It might be possible that we need to also open it for writing 705 * access in case we really need to still write the second portion of 706 * the boot sector ???? 707 * 708 * Remove any trailing backslash if needed. 709 */ 710 RtlInitUnicodeString(&Name, RootPath); 711 TrimTrailingPathSeparators_UStr(&Name); 712 713 InitializeObjectAttributes(&ObjectAttributes, 714 &Name, 715 OBJ_CASE_INSENSITIVE, 716 NULL, 717 NULL); 718 719 Status = NtOpenFile(&PartitionHandle, 720 GENERIC_READ | SYNCHRONIZE, 721 &ObjectAttributes, 722 &IoStatusBlock, 723 FILE_SHARE_READ | FILE_SHARE_WRITE, 724 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */); 725 if (!NT_SUCCESS(Status)) 726 return Status; 727 728 /* Open or create the file where the new bootsector will be saved */ 729 RtlInitUnicodeString(&Name, DstPath); 730 InitializeObjectAttributes(&ObjectAttributes, 731 &Name, 732 OBJ_CASE_INSENSITIVE, 733 NULL, 734 NULL); 735 736 Status = NtCreateFile(&FileHandle, 737 GENERIC_WRITE | SYNCHRONIZE, 738 &ObjectAttributes, 739 &IoStatusBlock, 740 NULL, 741 FILE_ATTRIBUTE_NORMAL, 742 0, 743 FILE_SUPERSEDE, // FILE_OVERWRITE_IF 744 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, 745 NULL, 746 0); 747 if (!NT_SUCCESS(Status)) 748 { 749 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status); 750 NtClose(PartitionHandle); 751 return Status; 752 } 753 754 /* Install the bootcode (MBR, VBR) */ 755 Status = InstallBootCode(SrcPath, FileHandle, PartitionHandle); 756 757 /* Close the file and the partition */ 758 NtClose(FileHandle); 759 NtClose(PartitionHandle); 760 761 return Status; 762 } 763 764 765 static 766 NTSTATUS 767 InstallMbrBootCode( 768 IN PCWSTR SrcPath, // MBR source file (on the installation medium) 769 IN HANDLE DstPath, // Where to save the bootsector built from the source + disk information 770 IN HANDLE DiskHandle) // Disk holding the (old) MBR information 771 { 772 NTSTATUS Status; 773 UNICODE_STRING Name; 774 IO_STATUS_BLOCK IoStatusBlock; 775 LARGE_INTEGER FileOffset; 776 BOOTCODE OrigBootSector = {0}; 777 BOOTCODE NewBootSector = {0}; 778 779 C_ASSERT(sizeof(PARTITION_SECTOR) == SECTORSIZE); 780 781 /* Allocate and read the current original MBR bootsector */ 782 Status = ReadBootCodeByHandle(&OrigBootSector, 783 DiskHandle, 784 sizeof(PARTITION_SECTOR)); 785 if (!NT_SUCCESS(Status)) 786 return Status; 787 788 /* Allocate and read the new bootsector from SrcPath */ 789 RtlInitUnicodeString(&Name, SrcPath); 790 Status = ReadBootCodeFromFile(&NewBootSector, 791 &Name, 792 sizeof(PARTITION_SECTOR)); 793 if (!NT_SUCCESS(Status)) 794 { 795 FreeBootCode(&OrigBootSector); 796 return Status; 797 } 798 799 /* 800 * Copy the disk signature, the reserved fields and 801 * the partition table from the old MBR to the new one. 802 */ 803 RtlCopyMemory(&((PPARTITION_SECTOR)NewBootSector.BootCode)->Signature, 804 &((PPARTITION_SECTOR)OrigBootSector.BootCode)->Signature, 805 sizeof(PARTITION_SECTOR) - 806 FIELD_OFFSET(PARTITION_SECTOR, Signature) 807 /* Length of partition table */); 808 809 /* Free the original bootsector */ 810 FreeBootCode(&OrigBootSector); 811 812 /* Write the new bootsector to DstPath */ 813 FileOffset.QuadPart = 0ULL; 814 Status = NtWriteFile(DstPath, 815 NULL, 816 NULL, 817 NULL, 818 &IoStatusBlock, 819 NewBootSector.BootCode, 820 NewBootSector.Length, 821 &FileOffset, 822 NULL); 823 824 /* Free the new bootsector */ 825 FreeBootCode(&NewBootSector); 826 827 return Status; 828 } 829 830 NTSTATUS 831 InstallMbrBootCodeToDisk( 832 IN PUNICODE_STRING SystemRootPath, 833 IN PUNICODE_STRING SourceRootPath, 834 IN PCWSTR DestinationDevicePathBuffer) 835 { 836 NTSTATUS Status; 837 WCHAR SourceMbrPathBuffer[MAX_PATH]; 838 WCHAR DstPath[MAX_PATH]; 839 840 #if 0 841 /* 842 * The DestinationDevicePathBuffer parameter has been built with 843 * the following instruction by the caller; I'm not yet sure whether 844 * I actually want this function to build the path instead, hence 845 * I keep this code here but disabled for now... 846 */ 847 WCHAR DestinationDevicePathBuffer[MAX_PATH]; 848 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer), 849 L"\\Device\\Harddisk%d\\Partition0", 850 DiskNumber); 851 #endif 852 853 CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, 854 SourceRootPath->Buffer, L"\\loader\\dosmbr.bin"); 855 856 if (IsThereAValidBootSector(DestinationDevicePathBuffer)) 857 { 858 /* Save current MBR */ 859 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, 860 SystemRootPath->Buffer, L"mbr.old"); 861 862 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath); 863 Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR)); 864 if (!NT_SUCCESS(Status)) 865 { 866 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 867 // Don't care if we succeeded or not saving the old MBR, just go ahead. 868 } 869 } 870 871 DPRINT1("Install MBR bootcode: %S ==> %S\n", 872 SourceMbrPathBuffer, DestinationDevicePathBuffer); 873 874 /* Install the MBR */ 875 return InstallBootCodeToDisk(SourceMbrPathBuffer, 876 DestinationDevicePathBuffer, 877 InstallMbrBootCode); 878 } 879 880 881 static 882 NTSTATUS 883 InstallFatBootcodeToPartition( 884 IN PUNICODE_STRING SystemRootPath, 885 IN PUNICODE_STRING SourceRootPath, 886 IN PUNICODE_STRING DestinationArcPath, 887 IN PCWSTR FileSystemName) 888 { 889 NTSTATUS Status; 890 BOOLEAN DoesFreeLdrExist; 891 WCHAR SrcPath[MAX_PATH]; 892 WCHAR DstPath[MAX_PATH]; 893 894 /* FAT or FAT32 partition */ 895 DPRINT("System path: '%wZ'\n", SystemRootPath); 896 897 /* Copy FreeLoader to the system partition, always overwriting the older version */ 898 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 899 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); 900 901 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 902 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 903 if (!NT_SUCCESS(Status)) 904 { 905 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 906 return Status; 907 } 908 909 /* Prepare for possibly updating 'freeldr.ini' */ 910 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 911 if (DoesFreeLdrExist) 912 { 913 /* Update existing 'freeldr.ini' */ 914 DPRINT1("Update existing 'freeldr.ini'\n"); 915 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 916 if (!NT_SUCCESS(Status)) 917 { 918 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 919 return Status; 920 } 921 } 922 923 /* Check for NT and other bootloaders */ 924 925 // FIXME: Check for Vista+ bootloader! 926 /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/ 927 /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/ 928 if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE || 929 DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE) 930 { 931 /* Search root directory for 'NTLDR' and 'BOOT.INI' */ 932 DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n"); 933 934 /* Create or update 'freeldr.ini' */ 935 if (DoesFreeLdrExist == FALSE) 936 { 937 /* Create new 'freeldr.ini' */ 938 DPRINT1("Create new 'freeldr.ini'\n"); 939 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 940 if (!NT_SUCCESS(Status)) 941 { 942 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 943 return Status; 944 } 945 946 /* Install new bootcode into a file */ 947 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"bootsect.ros"); 948 949 if (wcsicmp(FileSystemName, L"FAT32") == 0) 950 { 951 /* Install FAT32 bootcode */ 952 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin"); 953 954 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath); 955 Status = InstallBootCodeToFile(SrcPath, DstPath, 956 SystemRootPath->Buffer, 957 InstallFat32BootCode); 958 if (!NT_SUCCESS(Status)) 959 { 960 DPRINT1("InstallBootCodeToFile(FAT32) failed (Status %lx)\n", Status); 961 return Status; 962 } 963 } 964 else // if (wcsicmp(FileSystemName, L"FAT") == 0) 965 { 966 /* Install FAT16 bootcode */ 967 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 968 969 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, DstPath); 970 Status = InstallBootCodeToFile(SrcPath, DstPath, 971 SystemRootPath->Buffer, 972 InstallFat16BootCode); 973 if (!NT_SUCCESS(Status)) 974 { 975 DPRINT1("InstallBootCodeToFile(FAT16) failed (Status %lx)\n", Status); 976 return Status; 977 } 978 } 979 } 980 981 /* Update 'boot.ini' */ 982 /* Windows' NTLDR loads an external bootsector file when the specified drive 983 letter is C:, otherwise it will interpret it as a boot DOS path specifier. */ 984 DPRINT1("Update 'boot.ini'\n"); 985 Status = UpdateBootIni(SystemRootPath->Buffer, 986 L"C:\\bootsect.ros", 987 L"\"ReactOS\""); 988 if (!NT_SUCCESS(Status)) 989 { 990 DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status); 991 return Status; 992 } 993 } 994 else 995 { 996 /* Non-NT bootloaders: install our own bootloader */ 997 998 PCWSTR Section; 999 PCWSTR Description; 1000 PCWSTR BootSector; 1001 1002 /* Search for COMPAQ MS-DOS 1.x (1.11, 1.12, based on MS-DOS 1.25) boot loader */ 1003 if (DoesFileExist_2(SystemRootPath->Buffer, L"IOSYS.COM") == TRUE || 1004 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.COM") == TRUE) 1005 { 1006 DPRINT1("Found COMPAQ MS-DOS 1.x (1.11, 1.12) / MS-DOS 1.25 boot loader\n"); 1007 1008 Section = L"CPQDOS"; 1009 Description = L"\"COMPAQ MS-DOS 1.x / MS-DOS 1.25\""; 1010 BootSector = L"BOOTSECT.DOS"; 1011 } 1012 else 1013 /* Search for Microsoft DOS or Windows 9x boot loader */ 1014 if (DoesFileExist_2(SystemRootPath->Buffer, L"IO.SYS") == TRUE || 1015 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.SYS") == TRUE) 1016 // WINBOOT.SYS 1017 { 1018 DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n"); 1019 1020 Section = L"MSDOS"; 1021 Description = L"\"MS-DOS/Windows\""; 1022 BootSector = L"BOOTSECT.DOS"; 1023 } 1024 else 1025 /* Search for IBM PC-DOS or DR-DOS 5.x boot loader */ 1026 if (DoesFileExist_2(SystemRootPath->Buffer, L"IBMIO.COM" ) == TRUE || // Some people refer to this file instead of IBMBIO.COM... 1027 DoesFileExist_2(SystemRootPath->Buffer, L"IBMBIO.COM") == TRUE || 1028 DoesFileExist_2(SystemRootPath->Buffer, L"IBMDOS.COM") == TRUE) 1029 { 1030 DPRINT1("Found IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\n"); 1031 1032 Section = L"IBMDOS"; 1033 Description = L"\"IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\""; 1034 BootSector = L"BOOTSECT.DOS"; 1035 } 1036 else 1037 /* Search for DR-DOS 3.x boot loader */ 1038 if (DoesFileExist_2(SystemRootPath->Buffer, L"DRBIOS.SYS") == TRUE || 1039 DoesFileExist_2(SystemRootPath->Buffer, L"DRBDOS.SYS") == TRUE) 1040 { 1041 DPRINT1("Found DR-DOS 3.x\n"); 1042 1043 Section = L"DRDOS"; 1044 Description = L"\"DR-DOS 3.x\""; 1045 BootSector = L"BOOTSECT.DOS"; 1046 } 1047 else 1048 /* Search for Dell Real-Mode Kernel (DRMK) OS */ 1049 if (DoesFileExist_2(SystemRootPath->Buffer, L"DELLBIO.BIN") == TRUE || 1050 DoesFileExist_2(SystemRootPath->Buffer, L"DELLRMK.BIN") == TRUE) 1051 { 1052 DPRINT1("Found Dell Real-Mode Kernel OS\n"); 1053 1054 Section = L"DRMK"; 1055 Description = L"\"Dell Real-Mode Kernel OS\""; 1056 BootSector = L"BOOTSECT.DOS"; 1057 } 1058 else 1059 /* Search for MS OS/2 1.x */ 1060 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT.COM") == TRUE || 1061 DoesFileExist_2(SystemRootPath->Buffer, L"OS2BIO.COM" ) == TRUE || 1062 DoesFileExist_2(SystemRootPath->Buffer, L"OS2DOS.COM" ) == TRUE) 1063 { 1064 DPRINT1("Found MS OS/2 1.x\n"); 1065 1066 Section = L"MSOS2"; 1067 Description = L"\"MS OS/2 1.x\""; 1068 BootSector = L"BOOTSECT.OS2"; 1069 } 1070 else 1071 /* Search for MS or IBM OS/2 */ 1072 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT") == TRUE || 1073 DoesFileExist_2(SystemRootPath->Buffer, L"OS2LDR" ) == TRUE || 1074 DoesFileExist_2(SystemRootPath->Buffer, L"OS2KRNL") == TRUE) 1075 { 1076 DPRINT1("Found MS/IBM OS/2\n"); 1077 1078 Section = L"IBMOS2"; 1079 Description = L"\"MS/IBM OS/2\""; 1080 BootSector = L"BOOTSECT.OS2"; 1081 } 1082 else 1083 /* Search for FreeDOS boot loader */ 1084 if (DoesFileExist_2(SystemRootPath->Buffer, L"kernel.sys") == TRUE) 1085 { 1086 DPRINT1("Found FreeDOS boot loader\n"); 1087 1088 Section = L"FDOS"; 1089 Description = L"\"FreeDOS\""; 1090 BootSector = L"BOOTSECT.DOS"; 1091 } 1092 else 1093 { 1094 /* No or unknown boot loader */ 1095 DPRINT1("No or unknown boot loader found\n"); 1096 1097 Section = L"Unknown"; 1098 Description = L"\"Unknown Operating System\""; 1099 BootSector = L"BOOTSECT.OLD"; 1100 } 1101 1102 /* Create or update 'freeldr.ini' */ 1103 if (DoesFreeLdrExist == FALSE) 1104 { 1105 /* Create new 'freeldr.ini' */ 1106 DPRINT1("Create new 'freeldr.ini'\n"); 1107 1108 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1109 { 1110 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1111 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1112 Section, Description, 1113 SystemRootPath->Buffer, BootSector); 1114 if (!NT_SUCCESS(Status)) 1115 { 1116 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1117 return Status; 1118 } 1119 1120 /* Save current bootsector */ 1121 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1122 1123 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1124 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE); 1125 if (!NT_SUCCESS(Status)) 1126 { 1127 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1128 return Status; 1129 } 1130 } 1131 else 1132 { 1133 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1134 if (!NT_SUCCESS(Status)) 1135 { 1136 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1137 return Status; 1138 } 1139 } 1140 1141 /* Install new bootsector on the disk */ 1142 if (wcsicmp(FileSystemName, L"FAT32") == 0) 1143 { 1144 /* Install FAT32 bootcode */ 1145 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin"); 1146 1147 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1148 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat32BootCode); 1149 DPRINT1("Status: 0x%08X\n", Status); 1150 if (!NT_SUCCESS(Status)) 1151 { 1152 DPRINT1("InstallBootCodeToDisk(FAT32) failed (Status %lx)\n", Status); 1153 return Status; 1154 } 1155 } 1156 else // if (wcsicmp(FileSystemName, L"FAT") == 0) 1157 { 1158 /* Install FAT16 bootcode */ 1159 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1160 1161 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1162 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat16BootCode); 1163 if (!NT_SUCCESS(Status)) 1164 { 1165 DPRINT1("InstallBootCodeToDisk(FAT16) failed (Status %lx)\n", Status); 1166 return Status; 1167 } 1168 } 1169 } 1170 } 1171 1172 return STATUS_SUCCESS; 1173 } 1174 1175 static 1176 NTSTATUS 1177 InstallBtrfsBootcodeToPartition( 1178 IN PUNICODE_STRING SystemRootPath, 1179 IN PUNICODE_STRING SourceRootPath, 1180 IN PUNICODE_STRING DestinationArcPath) 1181 { 1182 NTSTATUS Status; 1183 BOOLEAN DoesFreeLdrExist; 1184 WCHAR SrcPath[MAX_PATH]; 1185 WCHAR DstPath[MAX_PATH]; 1186 1187 /* BTRFS partition */ 1188 DPRINT("System path: '%wZ'\n", SystemRootPath); 1189 1190 /* Copy FreeLoader to the system partition, always overwriting the older version */ 1191 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 1192 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); 1193 1194 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 1195 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 1196 if (!NT_SUCCESS(Status)) 1197 { 1198 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 1199 return Status; 1200 } 1201 1202 /* Prepare for possibly updating 'freeldr.ini' */ 1203 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 1204 if (DoesFreeLdrExist) 1205 { 1206 /* Update existing 'freeldr.ini' */ 1207 DPRINT1("Update existing 'freeldr.ini'\n"); 1208 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1209 if (!NT_SUCCESS(Status)) 1210 { 1211 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 1212 return Status; 1213 } 1214 } 1215 1216 /* Check for *nix bootloaders */ 1217 1218 /* Create or update 'freeldr.ini' */ 1219 if (DoesFreeLdrExist == FALSE) 1220 { 1221 /* Create new 'freeldr.ini' */ 1222 DPRINT1("Create new 'freeldr.ini'\n"); 1223 1224 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */ 1225 DPRINT1("*nix or unknown boot loader found\n"); 1226 1227 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1228 { 1229 PCWSTR BootSector = L"BOOTSECT.OLD"; 1230 1231 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1232 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1233 L"Linux", L"\"Linux\"", 1234 SystemRootPath->Buffer, BootSector); 1235 if (!NT_SUCCESS(Status)) 1236 { 1237 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1238 return Status; 1239 } 1240 1241 /* Save current bootsector */ 1242 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1243 1244 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1245 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, BTRFS_BOOTSECTOR_SIZE); 1246 if (!NT_SUCCESS(Status)) 1247 { 1248 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1249 return Status; 1250 } 1251 } 1252 else 1253 { 1254 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1255 if (!NT_SUCCESS(Status)) 1256 { 1257 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1258 return Status; 1259 } 1260 } 1261 1262 /* Install new bootsector on the disk */ 1263 /* Install BTRFS bootcode */ 1264 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin"); 1265 1266 DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1267 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallBtrfsBootCode); 1268 if (!NT_SUCCESS(Status)) 1269 { 1270 DPRINT1("InstallBootCodeToDisk(BTRFS) failed (Status %lx)\n", Status); 1271 return Status; 1272 } 1273 } 1274 1275 return STATUS_SUCCESS; 1276 } 1277 1278 static 1279 NTSTATUS 1280 InstallNtfsBootcodeToPartition( 1281 IN PUNICODE_STRING SystemRootPath, 1282 IN PUNICODE_STRING SourceRootPath, 1283 IN PUNICODE_STRING DestinationArcPath) 1284 { 1285 NTSTATUS Status; 1286 BOOLEAN DoesFreeLdrExist; 1287 WCHAR SrcPath[MAX_PATH]; 1288 WCHAR DstPath[MAX_PATH]; 1289 1290 /* NTFS partition */ 1291 DPRINT("System path: '%wZ'\n", SystemRootPath); 1292 1293 /* Copy FreeLoader to the system partition, always overwriting the older version */ 1294 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 1295 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys"); 1296 1297 DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath); 1298 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 1299 if (!NT_SUCCESS(Status)) 1300 { 1301 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 1302 return Status; 1303 } 1304 1305 /* Prepare for possibly updating 'freeldr.ini' */ 1306 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini"); 1307 if (DoesFreeLdrExist) 1308 { 1309 /* Update existing 'freeldr.ini' */ 1310 DPRINT1("Update existing 'freeldr.ini'\n"); 1311 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1312 if (!NT_SUCCESS(Status)) 1313 { 1314 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status); 1315 return Status; 1316 } 1317 1318 return STATUS_SUCCESS; 1319 } 1320 1321 /* Check for *nix bootloaders */ 1322 1323 DPRINT1("Create new 'freeldr.ini'\n"); 1324 1325 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */ 1326 DPRINT1("*nix or unknown boot loader found\n"); 1327 1328 if (IsThereAValidBootSector(SystemRootPath->Buffer)) 1329 { 1330 PCWSTR BootSector = L"BOOTSECT.OLD"; 1331 1332 Status = CreateFreeLoaderIniForReactOSAndBootSector( 1333 SystemRootPath->Buffer, DestinationArcPath->Buffer, 1334 L"Linux", L"\"Linux\"", 1335 SystemRootPath->Buffer, BootSector); 1336 if (!NT_SUCCESS(Status)) 1337 { 1338 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status); 1339 return Status; 1340 } 1341 1342 /* Save current bootsector */ 1343 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector); 1344 1345 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); 1346 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, NTFS_BOOTSECTOR_SIZE); 1347 if (!NT_SUCCESS(Status)) 1348 { 1349 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); 1350 return Status; 1351 } 1352 } 1353 else 1354 { 1355 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); 1356 if (!NT_SUCCESS(Status)) 1357 { 1358 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1359 return Status; 1360 } 1361 } 1362 1363 /* Install new bootsector on the disk */ 1364 1365 /* Install NTFS bootcode */ 1366 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\ntfs.bin"); 1367 1368 DPRINT1("Install NTFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); 1369 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallNtfsBootCode); 1370 if (!NT_SUCCESS(Status)) 1371 { 1372 DPRINT1("InstallBootCodeToDisk(NTFS) failed (Status %lx)\n", Status); 1373 return Status; 1374 } 1375 1376 return STATUS_SUCCESS; 1377 } 1378 1379 1380 NTSTATUS 1381 InstallVBRToPartition( 1382 IN PUNICODE_STRING SystemRootPath, 1383 IN PUNICODE_STRING SourceRootPath, 1384 IN PUNICODE_STRING DestinationArcPath, 1385 IN PCWSTR FileSystemName) 1386 { 1387 if (wcsicmp(FileSystemName, L"FAT") == 0 || 1388 wcsicmp(FileSystemName, L"FAT32") == 0) 1389 { 1390 return InstallFatBootcodeToPartition(SystemRootPath, 1391 SourceRootPath, 1392 DestinationArcPath, 1393 FileSystemName); 1394 } 1395 else if (wcsicmp(FileSystemName, L"NTFS") == 0) 1396 { 1397 return InstallNtfsBootcodeToPartition(SystemRootPath, 1398 SourceRootPath, 1399 DestinationArcPath); 1400 } 1401 else if (wcsicmp(FileSystemName, L"BTRFS") == 0) 1402 { 1403 return InstallBtrfsBootcodeToPartition(SystemRootPath, 1404 SourceRootPath, 1405 DestinationArcPath); 1406 } 1407 /* 1408 else if (wcsicmp(FileSystemName, L"EXT2") == 0 || 1409 wcsicmp(FileSystemName, L"EXT3") == 0 || 1410 wcsicmp(FileSystemName, L"EXT4") == 0) 1411 { 1412 return STATUS_NOT_SUPPORTED; 1413 } 1414 */ 1415 else 1416 { 1417 /* Unknown file system */ 1418 DPRINT1("Unknown file system '%S'\n", FileSystemName); 1419 } 1420 1421 return STATUS_NOT_SUPPORTED; 1422 } 1423 1424 1425 NTSTATUS 1426 InstallFatBootcodeToFloppy( 1427 IN PUNICODE_STRING SourceRootPath, 1428 IN PUNICODE_STRING DestinationArcPath) 1429 { 1430 static const PCWSTR FloppyDevice = L"\\Device\\Floppy0\\"; 1431 1432 NTSTATUS Status; 1433 WCHAR SrcPath[MAX_PATH]; 1434 WCHAR DstPath[MAX_PATH]; 1435 1436 /* Verify that the floppy disk is accessible */ 1437 if (DoesDirExist(NULL, FloppyDevice) == FALSE) 1438 return STATUS_DEVICE_NOT_READY; 1439 1440 /* Format the floppy disk */ 1441 // FormatPartition(...) 1442 Status = FormatFileSystem(FloppyDevice, 1443 L"FAT", 1444 FMIFS_FLOPPY, 1445 NULL, 1446 TRUE, 1447 0, 1448 NULL); 1449 if (!NT_SUCCESS(Status)) 1450 { 1451 if (Status == STATUS_NOT_SUPPORTED) 1452 DPRINT1("FAT FS non existent on this system?!\n"); 1453 else 1454 DPRINT1("VfatFormat() failed (Status %lx)\n", Status); 1455 1456 return Status; 1457 } 1458 1459 /* Copy FreeLoader to the boot partition */ 1460 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); 1461 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice, L"freeldr.sys"); 1462 1463 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); 1464 Status = SetupCopyFile(SrcPath, DstPath, FALSE); 1465 if (!NT_SUCCESS(Status)) 1466 { 1467 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); 1468 return Status; 1469 } 1470 1471 /* Create new 'freeldr.ini' */ 1472 DPRINT("Create new 'freeldr.ini'\n"); 1473 Status = CreateFreeLoaderIniForReactOS(FloppyDevice, DestinationArcPath->Buffer); 1474 if (!NT_SUCCESS(Status)) 1475 { 1476 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); 1477 return Status; 1478 } 1479 1480 /* Install FAT12 boosector */ 1481 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); 1482 CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice); 1483 1484 DPRINT("Install FAT12 bootcode: %S ==> %S\n", SrcPath, DstPath); 1485 Status = InstallBootCodeToDisk(SrcPath, DstPath, InstallFat12BootCode); 1486 if (!NT_SUCCESS(Status)) 1487 { 1488 DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status %lx)\n", Status); 1489 return Status; 1490 } 1491 1492 return STATUS_SUCCESS; 1493 } 1494 1495 /* EOF */ 1496