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" // HAXX 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
TrimTrailingPathSeparators_UStr(IN OUT PUNICODE_STRING UnicodeString)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
CreateFreeLoaderReactOSEntries(IN PVOID BootStoreHandle,IN PCWSTR ArcPath)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
CreateFreeLoaderIniForReactOS(IN PCWSTR IniPath,IN PCWSTR ArcPath)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
CreateFreeLoaderIniForReactOSAndBootSector(IN PCWSTR IniPath,IN PCWSTR ArcPath,IN PCWSTR Section,IN PCWSTR Description,IN PCWSTR BootPath,IN PCWSTR BootSector)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
EnumerateReactOSEntries(IN BOOT_STORE_TYPE Type,IN PBOOT_STORE_ENTRY BootEntry,IN PVOID Parameter OPTIONAL)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
UpdateFreeLoaderIni(IN PCWSTR IniPath,IN PCWSTR ArcPath)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
UpdateBootIni(IN PCWSTR IniPath,IN PCWSTR EntryName,IN PCWSTR EntryValue)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
IsThereAValidBootSector(IN PCWSTR RootPath)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
SaveBootSector(IN PCWSTR RootPath,IN PCWSTR DstPath,IN ULONG Length)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
InstallBootCodeToDisk(IN PCWSTR SrcPath,IN PCWSTR RootPath,IN PFS_INSTALL_BOOTCODE InstallBootCode)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
InstallBootCodeToFile(IN PCWSTR SrcPath,IN PCWSTR DstPath,IN PCWSTR RootPath,IN PFS_INSTALL_BOOTCODE InstallBootCode)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
InstallMbrBootCode(IN PCWSTR SrcPath,IN HANDLE DstPath,IN HANDLE DiskHandle)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
InstallMbrBootCodeToDisk(_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCWSTR DestinationDevicePathBuffer)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
InstallBootloaderFiles(_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath)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
InstallFatBootcodeToPartition(_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath,_In_ PCWSTR FileSystemName)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
InstallBtrfsBootcodeToPartition(_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath)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
InstallNtfsBootcodeToPartition(_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath)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
InstallVBRToPartition(_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath,_In_ PCWSTR FileSystemName)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
InstallBootManagerAndBootEntriesWorker(_In_ ARCHITECTURE_TYPE ArchType,_In_ PCUNICODE_STRING SystemRootPath,_In_ ULONG DiskNumber,_In_ PARTITION_STYLE DiskStyle,_In_ BOOLEAN IsSuperFloppy,_In_ PCWSTR FileSystem,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath,_In_ ULONG_PTR Options)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
GetDeviceInfo_UStr(_In_opt_ PCUNICODE_STRING DeviceName,_In_opt_ HANDLE DeviceHandle,_Out_ PFILE_FS_DEVICE_INFORMATION DeviceInfo)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
GetDeviceInfo(_In_opt_ PCWSTR DeviceName,_In_opt_ HANDLE DeviceHandle,_Out_ PFILE_FS_DEVICE_INFORMATION DeviceInfo)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
InstallBootManagerAndBootEntries(_In_ ARCHITECTURE_TYPE ArchType,_In_ PCUNICODE_STRING SystemRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath,_In_ ULONG_PTR Options)1661 InstallBootManagerAndBootEntries(
1662 _In_ ARCHITECTURE_TYPE ArchType,
1663 _In_ PCUNICODE_STRING SystemRootPath,
1664 _In_ PCUNICODE_STRING SourceRootPath,
1665 _In_ PCUNICODE_STRING DestinationArcPath,
1666 _In_ ULONG_PTR Options)
1667 {
1668 NTSTATUS Status;
1669 HANDLE DeviceHandle;
1670 FILE_FS_DEVICE_INFORMATION DeviceInfo;
1671 ULONG DiskNumber;
1672 PARTITION_STYLE PartitionStyle;
1673 BOOLEAN IsSuperFloppy;
1674 WCHAR FileSystem[MAX_PATH+1];
1675
1676 /* Remove any trailing backslash if needed */
1677 UNICODE_STRING RootPartition = *SystemRootPath;
1678 TrimTrailingPathSeparators_UStr(&RootPartition);
1679
1680 /* Open the volume */
1681 Status = pOpenDeviceEx_UStr(&RootPartition, &DeviceHandle,
1682 GENERIC_READ,
1683 FILE_SHARE_READ | FILE_SHARE_WRITE);
1684 if (!NT_SUCCESS(Status))
1685 {
1686 DPRINT1("Cannot open %wZ for bootloader installation (Status 0x%08lx)\n",
1687 &RootPartition, Status);
1688 return Status;
1689 }
1690
1691 /* Retrieve the volume file system (it will also be mounted) */
1692 Status = GetFileSystemName_UStr(NULL, DeviceHandle,
1693 FileSystem, sizeof(FileSystem));
1694 if (!NT_SUCCESS(Status) || !*FileSystem)
1695 {
1696 DPRINT1("GetFileSystemName() failed (Status 0x%08lx)\n", Status);
1697 goto Quit;
1698 }
1699
1700 /* Retrieve the device type and characteristics */
1701 Status = GetDeviceInfo_UStr(NULL, DeviceHandle, &DeviceInfo);
1702 if (!NT_SUCCESS(Status))
1703 {
1704 DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status);
1705 goto Quit;
1706 }
1707
1708 /* Ignore volumes that are NOT on usual disks */
1709 if (DeviceInfo.DeviceType != FILE_DEVICE_DISK /*&&
1710 DeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK*/)
1711 {
1712 DPRINT1("Invalid volume; device type %lu\n", DeviceInfo.DeviceType);
1713 Status = STATUS_INVALID_DEVICE_REQUEST;
1714 goto Quit;
1715 }
1716
1717
1718 /* Check whether this is a floppy or a partitionable device */
1719 if (DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE)
1720 {
1721 /* Floppies don't have partitions */
1722 // NOTE: See ntoskrnl/io/iomgr/rawfs.c!RawQueryFsSizeInfo()
1723 DiskNumber = ULONG_MAX;
1724 PartitionStyle = PARTITION_STYLE_MBR;
1725 IsSuperFloppy = TRUE;
1726 }
1727 else
1728 {
1729 IO_STATUS_BLOCK IoStatusBlock;
1730 STORAGE_DEVICE_NUMBER DeviceNumber;
1731
1732 /* The maximum information a DISK_GEOMETRY_EX dynamic structure can contain */
1733 typedef struct _DISK_GEOMETRY_EX_INTERNAL
1734 {
1735 DISK_GEOMETRY Geometry;
1736 LARGE_INTEGER DiskSize;
1737 DISK_PARTITION_INFO Partition;
1738 /* Followed by: DISK_DETECTION_INFO Detection; unused here */
1739 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
1740
1741 DISK_GEOMETRY_EX_INTERNAL DiskGeoEx;
1742 PARTITION_INFORMATION PartitionInfo;
1743
1744 /* Retrieve the disk number. NOTE: Fails for floppy disks. */
1745 Status = NtDeviceIoControlFile(DeviceHandle,
1746 NULL, NULL, NULL,
1747 &IoStatusBlock,
1748 IOCTL_STORAGE_GET_DEVICE_NUMBER,
1749 NULL, 0,
1750 &DeviceNumber, sizeof(DeviceNumber));
1751 if (!NT_SUCCESS(Status))
1752 goto Quit; /* This may be a dynamic volume, which is unsupported */
1753 ASSERT(DeviceNumber.DeviceType == DeviceInfo.DeviceType);
1754 if (DeviceNumber.DeviceNumber == ULONG_MAX)
1755 {
1756 DPRINT1("Invalid disk number reported, bail out\n");
1757 Status = STATUS_NOT_FOUND;
1758 goto Quit;
1759 }
1760
1761 /* Retrieve the drive geometry. NOTE: Fails for floppy disks;
1762 * use IOCTL_DISK_GET_DRIVE_GEOMETRY instead. */
1763 Status = NtDeviceIoControlFile(DeviceHandle,
1764 NULL, NULL, NULL,
1765 &IoStatusBlock,
1766 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
1767 NULL, 0,
1768 &DiskGeoEx,
1769 sizeof(DiskGeoEx));
1770 if (!NT_SUCCESS(Status))
1771 {
1772 DPRINT1("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed (Status 0x%08lx)\n", Status);
1773 goto Quit;
1774 }
1775
1776 /*
1777 * Retrieve the volume's partition information.
1778 * NOTE: Fails for floppy disks.
1779 *
1780 * NOTE: We can use the non-EX IOCTL because the super-floppy test will
1781 * fail anyway if the disk is NOT MBR-partitioned. (If the disk is GPT,
1782 * the IOCTL would return only the MBR protective partition, but the
1783 * super-floppy test would fail due to the wrong partitioning style.)
1784 */
1785 Status = NtDeviceIoControlFile(DeviceHandle,
1786 NULL, NULL, NULL,
1787 &IoStatusBlock,
1788 IOCTL_DISK_GET_PARTITION_INFO,
1789 NULL, 0,
1790 &PartitionInfo,
1791 sizeof(PartitionInfo));
1792 if (!NT_SUCCESS(Status))
1793 {
1794 DPRINT1("IOCTL_DISK_GET_PARTITION_INFO failed (Status 0x%08lx)\n", Status);
1795 goto Quit;
1796 }
1797
1798 DiskNumber = DeviceNumber.DeviceNumber;
1799 PartitionStyle = DiskGeoEx.Partition.PartitionStyle;
1800 IsSuperFloppy = IsDiskSuperFloppy2(&DiskGeoEx.Partition,
1801 (PULONGLONG)&DiskGeoEx.DiskSize.QuadPart,
1802 &PartitionInfo);
1803 }
1804
1805 Status = InstallBootManagerAndBootEntriesWorker(
1806 ArchType, SystemRootPath,
1807 DiskNumber, PartitionStyle, IsSuperFloppy, FileSystem,
1808 SourceRootPath, DestinationArcPath, Options);
1809
1810 Quit:
1811 NtClose(DeviceHandle);
1812 return Status;
1813 }
1814
1815 NTSTATUS
InstallBootcodeToRemovable(_In_ ARCHITECTURE_TYPE ArchType,_In_ PCUNICODE_STRING RemovableRootPath,_In_ PCUNICODE_STRING SourceRootPath,_In_ PCUNICODE_STRING DestinationArcPath)1816 InstallBootcodeToRemovable(
1817 _In_ ARCHITECTURE_TYPE ArchType,
1818 _In_ PCUNICODE_STRING RemovableRootPath,
1819 _In_ PCUNICODE_STRING SourceRootPath,
1820 _In_ PCUNICODE_STRING DestinationArcPath)
1821 {
1822 NTSTATUS Status;
1823 FILE_FS_DEVICE_INFORMATION DeviceInfo;
1824 PCWSTR FileSystemName;
1825 BOOLEAN IsFloppy;
1826
1827 /* Remove any trailing backslash if needed */
1828 UNICODE_STRING RootDrive = *RemovableRootPath;
1829 TrimTrailingPathSeparators_UStr(&RootDrive);
1830
1831 /* Verify that the removable disk is accessible */
1832 if (!DoesDirExist(NULL, RemovableRootPath->Buffer))
1833 return STATUS_DEVICE_NOT_READY;
1834
1835 /* Retrieve the device type and characteristics */
1836 Status = GetDeviceInfo_UStr(&RootDrive, NULL, &DeviceInfo);
1837 if (!NT_SUCCESS(Status))
1838 {
1839 static const UNICODE_STRING DeviceFloppy = RTL_CONSTANT_STRING(L"\\Device\\Floppy");
1840
1841 DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status);
1842
1843 /* Definitively fail if the device is not a floppy */
1844 if (!RtlPrefixUnicodeString(&DeviceFloppy, &RootDrive, TRUE))
1845 return Status; /* We cannot cope with a failure */
1846
1847 /* Try to fall back to something "sane" if the device may be a floppy */
1848 DeviceInfo.DeviceType = FILE_DEVICE_DISK;
1849 DeviceInfo.Characteristics = FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE;
1850 }
1851
1852 /* Ignore volumes that are NOT on usual disks */
1853 if (DeviceInfo.DeviceType != FILE_DEVICE_DISK /*&&
1854 DeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK*/)
1855 {
1856 DPRINT1("Invalid volume; device type %lu\n", DeviceInfo.DeviceType);
1857 return STATUS_INVALID_DEVICE_REQUEST;
1858 }
1859
1860 /* Fail if the disk is not removable */
1861 if (!(DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA))
1862 {
1863 DPRINT1("Device is NOT removable!\n");
1864 return STATUS_INVALID_DEVICE_REQUEST;
1865 }
1866
1867 /* Check whether this is a floppy or another removable device */
1868 IsFloppy = !!(DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE);
1869
1870 /* Use FAT32, unless the device is a floppy disk */
1871 FileSystemName = (IsFloppy ? L"FAT" : L"FAT32");
1872
1873 /* Format the removable disk */
1874 Status = FormatFileSystem_UStr(&RootDrive,
1875 FileSystemName,
1876 (IsFloppy ? FMIFS_FLOPPY : FMIFS_REMOVABLE),
1877 NULL,
1878 TRUE,
1879 0,
1880 NULL);
1881 if (!NT_SUCCESS(Status))
1882 {
1883 if (Status == STATUS_NOT_SUPPORTED)
1884 DPRINT1("%s FS non-existent on this system!\n", FileSystemName);
1885 else
1886 DPRINT1("FormatFileSystem(%s) failed (Status 0x%08lx)\n", FileSystemName, Status);
1887 return Status;
1888 }
1889
1890 /* Copy FreeLoader to the removable disk and save the boot entries */
1891 Status = InstallBootManagerAndBootEntries(ArchType,
1892 RemovableRootPath,
1893 SourceRootPath,
1894 DestinationArcPath,
1895 2 /* Install on removable media */);
1896 if (!NT_SUCCESS(Status))
1897 DPRINT1("InstallBootManagerAndBootEntries() failed (Status 0x%08lx)\n", Status);
1898 return Status;
1899 }
1900
1901 /* EOF */
1902