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