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