xref: /reactos/base/setup/lib/bootsup.c (revision 4225717d)
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