xref: /reactos/base/setup/lib/bootsup.c (revision 7b1049c8)
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, LockStatus;
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     /* Lock the volume */
588     LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);
589     if (!NT_SUCCESS(LockStatus))
590     {
591         DPRINT1("Unable to lock the volume before installing boot code. Status 0x%08x. Expect problems.\n", LockStatus);
592     }
593 
594     /* Install the bootcode (MBR, VBR) */
595     Status = InstallBootCode(SrcPath, PartitionHandle, PartitionHandle);
596 
597     /* dismount & Unlock the volume */
598     if (NT_SUCCESS(LockStatus))
599     {
600         LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);
601         if (!NT_SUCCESS(LockStatus))
602         {
603             DPRINT1("Unable to unlock the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus);
604         }
605 
606         LockStatus = NtFsControlFile(PartitionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0);
607         if (!NT_SUCCESS(LockStatus))
608         {
609             DPRINT1("Unable to unlock the volume after installing boot code. Status 0x%08x. Expect problems.\n", LockStatus);
610         }
611     }
612 
613     /* Close the partition */
614     NtClose(PartitionHandle);
615 
616     return Status;
617 }
618 
619 static
620 NTSTATUS
621 InstallBootCodeToFile(
622     IN PCWSTR SrcPath,
623     IN PCWSTR DstPath,
624     IN PCWSTR RootPath,
625     IN PFS_INSTALL_BOOTCODE InstallBootCode)
626 {
627     NTSTATUS Status;
628     UNICODE_STRING Name;
629     OBJECT_ATTRIBUTES ObjectAttributes;
630     IO_STATUS_BLOCK IoStatusBlock;
631     HANDLE PartitionHandle, FileHandle;
632 
633     /*
634      * Open the root partition from which the bootcode (MBR, VBR)
635      * parameters will be obtained.
636      *
637      * FIXME? It might be possible that we need to also open it for writing
638      * access in case we really need to still write the second portion of
639      * the boot sector ????
640      *
641      * Remove any trailing backslash if needed.
642      */
643     RtlInitUnicodeString(&Name, RootPath);
644     TrimTrailingPathSeparators_UStr(&Name);
645 
646     InitializeObjectAttributes(&ObjectAttributes,
647                                &Name,
648                                OBJ_CASE_INSENSITIVE,
649                                NULL,
650                                NULL);
651 
652     Status = NtOpenFile(&PartitionHandle,
653                         GENERIC_READ | SYNCHRONIZE,
654                         &ObjectAttributes,
655                         &IoStatusBlock,
656                         FILE_SHARE_READ | FILE_SHARE_WRITE,
657                         FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
658     if (!NT_SUCCESS(Status))
659         return Status;
660 
661     /* Open or create the file where the new bootsector will be saved */
662     RtlInitUnicodeString(&Name, DstPath);
663     InitializeObjectAttributes(&ObjectAttributes,
664                                &Name,
665                                OBJ_CASE_INSENSITIVE,
666                                NULL,
667                                NULL);
668 
669     Status = NtCreateFile(&FileHandle,
670                           GENERIC_WRITE | SYNCHRONIZE,
671                           &ObjectAttributes,
672                           &IoStatusBlock,
673                           NULL,
674                           FILE_ATTRIBUTE_NORMAL,
675                           0,
676                           FILE_SUPERSEDE, // FILE_OVERWRITE_IF
677                           FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
678                           NULL,
679                           0);
680     if (!NT_SUCCESS(Status))
681     {
682         DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
683         NtClose(PartitionHandle);
684         return Status;
685     }
686 
687     /* Install the bootcode (MBR, VBR) */
688     Status = InstallBootCode(SrcPath, FileHandle, PartitionHandle);
689 
690     /* Close the file and the partition */
691     NtClose(FileHandle);
692     NtClose(PartitionHandle);
693 
694     return Status;
695 }
696 
697 
698 static
699 NTSTATUS
700 InstallMbrBootCode(
701     IN PCWSTR SrcPath,      // MBR source file (on the installation medium)
702     IN HANDLE DstPath,      // Where to save the bootsector built from the source + disk information
703     IN HANDLE DiskHandle)   // Disk holding the (old) MBR information
704 {
705     NTSTATUS Status;
706     UNICODE_STRING Name;
707     IO_STATUS_BLOCK IoStatusBlock;
708     LARGE_INTEGER FileOffset;
709     BOOTCODE OrigBootSector = {0};
710     BOOTCODE NewBootSector  = {0};
711 
712 C_ASSERT(sizeof(PARTITION_SECTOR) == SECTORSIZE);
713 
714     /* Allocate and read the current original MBR bootsector */
715     Status = ReadBootCodeByHandle(&OrigBootSector,
716                                   DiskHandle,
717                                   sizeof(PARTITION_SECTOR));
718     if (!NT_SUCCESS(Status))
719         return Status;
720 
721     /* Allocate and read the new bootsector from SrcPath */
722     RtlInitUnicodeString(&Name, SrcPath);
723     Status = ReadBootCodeFromFile(&NewBootSector,
724                                   &Name,
725                                   sizeof(PARTITION_SECTOR));
726     if (!NT_SUCCESS(Status))
727     {
728         FreeBootCode(&OrigBootSector);
729         return Status;
730     }
731 
732     /*
733      * Copy the disk signature, the reserved fields and
734      * the partition table from the old MBR to the new one.
735      */
736     RtlCopyMemory(&((PPARTITION_SECTOR)NewBootSector.BootCode)->Signature,
737                   &((PPARTITION_SECTOR)OrigBootSector.BootCode)->Signature,
738                   sizeof(PARTITION_SECTOR) -
739                   FIELD_OFFSET(PARTITION_SECTOR, Signature)
740                   /* Length of partition table */);
741 
742     /* Free the original bootsector */
743     FreeBootCode(&OrigBootSector);
744 
745     /* Write the new bootsector to DstPath */
746     FileOffset.QuadPart = 0ULL;
747     Status = NtWriteFile(DstPath,
748                          NULL,
749                          NULL,
750                          NULL,
751                          &IoStatusBlock,
752                          NewBootSector.BootCode,
753                          NewBootSector.Length,
754                          &FileOffset,
755                          NULL);
756 
757     /* Free the new bootsector */
758     FreeBootCode(&NewBootSector);
759 
760     return Status;
761 }
762 
763 NTSTATUS
764 InstallMbrBootCodeToDisk(
765     IN PUNICODE_STRING SystemRootPath,
766     IN PUNICODE_STRING SourceRootPath,
767     IN PCWSTR DestinationDevicePathBuffer)
768 {
769     NTSTATUS Status;
770     WCHAR SourceMbrPathBuffer[MAX_PATH];
771     WCHAR DstPath[MAX_PATH];
772 
773 #if 0
774     /*
775      * The DestinationDevicePathBuffer parameter has been built with
776      * the following instruction by the caller; I'm not yet sure whether
777      * I actually want this function to build the path instead, hence
778      * I keep this code here but disabled for now...
779      */
780     WCHAR DestinationDevicePathBuffer[MAX_PATH];
781     RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
782                         L"\\Device\\Harddisk%d\\Partition0",
783                         DiskNumber);
784 #endif
785 
786     CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2,
787                  SourceRootPath->Buffer, L"\\loader\\dosmbr.bin");
788 
789     if (IsThereAValidBootSector(DestinationDevicePathBuffer))
790     {
791         /* Save current MBR */
792         CombinePaths(DstPath, ARRAYSIZE(DstPath), 2,
793                      SystemRootPath->Buffer, L"mbr.old");
794 
795         DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
796         Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
797         if (!NT_SUCCESS(Status))
798         {
799             DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
800             // Don't care if we succeeded or not saving the old MBR, just go ahead.
801         }
802     }
803 
804     DPRINT1("Install MBR bootcode: %S ==> %S\n",
805             SourceMbrPathBuffer, DestinationDevicePathBuffer);
806 
807     /* Install the MBR */
808     return InstallBootCodeToDisk(SourceMbrPathBuffer,
809                                  DestinationDevicePathBuffer,
810                                  InstallMbrBootCode);
811 }
812 
813 
814 static
815 NTSTATUS
816 InstallFatBootcodeToPartition(
817     IN PUNICODE_STRING SystemRootPath,
818     IN PUNICODE_STRING SourceRootPath,
819     IN PUNICODE_STRING DestinationArcPath,
820     IN PCWSTR FileSystemName)
821 {
822     NTSTATUS Status;
823     BOOLEAN DoesFreeLdrExist;
824     WCHAR SrcPath[MAX_PATH];
825     WCHAR DstPath[MAX_PATH];
826 
827     /* FAT or FAT32 partition */
828     DPRINT("System path: '%wZ'\n", SystemRootPath);
829 
830     /* Copy FreeLoader to the system partition, always overwriting the older version */
831     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
832     CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
833 
834     DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
835     Status = SetupCopyFile(SrcPath, DstPath, FALSE);
836     if (!NT_SUCCESS(Status))
837     {
838         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
839         return Status;
840     }
841 
842     /* Prepare for possibly updating 'freeldr.ini' */
843     DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini");
844     if (DoesFreeLdrExist)
845     {
846         /* Update existing 'freeldr.ini' */
847         DPRINT1("Update existing 'freeldr.ini'\n");
848         Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer);
849         if (!NT_SUCCESS(Status))
850         {
851             DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
852             return Status;
853         }
854     }
855 
856     /* Check for NT and other bootloaders */
857 
858     // FIXME: Check for Vista+ bootloader!
859     /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/
860     /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/
861     if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE ||
862         DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE)
863     {
864         /* Search root directory for 'NTLDR' and 'BOOT.INI' */
865         DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
866 
867         /* Create or update 'freeldr.ini' */
868         if (DoesFreeLdrExist == FALSE)
869         {
870             /* Create new 'freeldr.ini' */
871             DPRINT1("Create new 'freeldr.ini'\n");
872             Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
873             if (!NT_SUCCESS(Status))
874             {
875                 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
876                 return Status;
877             }
878 
879             /* Install new bootcode into a file */
880             CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"bootsect.ros");
881 
882             if (wcsicmp(FileSystemName, L"FAT32") == 0)
883             {
884                 /* Install FAT32 bootcode */
885                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin");
886 
887                 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
888                 Status = InstallBootCodeToFile(SrcPath, DstPath,
889                                                SystemRootPath->Buffer,
890                                                InstallFat32BootCode);
891                 if (!NT_SUCCESS(Status))
892                 {
893                     DPRINT1("InstallBootCodeToFile(FAT32) failed (Status %lx)\n", Status);
894                     return Status;
895                 }
896             }
897             else // if (wcsicmp(FileSystemName, L"FAT") == 0)
898             {
899                 /* Install FAT16 bootcode */
900                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
901 
902                 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, DstPath);
903                 Status = InstallBootCodeToFile(SrcPath, DstPath,
904                                                SystemRootPath->Buffer,
905                                                InstallFat16BootCode);
906                 if (!NT_SUCCESS(Status))
907                 {
908                     DPRINT1("InstallBootCodeToFile(FAT16) failed (Status %lx)\n", Status);
909                     return Status;
910                 }
911             }
912         }
913 
914         /* Update 'boot.ini' */
915         /* Windows' NTLDR loads an external bootsector file when the specified drive
916            letter is C:, otherwise it will interpret it as a boot DOS path specifier. */
917         DPRINT1("Update 'boot.ini'\n");
918         Status = UpdateBootIni(SystemRootPath->Buffer,
919                                L"C:\\bootsect.ros",
920                                L"\"ReactOS\"");
921         if (!NT_SUCCESS(Status))
922         {
923             DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
924             return Status;
925         }
926     }
927     else
928     {
929         /* Non-NT bootloaders: install our own bootloader */
930 
931         PCWSTR Section;
932         PCWSTR Description;
933         PCWSTR BootDrive;
934         PCWSTR BootPartition;
935         PCWSTR BootSector;
936 
937         /* Search for COMPAQ MS-DOS 1.x (1.11, 1.12, based on MS-DOS 1.25) boot loader */
938         if (DoesFileExist_2(SystemRootPath->Buffer, L"IOSYS.COM") == TRUE ||
939             DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.COM") == TRUE)
940         {
941             DPRINT1("Found COMPAQ MS-DOS 1.x (1.11, 1.12) / MS-DOS 1.25 boot loader\n");
942 
943             Section       = L"CPQDOS";
944             Description   = L"\"COMPAQ MS-DOS 1.x / MS-DOS 1.25\"";
945             BootDrive     = L"hd0";
946             BootPartition = L"1";
947             BootSector    = L"BOOTSECT.DOS";
948         }
949         else
950         /* Search for Microsoft DOS or Windows 9x boot loader */
951         if (DoesFileExist_2(SystemRootPath->Buffer, L"IO.SYS") == TRUE ||
952             DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.SYS") == TRUE)
953             // WINBOOT.SYS
954         {
955             DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
956 
957             Section       = L"MSDOS";
958             Description   = L"\"MS-DOS/Windows\"";
959             BootDrive     = L"hd0";
960             BootPartition = L"1";
961             BootSector    = L"BOOTSECT.DOS";
962         }
963         else
964         /* Search for IBM PC-DOS or DR-DOS 5.x boot loader */
965         if (DoesFileExist_2(SystemRootPath->Buffer, L"IBMIO.COM" ) == TRUE || // Some people refer to this file instead of IBMBIO.COM...
966             DoesFileExist_2(SystemRootPath->Buffer, L"IBMBIO.COM") == TRUE ||
967             DoesFileExist_2(SystemRootPath->Buffer, L"IBMDOS.COM") == TRUE)
968         {
969             DPRINT1("Found IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\n");
970 
971             Section       = L"IBMDOS";
972             Description   = L"\"IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\"";
973             BootDrive     = L"hd0";
974             BootPartition = L"1";
975             BootSector    = L"BOOTSECT.DOS";
976         }
977         else
978         /* Search for DR-DOS 3.x boot loader */
979         if (DoesFileExist_2(SystemRootPath->Buffer, L"DRBIOS.SYS") == TRUE ||
980             DoesFileExist_2(SystemRootPath->Buffer, L"DRBDOS.SYS") == TRUE)
981         {
982             DPRINT1("Found DR-DOS 3.x\n");
983 
984             Section       = L"DRDOS";
985             Description   = L"\"DR-DOS 3.x\"";
986             BootDrive     = L"hd0";
987             BootPartition = L"1";
988             BootSector    = L"BOOTSECT.DOS";
989         }
990         else
991         /* Search for Dell Real-Mode Kernel (DRMK) OS */
992         if (DoesFileExist_2(SystemRootPath->Buffer, L"DELLBIO.BIN") == TRUE ||
993             DoesFileExist_2(SystemRootPath->Buffer, L"DELLRMK.BIN") == TRUE)
994         {
995             DPRINT1("Found Dell Real-Mode Kernel OS\n");
996 
997             Section       = L"DRMK";
998             Description   = L"\"Dell Real-Mode Kernel OS\"";
999             BootDrive     = L"hd0";
1000             BootPartition = L"1";
1001             BootSector    = L"BOOTSECT.DOS";
1002         }
1003         else
1004         /* Search for MS OS/2 1.x */
1005         if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT.COM") == TRUE ||
1006             DoesFileExist_2(SystemRootPath->Buffer, L"OS2BIO.COM" ) == TRUE ||
1007             DoesFileExist_2(SystemRootPath->Buffer, L"OS2DOS.COM" ) == TRUE)
1008         {
1009             DPRINT1("Found MS OS/2 1.x\n");
1010 
1011             Section       = L"MSOS2";
1012             Description   = L"\"MS OS/2 1.x\"";
1013             BootDrive     = L"hd0";
1014             BootPartition = L"1";
1015             BootSector    = L"BOOTSECT.OS2";
1016         }
1017         else
1018         /* Search for MS or IBM OS/2 */
1019         if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT") == TRUE ||
1020             DoesFileExist_2(SystemRootPath->Buffer, L"OS2LDR" ) == TRUE ||
1021             DoesFileExist_2(SystemRootPath->Buffer, L"OS2KRNL") == TRUE)
1022         {
1023             DPRINT1("Found MS/IBM OS/2\n");
1024 
1025             Section       = L"IBMOS2";
1026             Description   = L"\"MS/IBM OS/2\"";
1027             BootDrive     = L"hd0";
1028             BootPartition = L"1";
1029             BootSector    = L"BOOTSECT.OS2";
1030         }
1031         else
1032         /* Search for FreeDOS boot loader */
1033         if (DoesFileExist_2(SystemRootPath->Buffer, L"kernel.sys") == TRUE)
1034         {
1035             DPRINT1("Found FreeDOS boot loader\n");
1036 
1037             Section       = L"FDOS";
1038             Description   = L"\"FreeDOS\"";
1039             BootDrive     = L"hd0";
1040             BootPartition = L"1";
1041             BootSector    = L"BOOTSECT.DOS";
1042         }
1043         else
1044         {
1045             /* No or unknown boot loader */
1046             DPRINT1("No or unknown boot loader found\n");
1047 
1048             Section       = L"Unknown";
1049             Description   = L"\"Unknown Operating System\"";
1050             BootDrive     = L"hd0";
1051             BootPartition = L"1";
1052             BootSector    = L"BOOTSECT.OLD";
1053         }
1054 
1055         /* Create or update 'freeldr.ini' */
1056         if (DoesFreeLdrExist == FALSE)
1057         {
1058             /* Create new 'freeldr.ini' */
1059             DPRINT1("Create new 'freeldr.ini'\n");
1060 
1061             if (IsThereAValidBootSector(SystemRootPath->Buffer))
1062             {
1063                 Status = CreateFreeLoaderIniForReactOSAndBootSector(
1064                              SystemRootPath->Buffer, DestinationArcPath->Buffer,
1065                              Section, Description,
1066                              BootDrive, BootPartition, BootSector);
1067                 if (!NT_SUCCESS(Status))
1068                 {
1069                     DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
1070                     return Status;
1071                 }
1072 
1073                 /* Save current bootsector */
1074                 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
1075 
1076                 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
1077                 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE);
1078                 if (!NT_SUCCESS(Status))
1079                 {
1080                     DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
1081                     return Status;
1082                 }
1083             }
1084             else
1085             {
1086                 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1087                 if (!NT_SUCCESS(Status))
1088                 {
1089                     DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
1090                     return Status;
1091                 }
1092             }
1093 
1094             /* Install new bootsector on the disk */
1095             if (wcsicmp(FileSystemName, L"FAT32") == 0)
1096             {
1097                 /* Install FAT32 bootcode */
1098                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin");
1099 
1100                 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
1101                 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat32BootCode);
1102                 DPRINT1("Status: 0x%08X\n", Status);
1103                 if (!NT_SUCCESS(Status))
1104                 {
1105                     DPRINT1("InstallBootCodeToDisk(FAT32) failed (Status %lx)\n", Status);
1106                     return Status;
1107                 }
1108             }
1109             else // if (wcsicmp(FileSystemName, L"FAT") == 0)
1110             {
1111                 /* Install FAT16 bootcode */
1112                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
1113 
1114                 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
1115                 Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat16BootCode);
1116                 if (!NT_SUCCESS(Status))
1117                 {
1118                     DPRINT1("InstallBootCodeToDisk(FAT16) failed (Status %lx)\n", Status);
1119                     return Status;
1120                 }
1121             }
1122         }
1123     }
1124 
1125     return STATUS_SUCCESS;
1126 }
1127 
1128 static
1129 NTSTATUS
1130 InstallBtrfsBootcodeToPartition(
1131     IN PUNICODE_STRING SystemRootPath,
1132     IN PUNICODE_STRING SourceRootPath,
1133     IN PUNICODE_STRING DestinationArcPath)
1134 {
1135     NTSTATUS Status;
1136     BOOLEAN DoesFreeLdrExist;
1137     WCHAR SrcPath[MAX_PATH];
1138     WCHAR DstPath[MAX_PATH];
1139 
1140     /* BTRFS partition */
1141     DPRINT("System path: '%wZ'\n", SystemRootPath);
1142 
1143     /* Copy FreeLoader to the system partition, always overwriting the older version */
1144     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
1145     CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
1146 
1147     DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
1148     Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1149     if (!NT_SUCCESS(Status))
1150     {
1151         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1152         return Status;
1153     }
1154 
1155     /* Prepare for possibly updating 'freeldr.ini' */
1156     DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini");
1157     if (DoesFreeLdrExist)
1158     {
1159         /* Update existing 'freeldr.ini' */
1160         DPRINT1("Update existing 'freeldr.ini'\n");
1161         Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1162         if (!NT_SUCCESS(Status))
1163         {
1164             DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
1165             return Status;
1166         }
1167     }
1168 
1169     /* Check for *nix bootloaders */
1170 
1171     /* Create or update 'freeldr.ini' */
1172     if (DoesFreeLdrExist == FALSE)
1173     {
1174         /* Create new 'freeldr.ini' */
1175         DPRINT1("Create new 'freeldr.ini'\n");
1176 
1177         /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */
1178         DPRINT1("*nix or unknown boot loader found\n");
1179 
1180         if (IsThereAValidBootSector(SystemRootPath->Buffer))
1181         {
1182             PCWSTR BootSector = L"BOOTSECT.OLD";
1183 
1184             Status = CreateFreeLoaderIniForReactOSAndBootSector(
1185                          SystemRootPath->Buffer, DestinationArcPath->Buffer,
1186                          L"Linux", L"\"Linux\"",
1187                          L"hd0", L"1", BootSector);
1188             if (!NT_SUCCESS(Status))
1189             {
1190                 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
1191                 return Status;
1192             }
1193 
1194             /* Save current bootsector */
1195             CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
1196 
1197             DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
1198             Status = SaveBootSector(SystemRootPath->Buffer, DstPath, BTRFS_BOOTSECTOR_SIZE);
1199             if (!NT_SUCCESS(Status))
1200             {
1201                 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
1202                 return Status;
1203             }
1204         }
1205         else
1206         {
1207             Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1208             if (!NT_SUCCESS(Status))
1209             {
1210                 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
1211                 return Status;
1212             }
1213         }
1214 
1215         /* Install new bootsector on the disk */
1216         /* Install BTRFS bootcode */
1217         CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin");
1218 
1219         DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
1220         Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallBtrfsBootCode);
1221         if (!NT_SUCCESS(Status))
1222         {
1223             DPRINT1("InstallBootCodeToDisk(BTRFS) failed (Status %lx)\n", Status);
1224             return Status;
1225         }
1226     }
1227 
1228     return STATUS_SUCCESS;
1229 }
1230 
1231 
1232 NTSTATUS
1233 InstallVBRToPartition(
1234     IN PUNICODE_STRING SystemRootPath,
1235     IN PUNICODE_STRING SourceRootPath,
1236     IN PUNICODE_STRING DestinationArcPath,
1237     IN PCWSTR FileSystemName)
1238 {
1239     if (wcsicmp(FileSystemName, L"FAT")   == 0 ||
1240         wcsicmp(FileSystemName, L"FAT32") == 0)
1241     {
1242         return InstallFatBootcodeToPartition(SystemRootPath,
1243                                              SourceRootPath,
1244                                              DestinationArcPath,
1245                                              FileSystemName);
1246     }
1247     /*
1248     else if (wcsicmp(FileSystemName, L"NTFS") == 0)
1249     {
1250         DPRINT1("Partitions of type NTFS or HPFS are not supported yet!\n");
1251         return STATUS_NOT_SUPPORTED;
1252     }
1253     */
1254     else if (wcsicmp(FileSystemName, L"BTRFS") == 0)
1255     {
1256         return InstallBtrfsBootcodeToPartition(SystemRootPath,
1257                                                SourceRootPath,
1258                                                DestinationArcPath);
1259     }
1260     /*
1261     else if (wcsicmp(FileSystemName, L"EXT2")  == 0 ||
1262              wcsicmp(FileSystemName, L"EXT3")  == 0 ||
1263              wcsicmp(FileSystemName, L"EXT4")  == 0 ||
1264              wcsicmp(FileSystemName, L"FFS")   == 0 ||
1265              wcsicmp(FileSystemName, L"REISERFS") == 0)
1266     {
1267         return STATUS_NOT_SUPPORTED;
1268     }
1269     */
1270     else
1271     {
1272         /* Unknown file system */
1273         DPRINT1("Unknown file system '%S'\n", FileSystemName);
1274     }
1275 
1276     return STATUS_NOT_SUPPORTED;
1277 }
1278 
1279 
1280 NTSTATUS
1281 InstallFatBootcodeToFloppy(
1282     IN PUNICODE_STRING SourceRootPath,
1283     IN PUNICODE_STRING DestinationArcPath)
1284 {
1285     static const PCWSTR FloppyDevice = L"\\Device\\Floppy0\\";
1286 
1287     NTSTATUS Status;
1288     WCHAR SrcPath[MAX_PATH];
1289     WCHAR DstPath[MAX_PATH];
1290 
1291     /* Verify that the floppy disk is accessible */
1292     if (DoesDirExist(NULL, FloppyDevice) == FALSE)
1293         return STATUS_DEVICE_NOT_READY;
1294 
1295     /* Format the floppy disk */
1296     // FormatPartition(...)
1297     Status = FormatFileSystem(FloppyDevice,
1298                               L"FAT",
1299                               FMIFS_FLOPPY,
1300                               NULL,
1301                               TRUE,
1302                               0,
1303                               NULL);
1304     if (!NT_SUCCESS(Status))
1305     {
1306         if (Status == STATUS_NOT_SUPPORTED)
1307             DPRINT1("FAT FS non existent on this system?!\n");
1308         else
1309             DPRINT1("VfatFormat() failed (Status %lx)\n", Status);
1310 
1311         return Status;
1312     }
1313 
1314     /* Copy FreeLoader to the boot partition */
1315     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
1316     CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice, L"freeldr.sys");
1317 
1318     DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
1319     Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1320     if (!NT_SUCCESS(Status))
1321     {
1322         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1323         return Status;
1324     }
1325 
1326     /* Create new 'freeldr.ini' */
1327     DPRINT("Create new 'freeldr.ini'\n");
1328     Status = CreateFreeLoaderIniForReactOS(FloppyDevice, DestinationArcPath->Buffer);
1329     if (!NT_SUCCESS(Status))
1330     {
1331         DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
1332         return Status;
1333     }
1334 
1335     /* Install FAT12 boosector */
1336     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
1337     CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice);
1338 
1339     DPRINT("Install FAT12 bootcode: %S ==> %S\n", SrcPath, DstPath);
1340     Status = InstallBootCodeToDisk(SrcPath, DstPath, InstallFat12BootCode);
1341     if (!NT_SUCCESS(Status))
1342     {
1343         DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status %lx)\n", Status);
1344         return Status;
1345     }
1346 
1347     return STATUS_SUCCESS;
1348 }
1349 
1350 /* EOF */
1351