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