xref: /reactos/base/setup/lib/bootsup.c (revision 7eead935)
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 "fsutil.h"
17 #include "partlist.h"
18 
19 #include "setuplib.h" // HAXX for IsUnattendedSetup!!
20 
21 #include "bootsup.h"
22 
23 #define NDEBUG
24 #include <debug.h>
25 
26 
27 /* TYPEDEFS *****************************************************************/
28 
29 /*
30  * BIG FIXME!!
31  * ===========
32  *
33  * All that stuff *MUST* go into the fsutil.c module.
34  * Indeed, all that relates to filesystem formatting details and as such
35  * *MUST* be abstracted out from this module (bootsup.c).
36  * However, bootsup.c can still deal with MBR code (actually it'll have
37  * at some point to share or give it to partlist.c, because when we'll
38  * support GPT disks, things will change a bit).
39  * And, bootsup.c can still manage initializing / adding boot entries
40  * into NTLDR and FREELDR, and installing the latter, and saving the old
41  * MBR / boot sectors in files.
42  */
43 #define SECTORSIZE 512
44 
45 #include <pshpack1.h>
46 typedef struct _FAT_BOOTSECTOR
47 {
48     UCHAR       JumpBoot[3];                // Jump instruction to boot code
49     CHAR        OemName[8];                 // "MSWIN4.1" for MS formatted volumes
50     USHORT      BytesPerSector;             // Bytes per sector
51     UCHAR       SectorsPerCluster;          // Number of sectors in a cluster
52     USHORT      ReservedSectors;            // Reserved sectors, usually 1 (the bootsector)
53     UCHAR       NumberOfFats;               // Number of FAT tables
54     USHORT      RootDirEntries;             // Number of root directory entries (fat12/16)
55     USHORT      TotalSectors;               // Number of total sectors on the drive, 16-bit
56     UCHAR       MediaDescriptor;            // Media descriptor byte
57     USHORT      SectorsPerFat;              // Sectors per FAT table (fat12/16)
58     USHORT      SectorsPerTrack;            // Number of sectors in a track
59     USHORT      NumberOfHeads;              // Number of heads on the disk
60     ULONG       HiddenSectors;              // Hidden sectors (sectors before the partition start like the partition table)
61     ULONG       TotalSectorsBig;            // This field is the new 32-bit total count of sectors on the volume
62     UCHAR       DriveNumber;                // Int 0x13 drive number (e.g. 0x80)
63     UCHAR       Reserved1;                  // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
64     UCHAR       BootSignature;              // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
65     ULONG       VolumeSerialNumber;         // Volume serial number
66     CHAR        VolumeLabel[11];            // Volume label. This field matches the 11-byte volume label recorded in the root directory
67     CHAR        FileSystemType[8];          // One of the strings "FAT12   ", "FAT16   ", or "FAT     "
68 
69     UCHAR       BootCodeAndData[448];       // The remainder of the boot sector
70 
71     USHORT      BootSectorMagic;            // 0xAA55
72 
73 } FAT_BOOTSECTOR, *PFAT_BOOTSECTOR;
74 
75 typedef struct _FAT32_BOOTSECTOR
76 {
77     UCHAR       JumpBoot[3];                // Jump instruction to boot code
78     CHAR        OemName[8];                 // "MSWIN4.1" for MS formatted volumes
79     USHORT      BytesPerSector;             // Bytes per sector
80     UCHAR       SectorsPerCluster;          // Number of sectors in a cluster
81     USHORT      ReservedSectors;            // Reserved sectors, usually 1 (the bootsector)
82     UCHAR       NumberOfFats;               // Number of FAT tables
83     USHORT      RootDirEntries;             // Number of root directory entries (fat12/16)
84     USHORT      TotalSectors;               // Number of total sectors on the drive, 16-bit
85     UCHAR       MediaDescriptor;            // Media descriptor byte
86     USHORT      SectorsPerFat;              // Sectors per FAT table (fat12/16)
87     USHORT      SectorsPerTrack;            // Number of sectors in a track
88     USHORT      NumberOfHeads;              // Number of heads on the disk
89     ULONG       HiddenSectors;              // Hidden sectors (sectors before the partition start like the partition table)
90     ULONG       TotalSectorsBig;            // This field is the new 32-bit total count of sectors on the volume
91     ULONG       SectorsPerFatBig;           // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0
92     USHORT      ExtendedFlags;              // Extended flags (fat32)
93     USHORT      FileSystemVersion;          // File system version (fat32)
94     ULONG       RootDirStartCluster;        // Starting cluster of the root directory (fat32)
95     USHORT      FsInfo;                     // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1.
96     USHORT      BackupBootSector;           // If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6.
97     UCHAR       Reserved[12];               // Reserved for future expansion
98     UCHAR       DriveNumber;                // Int 0x13 drive number (e.g. 0x80)
99     UCHAR       Reserved1;                  // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
100     UCHAR       BootSignature;              // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
101     ULONG       VolumeSerialNumber;         // Volume serial number
102     CHAR        VolumeLabel[11];            // Volume label. This field matches the 11-byte volume label recorded in the root directory
103     CHAR        FileSystemType[8];          // Always set to the string "FAT32   "
104 
105     UCHAR       BootCodeAndData[420];       // The remainder of the boot sector
106 
107     USHORT      BootSectorMagic;            // 0xAA55
108 
109 } FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR;
110 
111 typedef struct _BTRFS_BOOTSECTOR
112 {
113     UCHAR JumpBoot[3];
114     UCHAR ChunkMapSize;
115     UCHAR BootDrive;
116     ULONGLONG PartitionStartLBA;
117     UCHAR Fill[1521]; // 1536 - 15
118     USHORT BootSectorMagic;
119 } BTRFS_BOOTSECTOR, *PBTRFS_BOOTSECTOR;
120 C_ASSERT(sizeof(BTRFS_BOOTSECTOR) == 3 * 512);
121 
122 // TODO: Add more bootsector structures!
123 
124 #include <poppack.h>
125 
126 /* End of BIG FIXME!! */
127 
128 
129 /* FUNCTIONS ****************************************************************/
130 
131 static VOID
132 TrimTrailingPathSeparators_UStr(
133     IN OUT PUNICODE_STRING UnicodeString)
134 {
135     while (UnicodeString->Length >= sizeof(WCHAR) &&
136            UnicodeString->Buffer[UnicodeString->Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
137     {
138         UnicodeString->Length -= sizeof(WCHAR);
139     }
140 }
141 
142 
143 static VOID
144 CreateFreeLoaderReactOSEntries(
145     IN PVOID BootStoreHandle,
146     IN PCWSTR ArcPath)
147 {
148     UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
149     PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
150     PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
151     BOOT_STORE_OPTIONS BootOptions;
152 
153     BootEntry->Version = FreeLdr;
154     BootEntry->BootFilePath = NULL;
155 
156     BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
157     RtlCopyMemory(Options->Signature,
158                   NTOS_OPTIONS_SIGNATURE,
159                   RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
160 
161     Options->OsLoadPath = ArcPath;
162 
163     /* ReactOS */
164     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS");
165     BootEntry->FriendlyName = L"\"ReactOS\"";
166     Options->OsLoadOptions  = NULL; // L"";
167     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS"));
168 
169     /* ReactOS_Debug */
170     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Debug");
171     BootEntry->FriendlyName = L"\"ReactOS (Debug)\"";
172     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS";
173     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Debug"));
174 
175 #ifdef _WINKD_
176     /* ReactOS_VBoxDebug */
177     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_VBoxDebug");
178     BootEntry->FriendlyName = L"\"ReactOS (VBoxDebug)\"";
179     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=VBOX /SOS";
180     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_VBoxDebug"));
181 #endif
182 #if DBG
183 #ifndef _WINKD_
184     /* ReactOS_KdSerial */
185     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial");
186     BootEntry->FriendlyName = L"\"ReactOS (RosDbg)\"";
187     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /KDSERIAL";
188     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_KdSerial"));
189 #endif
190 
191     /* ReactOS_Screen */
192     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Screen");
193     BootEntry->FriendlyName = L"\"ReactOS (Screen)\"";
194     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=SCREEN /SOS";
195     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Screen"));
196 
197     /* ReactOS_LogFile */
198     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_LogFile");
199     BootEntry->FriendlyName = L"\"ReactOS (Log file)\"";
200     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=FILE /SOS";
201     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_LogFile"));
202 
203     /* ReactOS_Ram */
204     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_Ram");
205     BootEntry->FriendlyName = L"\"ReactOS (RAM Disk)\"";
206     Options->OsLoadPath     = L"ramdisk(0)\\ReactOS";
207     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /RDPATH=reactos.img /RDIMAGEOFFSET=32256";
208     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_Ram"));
209 
210     /* ReactOS_EMS */
211     // BootEntry->BootEntryKey = MAKESTRKEY(L"ReactOS_EMS");
212     BootEntry->FriendlyName = L"\"ReactOS (Emergency Management Services)\"";
213     Options->OsLoadPath     = ArcPath;
214     Options->OsLoadOptions  = L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /redirect=com2 /redirectbaudrate=115200";
215     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(L"ReactOS_EMS"));
216 #endif
217 
218 
219 #if DBG
220     if (IsUnattendedSetup)
221     {
222         /* DefaultOS=ReactOS */
223 #ifndef _WINKD_
224         BootOptions.CurrentBootEntryKey = MAKESTRKEY(L"ReactOS_KdSerial");
225 #else
226         BootOptions.CurrentBootEntryKey = MAKESTRKEY(L"ReactOS_Debug");
227 #endif
228     }
229     else
230 #endif
231     {
232         /* DefaultOS=ReactOS */
233         BootOptions.CurrentBootEntryKey = MAKESTRKEY(L"ReactOS");
234     }
235 
236 #if DBG
237     if (IsUnattendedSetup)
238 #endif
239     {
240         /* Timeout=0 for unattended or non debug */
241         BootOptions.Timeout = 0;
242     }
243 #if DBG
244     else
245     {
246         /* Timeout=10 */
247         BootOptions.Timeout = 10;
248     }
249 #endif
250 
251     BootOptions.Version = FreeLdr;
252     SetBootStoreOptions(BootStoreHandle, &BootOptions, 2 | 1);
253 }
254 
255 static NTSTATUS
256 CreateFreeLoaderIniForReactOS(
257     IN PCWSTR IniPath,
258     IN PCWSTR ArcPath)
259 {
260     NTSTATUS Status;
261     PVOID BootStoreHandle;
262 
263     /* Initialize the INI file and create the common FreeLdr sections */
264     Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, TRUE);
265     if (!NT_SUCCESS(Status))
266         return Status;
267 
268     /* Add the ReactOS entries */
269     CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath);
270 
271     /* Close the INI file */
272     CloseBootStore(BootStoreHandle);
273     return STATUS_SUCCESS;
274 }
275 
276 static NTSTATUS
277 CreateFreeLoaderIniForReactOSAndBootSector(
278     IN PCWSTR IniPath,
279     IN PCWSTR ArcPath,
280     IN PCWSTR Section,
281     IN PCWSTR Description,
282     IN PCWSTR BootDrive,
283     IN PCWSTR BootPartition,
284     IN PCWSTR BootSector)
285 {
286     NTSTATUS Status;
287     PVOID BootStoreHandle;
288     UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(BOOT_SECTOR_OPTIONS)];
289     PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
290     PBOOT_SECTOR_OPTIONS Options = (PBOOT_SECTOR_OPTIONS)&BootEntry->OsOptions;
291 
292     /* Initialize the INI file and create the common FreeLdr sections */
293     Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, TRUE);
294     if (!NT_SUCCESS(Status))
295         return Status;
296 
297     /* Add the ReactOS entries */
298     CreateFreeLoaderReactOSEntries(BootStoreHandle, ArcPath);
299 
300     BootEntry->Version = FreeLdr;
301     BootEntry->BootFilePath = NULL;
302 
303     BootEntry->OsOptionsLength = sizeof(BOOT_SECTOR_OPTIONS);
304     RtlCopyMemory(Options->Signature,
305                   BOOT_SECTOR_OPTIONS_SIGNATURE,
306                   RTL_FIELD_SIZE(BOOT_SECTOR_OPTIONS, Signature));
307 
308     Options->Drive = BootDrive;
309     Options->Partition = BootPartition;
310     Options->BootSectorFileName = BootSector;
311 
312     // BootEntry->BootEntryKey = MAKESTRKEY(Section);
313     BootEntry->FriendlyName = Description;
314     AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Section));
315 
316     /* Close the INI file */
317     CloseBootStore(BootStoreHandle);
318     return STATUS_SUCCESS;
319 }
320 
321 //
322 // I think this function can be generalizable as:
323 // "find the corresponding 'ReactOS' boot entry in this loader config file
324 // (here abstraction comes there), and if none, add a new one".
325 //
326 
327 typedef struct _ENUM_REACTOS_ENTRIES_DATA
328 {
329     ULONG i;
330     BOOLEAN UseExistingEntry;
331     PCWSTR ArcPath;
332     WCHAR SectionName[80];
333     WCHAR OsName[80];
334 } ENUM_REACTOS_ENTRIES_DATA, *PENUM_REACTOS_ENTRIES_DATA;
335 
336 // PENUM_BOOT_ENTRIES_ROUTINE
337 static NTSTATUS
338 NTAPI
339 EnumerateReactOSEntries(
340     IN BOOT_STORE_TYPE Type,
341     IN PBOOT_STORE_ENTRY BootEntry,
342     IN PVOID Parameter OPTIONAL)
343 {
344     NTSTATUS Status;
345     PENUM_REACTOS_ENTRIES_DATA Data = (PENUM_REACTOS_ENTRIES_DATA)Parameter;
346     PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
347     WCHAR SystemPath[MAX_PATH];
348 
349     /* We have a boot entry */
350 
351     /* Check for supported boot type "Windows2003" */
352     if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) ||
353         RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
354                          NTOS_OPTIONS_SIGNATURE,
355                          RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) !=
356                          RTL_FIELD_SIZE(NTOS_OPTIONS, Signature))
357     {
358         /* This is not a ReactOS entry */
359         // DPRINT("    An installation '%S' of unsupported type '%S'\n",
360                // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a");
361         DPRINT("    An installation '%S' of unsupported type %lu\n",
362                BootEntry->FriendlyName, BootEntry->OsOptionsLength);
363         /* Continue the enumeration */
364         goto SkipThisEntry;
365     }
366 
367     /* BootType is Windows2003, now check OsLoadPath */
368     if (!Options->OsLoadPath || !*Options->OsLoadPath)
369     {
370         /* Certainly not a ReactOS installation */
371         DPRINT1("    A Win2k3 install '%S' without an ARC path?!\n", BootEntry->FriendlyName);
372         /* Continue the enumeration */
373         goto SkipThisEntry;
374     }
375 
376     if (_wcsicmp(Options->OsLoadPath, Data->ArcPath) != 0)
377     {
378         /* Not found, retry with a quoted path */
379         Status = RtlStringCchPrintfW(SystemPath, ARRAYSIZE(SystemPath), L"\"%s\"", Data->ArcPath);
380         if (!NT_SUCCESS(Status) || _wcsicmp(Options->OsLoadPath, SystemPath) != 0)
381         {
382             /*
383              * This entry is a ReactOS entry, but the SystemRoot
384              * does not match the one we are looking for.
385              */
386             /* Continue the enumeration */
387             goto SkipThisEntry;
388         }
389     }
390 
391     DPRINT("    Found a candidate Win2k3 install '%S' with ARC path '%S'\n",
392            BootEntry->FriendlyName, Options->OsLoadPath);
393     // DPRINT("    Found a Win2k3 install '%S' with ARC path '%S'\n",
394            // BootEntry->FriendlyName, Options->OsLoadPath);
395 
396     DPRINT("EnumerateReactOSEntries: OsLoadPath: '%S'\n", Options->OsLoadPath);
397 
398     Data->UseExistingEntry = TRUE;
399     RtlStringCchCopyW(Data->OsName, ARRAYSIZE(Data->OsName), BootEntry->FriendlyName);
400 
401     /* We have found our entry, stop the enumeration now! */
402     return STATUS_NO_MORE_ENTRIES;
403 
404 SkipThisEntry:
405     Data->UseExistingEntry = FALSE;
406     if (Type == FreeLdr && wcscmp(Data->SectionName, (PWSTR)BootEntry->BootEntryKey)== 0)
407     {
408         RtlStringCchPrintfW(Data->SectionName, ARRAYSIZE(Data->SectionName),
409                             L"ReactOS_%lu", Data->i);
410         RtlStringCchPrintfW(Data->OsName, ARRAYSIZE(Data->OsName),
411                             L"\"ReactOS %lu\"", Data->i);
412         Data->i++;
413     }
414     return STATUS_SUCCESS;
415 }
416 
417 static
418 NTSTATUS
419 UpdateFreeLoaderIni(
420     IN PCWSTR IniPath,
421     IN PCWSTR ArcPath)
422 {
423     NTSTATUS Status;
424     PVOID BootStoreHandle;
425     ENUM_REACTOS_ENTRIES_DATA Data;
426     UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
427     PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
428     PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
429 
430     /* Open the INI file */
431     Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, /*TRUE*/ FALSE);
432     if (!NT_SUCCESS(Status))
433         return Status;
434 
435     /* Find an existing usable or an unused section name */
436     Data.UseExistingEntry = TRUE;
437     Data.i = 1;
438     Data.ArcPath = ArcPath;
439     RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS");
440     RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\"");
441 
442     //
443     // FIXME: We temporarily use EnumerateBootStoreEntries, until
444     // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented.
445     //
446     Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data);
447 
448     /* Create a new "ReactOS" entry if there is none already existing that suits us */
449     if (!Data.UseExistingEntry)
450     {
451         // RtlStringCchPrintfW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS_%lu", Data.i);
452         // RtlStringCchPrintfW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS %lu\"", Data.i);
453 
454         BootEntry->Version = FreeLdr;
455         BootEntry->BootFilePath = NULL;
456 
457         BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
458         RtlCopyMemory(Options->Signature,
459                       NTOS_OPTIONS_SIGNATURE,
460                       RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
461 
462         Options->OsLoadPath = ArcPath;
463 
464         // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName);
465         BootEntry->FriendlyName = Data.OsName;
466         Options->OsLoadOptions  = NULL; // L"";
467         AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Data.SectionName));
468     }
469 
470     /* Close the INI file */
471     CloseBootStore(BootStoreHandle);
472     return STATUS_SUCCESS;
473 }
474 
475 static
476 NTSTATUS
477 UpdateBootIni(
478     IN PCWSTR IniPath,
479     IN PCWSTR EntryName,    // ~= ArcPath
480     IN PCWSTR EntryValue)
481 {
482     NTSTATUS Status;
483     PVOID BootStoreHandle;
484     ENUM_REACTOS_ENTRIES_DATA Data;
485 
486     // NOTE: Technically it would be "BootSector"...
487     UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
488     PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
489     PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
490 
491     /* Open the INI file */
492     Status = OpenBootStore(&BootStoreHandle, IniPath, NtLdr, FALSE);
493     if (!NT_SUCCESS(Status))
494         return Status;
495 
496     /* Find an existing usable or an unused section name */
497     Data.UseExistingEntry = TRUE;
498     // Data.i = 1;
499     Data.ArcPath = EntryName;
500     // RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS");
501     RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\"");
502 
503     //
504     // FIXME: We temporarily use EnumerateBootStoreEntries, until
505     // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented.
506     //
507     Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data);
508 
509     /* If either the key was not found, or contains something else, add a new one */
510     if (!Data.UseExistingEntry /* ||
511         ( (Status == STATUS_NO_MORE_ENTRIES) && wcscmp(Data.OsName, EntryValue) ) */)
512     {
513         BootEntry->Version = NtLdr;
514         BootEntry->BootFilePath = NULL;
515 
516         BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
517         RtlCopyMemory(Options->Signature,
518                       NTOS_OPTIONS_SIGNATURE,
519                       RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
520 
521         Options->OsLoadPath = EntryName;
522 
523         // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName);
524         // BootEntry->FriendlyName = Data.OsName;
525         BootEntry->FriendlyName = EntryValue;
526         Options->OsLoadOptions  = NULL; // L"";
527         AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(0 /*Data.SectionName*/));
528     }
529 
530     /* Close the INI file */
531     CloseBootStore(BootStoreHandle);
532     return STATUS_SUCCESS; // Status;
533 }
534 
535 
536 static
537 BOOLEAN
538 IsThereAValidBootSector(
539     IN PCWSTR RootPath)
540 {
541     /*
542      * We first demand that the bootsector has a valid signature at its end.
543      * We then check the first 3 bytes (as a ULONG) of the bootsector for a
544      * potential "valid" instruction (the BIOS starts execution of the bootsector
545      * at its beginning). Currently this criterium is that this ULONG must be
546      * non-zero. If both these tests pass, then the bootsector is valid; otherwise
547      * it is invalid and certainly needs to be overwritten.
548      */
549 
550     BOOLEAN IsValid = FALSE;
551     NTSTATUS Status;
552     UNICODE_STRING RootPartition;
553     OBJECT_ATTRIBUTES ObjectAttributes;
554     IO_STATUS_BLOCK IoStatusBlock;
555     HANDLE FileHandle;
556     LARGE_INTEGER FileOffset;
557     PUCHAR BootSector;
558 
559     /* Allocate buffer for bootsector */
560     BootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
561     if (BootSector == NULL)
562         return FALSE; // STATUS_INSUFFICIENT_RESOURCES;
563     RtlZeroMemory(BootSector, SECTORSIZE);
564 
565     /* Open the root partition - Remove any trailing backslash if needed */
566     RtlInitUnicodeString(&RootPartition, RootPath);
567     TrimTrailingPathSeparators_UStr(&RootPartition);
568 
569     InitializeObjectAttributes(&ObjectAttributes,
570                                &RootPartition,
571                                OBJ_CASE_INSENSITIVE,
572                                NULL,
573                                NULL);
574 
575     Status = NtOpenFile(&FileHandle,
576                         GENERIC_READ | SYNCHRONIZE,
577                         &ObjectAttributes,
578                         &IoStatusBlock,
579                         FILE_SHARE_READ | FILE_SHARE_WRITE,
580                         FILE_SYNCHRONOUS_IO_NONALERT);
581     if (!NT_SUCCESS(Status))
582         goto Quit;
583 
584     /* Read current boot sector into buffer */
585     FileOffset.QuadPart = 0ULL;
586     Status = NtReadFile(FileHandle,
587                         NULL,
588                         NULL,
589                         NULL,
590                         &IoStatusBlock,
591                         BootSector,
592                         SECTORSIZE,
593                         &FileOffset,
594                         NULL);
595     NtClose(FileHandle);
596     if (!NT_SUCCESS(Status))
597         goto Quit;
598 
599     /* Check for the existence of the bootsector signature */
600     IsValid = (*(PUSHORT)(BootSector + 0x1FE) == 0xAA55);
601     if (IsValid)
602     {
603         /* Check for the first instruction encoded on three bytes */
604         IsValid = (((*(PULONG)BootSector) & 0x00FFFFFF) != 0x00000000);
605     }
606 
607 Quit:
608     /* Free the boot sector */
609     RtlFreeHeap(ProcessHeap, 0, BootSector);
610     return IsValid;
611 }
612 
613 static
614 NTSTATUS
615 SaveBootSector(
616     IN PCWSTR RootPath,
617     IN PCWSTR DstPath,
618     IN ULONG Length)
619 {
620     NTSTATUS Status;
621     UNICODE_STRING Name;
622     OBJECT_ATTRIBUTES ObjectAttributes;
623     IO_STATUS_BLOCK IoStatusBlock;
624     HANDLE FileHandle;
625     LARGE_INTEGER FileOffset;
626     PUCHAR BootSector;
627 
628     /* Allocate buffer for bootsector */
629     BootSector = RtlAllocateHeap(ProcessHeap, 0, Length);
630     if (BootSector == NULL)
631         return STATUS_INSUFFICIENT_RESOURCES;
632 
633     /* Open the root partition - Remove any trailing backslash if needed */
634     RtlInitUnicodeString(&Name, RootPath);
635     TrimTrailingPathSeparators_UStr(&Name);
636 
637     InitializeObjectAttributes(&ObjectAttributes,
638                                &Name,
639                                OBJ_CASE_INSENSITIVE,
640                                NULL,
641                                NULL);
642 
643     Status = NtOpenFile(&FileHandle,
644                         GENERIC_READ | SYNCHRONIZE,
645                         &ObjectAttributes,
646                         &IoStatusBlock,
647                         FILE_SHARE_READ | FILE_SHARE_WRITE,
648                         FILE_SYNCHRONOUS_IO_NONALERT);
649     if (!NT_SUCCESS(Status))
650     {
651         RtlFreeHeap(ProcessHeap, 0, BootSector);
652         return Status;
653     }
654 
655     /* Read current boot sector into buffer */
656     FileOffset.QuadPart = 0ULL;
657     Status = NtReadFile(FileHandle,
658                         NULL,
659                         NULL,
660                         NULL,
661                         &IoStatusBlock,
662                         BootSector,
663                         Length,
664                         &FileOffset,
665                         NULL);
666     NtClose(FileHandle);
667     if (!NT_SUCCESS(Status))
668     {
669         RtlFreeHeap(ProcessHeap, 0, BootSector);
670         return Status;
671     }
672 
673     /* Write bootsector to DstPath */
674     RtlInitUnicodeString(&Name, DstPath);
675     InitializeObjectAttributes(&ObjectAttributes,
676                                &Name,
677                                OBJ_CASE_INSENSITIVE,
678                                NULL,
679                                NULL);
680 
681     Status = NtCreateFile(&FileHandle,
682                           GENERIC_WRITE | SYNCHRONIZE,
683                           &ObjectAttributes,
684                           &IoStatusBlock,
685                           NULL,
686                           FILE_ATTRIBUTE_NORMAL,
687                           0,
688                           FILE_SUPERSEDE,
689                           FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
690                           NULL,
691                           0);
692     if (!NT_SUCCESS(Status))
693     {
694         RtlFreeHeap(ProcessHeap, 0, BootSector);
695         return Status;
696     }
697 
698     Status = NtWriteFile(FileHandle,
699                          NULL,
700                          NULL,
701                          NULL,
702                          &IoStatusBlock,
703                          BootSector,
704                          Length,
705                          NULL,
706                          NULL);
707     NtClose(FileHandle);
708 
709     /* Free the boot sector */
710     RtlFreeHeap(ProcessHeap, 0, BootSector);
711 
712     return Status;
713 }
714 
715 
716 static
717 NTSTATUS
718 InstallMbrBootCodeToDiskHelper(
719     IN PCWSTR SrcPath,
720     IN PCWSTR RootPath)
721 {
722     NTSTATUS Status;
723     UNICODE_STRING Name;
724     OBJECT_ATTRIBUTES ObjectAttributes;
725     IO_STATUS_BLOCK IoStatusBlock;
726     HANDLE FileHandle;
727     LARGE_INTEGER FileOffset;
728     PPARTITION_SECTOR OrigBootSector;
729     PPARTITION_SECTOR NewBootSector;
730 
731     /* Allocate buffer for original bootsector */
732     OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTITION_SECTOR));
733     if (OrigBootSector == NULL)
734         return STATUS_INSUFFICIENT_RESOURCES;
735 
736     /* Open the root partition - Remove any trailing backslash if needed */
737     RtlInitUnicodeString(&Name, RootPath);
738     TrimTrailingPathSeparators_UStr(&Name);
739 
740     InitializeObjectAttributes(&ObjectAttributes,
741                                &Name,
742                                OBJ_CASE_INSENSITIVE,
743                                NULL,
744                                NULL);
745 
746     Status = NtOpenFile(&FileHandle,
747                         GENERIC_READ | SYNCHRONIZE,
748                         &ObjectAttributes,
749                         &IoStatusBlock,
750                         FILE_SHARE_READ | FILE_SHARE_WRITE,
751                         FILE_SYNCHRONOUS_IO_NONALERT);
752     if (!NT_SUCCESS(Status))
753     {
754         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
755         return Status;
756     }
757 
758     /* Read current boot sector into buffer */
759     FileOffset.QuadPart = 0ULL;
760     Status = NtReadFile(FileHandle,
761                         NULL,
762                         NULL,
763                         NULL,
764                         &IoStatusBlock,
765                         OrigBootSector,
766                         sizeof(PARTITION_SECTOR),
767                         &FileOffset,
768                         NULL);
769     NtClose(FileHandle);
770     if (!NT_SUCCESS(Status))
771     {
772         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
773         return Status;
774     }
775 
776     /* Allocate buffer for new bootsector */
777     NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTITION_SECTOR));
778     if (NewBootSector == NULL)
779     {
780         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
781         return STATUS_INSUFFICIENT_RESOURCES;
782     }
783 
784     /* Read new bootsector from SrcPath */
785     RtlInitUnicodeString(&Name, SrcPath);
786     InitializeObjectAttributes(&ObjectAttributes,
787                                &Name,
788                                OBJ_CASE_INSENSITIVE,
789                                NULL,
790                                NULL);
791 
792     Status = NtOpenFile(&FileHandle,
793                         GENERIC_READ | SYNCHRONIZE,
794                         &ObjectAttributes,
795                         &IoStatusBlock,
796                         FILE_SHARE_READ,
797                         FILE_SYNCHRONOUS_IO_NONALERT);
798     if (!NT_SUCCESS(Status))
799     {
800         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
801         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
802         return Status;
803     }
804 
805     Status = NtReadFile(FileHandle,
806                         NULL,
807                         NULL,
808                         NULL,
809                         &IoStatusBlock,
810                         NewBootSector,
811                         sizeof(PARTITION_SECTOR),
812                         NULL,
813                         NULL);
814     NtClose(FileHandle);
815     if (!NT_SUCCESS(Status))
816     {
817         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
818         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
819         return Status;
820     }
821 
822     /*
823      * Copy the disk signature, the reserved fields and
824      * the partition table from the old MBR to the new one.
825      */
826     RtlCopyMemory(&NewBootSector->Signature,
827                   &OrigBootSector->Signature,
828                   sizeof(PARTITION_SECTOR) - offsetof(PARTITION_SECTOR, Signature)
829                     /* Length of partition table */);
830 
831     /* Free the original boot sector */
832     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
833 
834     /* Open the root partition - Remove any trailing backslash if needed */
835     RtlInitUnicodeString(&Name, RootPath);
836     TrimTrailingPathSeparators_UStr(&Name);
837 
838     InitializeObjectAttributes(&ObjectAttributes,
839                                &Name,
840                                OBJ_CASE_INSENSITIVE,
841                                NULL,
842                                NULL);
843 
844     Status = NtOpenFile(&FileHandle,
845                         GENERIC_WRITE | SYNCHRONIZE,
846                         &ObjectAttributes,
847                         &IoStatusBlock,
848                         FILE_SHARE_READ | FILE_SHARE_WRITE,
849                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
850     if (!NT_SUCCESS(Status))
851     {
852         DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
853         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
854         return Status;
855     }
856 
857     /* Write new bootsector to RootPath */
858     FileOffset.QuadPart = 0ULL;
859     Status = NtWriteFile(FileHandle,
860                          NULL,
861                          NULL,
862                          NULL,
863                          &IoStatusBlock,
864                          NewBootSector,
865                          sizeof(PARTITION_SECTOR),
866                          &FileOffset,
867                          NULL);
868     NtClose(FileHandle);
869 
870     /* Free the new boot sector */
871     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
872 
873     return Status;
874 }
875 
876 NTSTATUS
877 InstallMbrBootCodeToDisk(
878     IN PUNICODE_STRING SystemRootPath,
879     IN PUNICODE_STRING SourceRootPath,
880     IN PCWSTR DestinationDevicePathBuffer)
881 {
882     NTSTATUS Status;
883     WCHAR SourceMbrPathBuffer[MAX_PATH];
884     WCHAR DstPath[MAX_PATH];
885 
886 #if 0
887     /*
888      * The DestinationDevicePathBuffer parameter has been built with
889      * the following instruction by the caller; I'm not yet sure whether
890      * I actually want this function to build the path instead, hence
891      * I keep this code here but disabled for now...
892      */
893     WCHAR DestinationDevicePathBuffer[MAX_PATH];
894     RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
895                         L"\\Device\\Harddisk%d\\Partition0",
896                         DiskNumber);
897 #endif
898 
899     CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2,
900                  SourceRootPath->Buffer, L"\\loader\\dosmbr.bin");
901 
902     if (IsThereAValidBootSector(DestinationDevicePathBuffer))
903     {
904         /* Save current MBR */
905         CombinePaths(DstPath, ARRAYSIZE(DstPath), 2,
906                      SystemRootPath->Buffer, L"mbr.old");
907 
908         DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
909         Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
910         if (!NT_SUCCESS(Status))
911         {
912             DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
913             // Don't care if we succeeded or not saving the old MBR, just go ahead.
914         }
915     }
916 
917     DPRINT1("Install MBR bootcode: %S ==> %S\n",
918             SourceMbrPathBuffer, DestinationDevicePathBuffer);
919 
920     return InstallMbrBootCodeToDiskHelper(SourceMbrPathBuffer,
921                                           DestinationDevicePathBuffer);
922 }
923 
924 
925 static
926 NTSTATUS
927 InstallFat12BootCodeToFloppy(
928     IN PCWSTR SrcPath,
929     IN PCWSTR RootPath)
930 {
931     NTSTATUS Status;
932     UNICODE_STRING Name;
933     OBJECT_ATTRIBUTES ObjectAttributes;
934     IO_STATUS_BLOCK IoStatusBlock;
935     HANDLE FileHandle;
936     LARGE_INTEGER FileOffset;
937     PFAT_BOOTSECTOR OrigBootSector;
938     PFAT_BOOTSECTOR NewBootSector;
939 
940     /* Allocate buffer for original bootsector */
941     OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
942     if (OrigBootSector == NULL)
943         return STATUS_INSUFFICIENT_RESOURCES;
944 
945     /* Open the root partition - Remove any trailing backslash if needed */
946     RtlInitUnicodeString(&Name, RootPath);
947     TrimTrailingPathSeparators_UStr(&Name);
948 
949     InitializeObjectAttributes(&ObjectAttributes,
950                                &Name,
951                                OBJ_CASE_INSENSITIVE,
952                                NULL,
953                                NULL);
954 
955     Status = NtOpenFile(&FileHandle,
956                         GENERIC_READ | SYNCHRONIZE,
957                         &ObjectAttributes,
958                         &IoStatusBlock,
959                         FILE_SHARE_READ | FILE_SHARE_WRITE,
960                         FILE_SYNCHRONOUS_IO_NONALERT);
961     if (!NT_SUCCESS(Status))
962     {
963         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
964         return Status;
965     }
966 
967     /* Read current boot sector into buffer */
968     FileOffset.QuadPart = 0ULL;
969     Status = NtReadFile(FileHandle,
970                         NULL,
971                         NULL,
972                         NULL,
973                         &IoStatusBlock,
974                         OrigBootSector,
975                         SECTORSIZE,
976                         &FileOffset,
977                         NULL);
978     NtClose(FileHandle);
979     if (!NT_SUCCESS(Status))
980     {
981         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
982         return Status;
983     }
984 
985     /* Allocate buffer for new bootsector */
986     NewBootSector = RtlAllocateHeap(ProcessHeap,
987                                     0,
988                                     SECTORSIZE);
989     if (NewBootSector == NULL)
990     {
991         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
992         return STATUS_INSUFFICIENT_RESOURCES;
993     }
994 
995     /* Read new bootsector from SrcPath */
996     RtlInitUnicodeString(&Name, SrcPath);
997 
998     InitializeObjectAttributes(&ObjectAttributes,
999                                &Name,
1000                                OBJ_CASE_INSENSITIVE,
1001                                NULL,
1002                                NULL);
1003 
1004     Status = NtOpenFile(&FileHandle,
1005                         GENERIC_READ | SYNCHRONIZE,
1006                         &ObjectAttributes,
1007                         &IoStatusBlock,
1008                         FILE_SHARE_READ,
1009                         FILE_SYNCHRONOUS_IO_NONALERT);
1010     if (!NT_SUCCESS(Status))
1011     {
1012         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1013         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1014         return Status;
1015     }
1016 
1017     Status = NtReadFile(FileHandle,
1018                         NULL,
1019                         NULL,
1020                         NULL,
1021                         &IoStatusBlock,
1022                         NewBootSector,
1023                         SECTORSIZE,
1024                         NULL,
1025                         NULL);
1026     NtClose(FileHandle);
1027     if (!NT_SUCCESS(Status))
1028     {
1029         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1030         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1031         return Status;
1032     }
1033 
1034     /* Adjust bootsector (copy a part of the FAT16 BPB) */
1035     memcpy(&NewBootSector->OemName,
1036            &OrigBootSector->OemName,
1037            FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
1038            FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
1039 
1040     /* Free the original boot sector */
1041     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1042 
1043     /* Open the root partition - Remove any trailing backslash if needed */
1044     RtlInitUnicodeString(&Name, RootPath);
1045     TrimTrailingPathSeparators_UStr(&Name);
1046 
1047     InitializeObjectAttributes(&ObjectAttributes,
1048                                &Name,
1049                                OBJ_CASE_INSENSITIVE,
1050                                NULL,
1051                                NULL);
1052 
1053     Status = NtOpenFile(&FileHandle,
1054                         GENERIC_WRITE | SYNCHRONIZE,
1055                         &ObjectAttributes,
1056                         &IoStatusBlock,
1057                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1058                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1059     if (!NT_SUCCESS(Status))
1060     {
1061         DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1062         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1063         return Status;
1064     }
1065 
1066     /* Write new bootsector to RootPath */
1067     FileOffset.QuadPart = 0ULL;
1068     Status = NtWriteFile(FileHandle,
1069                          NULL,
1070                          NULL,
1071                          NULL,
1072                          &IoStatusBlock,
1073                          NewBootSector,
1074                          SECTORSIZE,
1075                          &FileOffset,
1076                          NULL);
1077     NtClose(FileHandle);
1078 
1079     /* Free the new boot sector */
1080     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1081 
1082     return Status;
1083 }
1084 
1085 static
1086 NTSTATUS
1087 InstallFat16BootCode(
1088     IN PCWSTR SrcPath,          // FAT16 bootsector source file (on the installation medium)
1089     IN HANDLE DstPath,          // Where to save the bootsector built from the source + partition information
1090     IN HANDLE RootPartition)    // Partition holding the (old) FAT16 information
1091 {
1092     NTSTATUS Status;
1093     UNICODE_STRING Name;
1094     OBJECT_ATTRIBUTES ObjectAttributes;
1095     IO_STATUS_BLOCK IoStatusBlock;
1096     HANDLE FileHandle;
1097     LARGE_INTEGER FileOffset;
1098     PFAT_BOOTSECTOR OrigBootSector;
1099     PFAT_BOOTSECTOR NewBootSector;
1100 
1101     /* Allocate a buffer for the original bootsector */
1102     OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1103     if (OrigBootSector == NULL)
1104         return STATUS_INSUFFICIENT_RESOURCES;
1105 
1106     /* Read the current partition boot sector into the buffer */
1107     FileOffset.QuadPart = 0ULL;
1108     Status = NtReadFile(RootPartition,
1109                         NULL,
1110                         NULL,
1111                         NULL,
1112                         &IoStatusBlock,
1113                         OrigBootSector,
1114                         SECTORSIZE,
1115                         &FileOffset,
1116                         NULL);
1117     if (!NT_SUCCESS(Status))
1118     {
1119         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1120         return Status;
1121     }
1122 
1123     /* Allocate a buffer for the new bootsector */
1124     NewBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1125     if (NewBootSector == NULL)
1126     {
1127         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1128         return STATUS_INSUFFICIENT_RESOURCES;
1129     }
1130 
1131     /* Read the new bootsector from SrcPath */
1132     RtlInitUnicodeString(&Name, SrcPath);
1133     InitializeObjectAttributes(&ObjectAttributes,
1134                                &Name,
1135                                OBJ_CASE_INSENSITIVE,
1136                                NULL,
1137                                NULL);
1138 
1139     Status = NtOpenFile(&FileHandle,
1140                         GENERIC_READ | SYNCHRONIZE,
1141                         &ObjectAttributes,
1142                         &IoStatusBlock,
1143                         FILE_SHARE_READ,
1144                         FILE_SYNCHRONOUS_IO_NONALERT);
1145     if (!NT_SUCCESS(Status))
1146     {
1147         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1148         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1149         return Status;
1150     }
1151 
1152     FileOffset.QuadPart = 0ULL;
1153     Status = NtReadFile(FileHandle,
1154                         NULL,
1155                         NULL,
1156                         NULL,
1157                         &IoStatusBlock,
1158                         NewBootSector,
1159                         SECTORSIZE,
1160                         &FileOffset,
1161                         NULL);
1162     NtClose(FileHandle);
1163     if (!NT_SUCCESS(Status))
1164     {
1165         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1166         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1167         return Status;
1168     }
1169 
1170     /* Adjust the bootsector (copy a part of the FAT16 BPB) */
1171     memcpy(&NewBootSector->OemName,
1172            &OrigBootSector->OemName,
1173            FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
1174            FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
1175 
1176     /* Free the original boot sector */
1177     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1178 
1179     /* Write the new bootsector to DstPath */
1180     FileOffset.QuadPart = 0ULL;
1181     Status = NtWriteFile(DstPath,
1182                          NULL,
1183                          NULL,
1184                          NULL,
1185                          &IoStatusBlock,
1186                          NewBootSector,
1187                          SECTORSIZE,
1188                          &FileOffset,
1189                          NULL);
1190 
1191     /* Free the new boot sector */
1192     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1193 
1194     return Status;
1195 }
1196 
1197 static
1198 NTSTATUS
1199 InstallFat16BootCodeToFile(
1200     IN PCWSTR SrcPath,
1201     IN PCWSTR DstPath,
1202     IN PCWSTR RootPath)
1203 {
1204     NTSTATUS Status;
1205     UNICODE_STRING Name;
1206     OBJECT_ATTRIBUTES ObjectAttributes;
1207     IO_STATUS_BLOCK IoStatusBlock;
1208     HANDLE PartitionHandle, FileHandle;
1209 
1210     /*
1211      * Open the root partition from which the boot sector
1212      * parameters will be obtained.
1213      * Remove any trailing backslash if needed.
1214      */
1215     RtlInitUnicodeString(&Name, RootPath);
1216     TrimTrailingPathSeparators_UStr(&Name);
1217 
1218     InitializeObjectAttributes(&ObjectAttributes,
1219                                &Name,
1220                                OBJ_CASE_INSENSITIVE,
1221                                NULL,
1222                                NULL);
1223 
1224     Status = NtOpenFile(&PartitionHandle,
1225                         GENERIC_READ | SYNCHRONIZE,
1226                         &ObjectAttributes,
1227                         &IoStatusBlock,
1228                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1229                         FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
1230     if (!NT_SUCCESS(Status))
1231         return Status;
1232 
1233     /* Open or create the file where the new bootsector will be saved */
1234     RtlInitUnicodeString(&Name, DstPath);
1235     InitializeObjectAttributes(&ObjectAttributes,
1236                                &Name,
1237                                OBJ_CASE_INSENSITIVE,
1238                                NULL,
1239                                NULL);
1240 
1241     Status = NtCreateFile(&FileHandle,
1242                           GENERIC_WRITE | SYNCHRONIZE,
1243                           &ObjectAttributes,
1244                           &IoStatusBlock,
1245                           NULL,
1246                           FILE_ATTRIBUTE_NORMAL,
1247                           0,
1248                           FILE_OVERWRITE_IF,
1249                           FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1250                           NULL,
1251                           0);
1252     if (!NT_SUCCESS(Status))
1253     {
1254         DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
1255         NtClose(PartitionHandle);
1256         return Status;
1257     }
1258 
1259     /* Install the FAT16 boot sector */
1260     Status = InstallFat16BootCode(SrcPath, FileHandle, PartitionHandle);
1261 
1262     /* Close the file and the partition */
1263     NtClose(FileHandle);
1264     NtClose(PartitionHandle);
1265 
1266     return Status;
1267 }
1268 
1269 static
1270 NTSTATUS
1271 InstallFat16BootCodeToDisk(
1272     IN PCWSTR SrcPath,
1273     IN PCWSTR RootPath)
1274 {
1275     NTSTATUS Status;
1276     UNICODE_STRING Name;
1277     OBJECT_ATTRIBUTES ObjectAttributes;
1278     IO_STATUS_BLOCK IoStatusBlock;
1279     HANDLE PartitionHandle;
1280 
1281     /*
1282      * Open the root partition from which the boot sector parameters will be
1283      * obtained; this is also where we will write the updated boot sector.
1284      * Remove any trailing backslash if needed.
1285      */
1286     RtlInitUnicodeString(&Name, RootPath);
1287     TrimTrailingPathSeparators_UStr(&Name);
1288 
1289     InitializeObjectAttributes(&ObjectAttributes,
1290                                &Name,
1291                                OBJ_CASE_INSENSITIVE,
1292                                NULL,
1293                                NULL);
1294 
1295     Status = NtOpenFile(&PartitionHandle,
1296                         GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1297                         &ObjectAttributes,
1298                         &IoStatusBlock,
1299                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1300                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1301     if (!NT_SUCCESS(Status))
1302         return Status;
1303 
1304     /* Install the FAT16 boot sector */
1305     Status = InstallFat16BootCode(SrcPath, PartitionHandle, PartitionHandle);
1306 
1307     /* Close the partition */
1308     NtClose(PartitionHandle);
1309 
1310     return Status;
1311 }
1312 
1313 
1314 static
1315 NTSTATUS
1316 InstallFat32BootCode(
1317     IN PCWSTR SrcPath,          // FAT32 bootsector source file (on the installation medium)
1318     IN HANDLE DstPath,          // Where to save the bootsector built from the source + partition information
1319     IN HANDLE RootPartition)    // Partition holding the (old) FAT32 information
1320 {
1321     NTSTATUS Status;
1322     UNICODE_STRING Name;
1323     OBJECT_ATTRIBUTES ObjectAttributes;
1324     IO_STATUS_BLOCK IoStatusBlock;
1325     HANDLE FileHandle;
1326     LARGE_INTEGER FileOffset;
1327     PFAT32_BOOTSECTOR OrigBootSector;
1328     PFAT32_BOOTSECTOR NewBootSector;
1329     USHORT BackupBootSector;
1330 
1331     /* Allocate a buffer for the original bootsector */
1332     OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1333     if (OrigBootSector == NULL)
1334         return STATUS_INSUFFICIENT_RESOURCES;
1335 
1336     /* Read the current boot sector into the buffer */
1337     FileOffset.QuadPart = 0ULL;
1338     Status = NtReadFile(RootPartition,
1339                         NULL,
1340                         NULL,
1341                         NULL,
1342                         &IoStatusBlock,
1343                         OrigBootSector,
1344                         SECTORSIZE,
1345                         &FileOffset,
1346                         NULL);
1347     if (!NT_SUCCESS(Status))
1348     {
1349         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1350         return Status;
1351     }
1352 
1353     /* Allocate a buffer for the new bootsector (2 sectors) */
1354     NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE);
1355     if (NewBootSector == NULL)
1356     {
1357         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1358         return STATUS_INSUFFICIENT_RESOURCES;
1359     }
1360 
1361     /* Read the new bootsector from SrcPath */
1362     RtlInitUnicodeString(&Name, SrcPath);
1363     InitializeObjectAttributes(&ObjectAttributes,
1364                                &Name,
1365                                OBJ_CASE_INSENSITIVE,
1366                                NULL,
1367                                NULL);
1368 
1369     Status = NtOpenFile(&FileHandle,
1370                         GENERIC_READ | SYNCHRONIZE,
1371                         &ObjectAttributes,
1372                         &IoStatusBlock,
1373                         FILE_SHARE_READ,
1374                         FILE_SYNCHRONOUS_IO_NONALERT);
1375     if (!NT_SUCCESS(Status))
1376     {
1377         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1378         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1379         return Status;
1380     }
1381 
1382     FileOffset.QuadPart = 0ULL;
1383     Status = NtReadFile(FileHandle,
1384                         NULL,
1385                         NULL,
1386                         NULL,
1387                         &IoStatusBlock,
1388                         NewBootSector,
1389                         2 * SECTORSIZE,
1390                         &FileOffset,
1391                         NULL);
1392     NtClose(FileHandle);
1393     if (!NT_SUCCESS(Status))
1394     {
1395         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1396         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1397         return Status;
1398     }
1399 
1400     /* Adjust the bootsector (copy a part of the FAT32 BPB) */
1401     memcpy(&NewBootSector->OemName,
1402            &OrigBootSector->OemName,
1403            FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1404            FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1405 
1406     /*
1407      * We know we copy the boot code to a file only when DstPath != RootPartition,
1408      * otherwise the boot code is copied to the specified root partition.
1409      */
1410     if (DstPath != RootPartition)
1411     {
1412         /* Copy to a file: Disable the backup boot sector */
1413         NewBootSector->BackupBootSector = 0;
1414     }
1415     else
1416     {
1417         /* Copy to a disk: Get the location of the backup boot sector */
1418         BackupBootSector = OrigBootSector->BackupBootSector;
1419     }
1420 
1421     /* Free the original boot sector */
1422     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1423 
1424     /* Write the first sector of the new bootcode to DstPath sector 0 */
1425     FileOffset.QuadPart = 0ULL;
1426     Status = NtWriteFile(DstPath,
1427                          NULL,
1428                          NULL,
1429                          NULL,
1430                          &IoStatusBlock,
1431                          NewBootSector,
1432                          SECTORSIZE,
1433                          &FileOffset,
1434                          NULL);
1435     if (!NT_SUCCESS(Status))
1436     {
1437         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1438         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1439         return Status;
1440     }
1441 
1442     if (DstPath == RootPartition)
1443     {
1444         /* Copy to a disk: Write the backup boot sector */
1445         if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1446         {
1447             FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1448             Status = NtWriteFile(DstPath,
1449                                  NULL,
1450                                  NULL,
1451                                  NULL,
1452                                  &IoStatusBlock,
1453                                  NewBootSector,
1454                                  SECTORSIZE,
1455                                  &FileOffset,
1456                                  NULL);
1457             if (!NT_SUCCESS(Status))
1458             {
1459                 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1460                 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1461                 return Status;
1462             }
1463         }
1464     }
1465 
1466     /* Write the second sector of the new bootcode to boot disk sector 14 */
1467     // FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE);
1468     FileOffset.QuadPart = 14 * SECTORSIZE;
1469     Status = NtWriteFile(DstPath,   // or really RootPartition ???
1470                          NULL,
1471                          NULL,
1472                          NULL,
1473                          &IoStatusBlock,
1474                          ((PUCHAR)NewBootSector + SECTORSIZE),
1475                          SECTORSIZE,
1476                          &FileOffset,
1477                          NULL);
1478     if (!NT_SUCCESS(Status))
1479     {
1480         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1481     }
1482 
1483     /* Free the new boot sector */
1484     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1485 
1486     return Status;
1487 }
1488 
1489 static
1490 NTSTATUS
1491 InstallFat32BootCodeToFile(
1492     IN PCWSTR SrcPath,
1493     IN PCWSTR DstPath,
1494     IN PCWSTR RootPath)
1495 {
1496     NTSTATUS Status;
1497     UNICODE_STRING Name;
1498     OBJECT_ATTRIBUTES ObjectAttributes;
1499     IO_STATUS_BLOCK IoStatusBlock;
1500     HANDLE PartitionHandle, FileHandle;
1501 
1502     /*
1503      * Open the root partition from which the boot sector parameters
1504      * will be obtained.
1505      * FIXME? It might be possible that we need to also open it for writing
1506      * access in case we really need to still write the second portion of
1507      * the boot sector ????
1508      *
1509      * Remove any trailing backslash if needed.
1510      */
1511     RtlInitUnicodeString(&Name, RootPath);
1512     TrimTrailingPathSeparators_UStr(&Name);
1513 
1514     InitializeObjectAttributes(&ObjectAttributes,
1515                                &Name,
1516                                OBJ_CASE_INSENSITIVE,
1517                                NULL,
1518                                NULL);
1519 
1520     Status = NtOpenFile(&PartitionHandle,
1521                         GENERIC_READ | SYNCHRONIZE,
1522                         &ObjectAttributes,
1523                         &IoStatusBlock,
1524                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1525                         FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
1526     if (!NT_SUCCESS(Status))
1527         return Status;
1528 
1529     /* Open or create the file where (the first sector of ????) the new bootsector will be saved */
1530     RtlInitUnicodeString(&Name, DstPath);
1531     InitializeObjectAttributes(&ObjectAttributes,
1532                                &Name,
1533                                OBJ_CASE_INSENSITIVE,
1534                                NULL,
1535                                NULL);
1536 
1537     Status = NtCreateFile(&FileHandle,
1538                           GENERIC_WRITE | SYNCHRONIZE,
1539                           &ObjectAttributes,
1540                           &IoStatusBlock,
1541                           NULL,
1542                           FILE_ATTRIBUTE_NORMAL,
1543                           0,
1544                           FILE_SUPERSEDE, // FILE_OVERWRITE_IF, <- is used for FAT16
1545                           FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1546                           NULL,
1547                           0);
1548     if (!NT_SUCCESS(Status))
1549     {
1550         DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
1551         NtClose(PartitionHandle);
1552         return Status;
1553     }
1554 
1555     /* Install the FAT32 boot sector */
1556     Status = InstallFat32BootCode(SrcPath, FileHandle, PartitionHandle);
1557 
1558     /* Close the file and the partition */
1559     NtClose(FileHandle);
1560     NtClose(PartitionHandle);
1561 
1562     return Status;
1563 }
1564 
1565 static
1566 NTSTATUS
1567 InstallFat32BootCodeToDisk(
1568     IN PCWSTR SrcPath,
1569     IN PCWSTR RootPath)
1570 {
1571     NTSTATUS Status;
1572     UNICODE_STRING Name;
1573     OBJECT_ATTRIBUTES ObjectAttributes;
1574     IO_STATUS_BLOCK IoStatusBlock;
1575     HANDLE PartitionHandle;
1576 
1577     /*
1578      * Open the root partition from which the boot sector parameters will be
1579      * obtained; this is also where we will write the updated boot sector.
1580      * Remove any trailing backslash if needed.
1581      */
1582     RtlInitUnicodeString(&Name, RootPath);
1583     TrimTrailingPathSeparators_UStr(&Name);
1584 
1585     InitializeObjectAttributes(&ObjectAttributes,
1586                                &Name,
1587                                OBJ_CASE_INSENSITIVE,
1588                                NULL,
1589                                NULL);
1590 
1591     Status = NtOpenFile(&PartitionHandle,
1592                         GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1593                         &ObjectAttributes,
1594                         &IoStatusBlock,
1595                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1596                         FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
1597     if (!NT_SUCCESS(Status))
1598         return Status;
1599 
1600     /* Install the FAT32 boot sector */
1601     Status = InstallFat32BootCode(SrcPath, PartitionHandle, PartitionHandle);
1602 
1603     /* Close the partition */
1604     NtClose(PartitionHandle);
1605 
1606     return Status;
1607 }
1608 
1609 static
1610 NTSTATUS
1611 InstallBtrfsBootCodeToDisk(
1612     IN PCWSTR SrcPath,
1613     IN PCWSTR RootPath)
1614 {
1615     NTSTATUS Status;
1616     NTSTATUS LockStatus;
1617     UNICODE_STRING Name;
1618     OBJECT_ATTRIBUTES ObjectAttributes;
1619     IO_STATUS_BLOCK IoStatusBlock;
1620     HANDLE FileHandle;
1621     LARGE_INTEGER FileOffset;
1622 //  PEXT2_BOOTSECTOR OrigBootSector;
1623     PBTRFS_BOOTSECTOR NewBootSector;
1624     // USHORT BackupBootSector;
1625     PARTITION_INFORMATION_EX PartInfo;
1626 
1627 #if 0
1628     /* Allocate buffer for original bootsector */
1629     OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1630     if (OrigBootSector == NULL)
1631         return STATUS_INSUFFICIENT_RESOURCES;
1632 
1633     /* Open the root partition - Remove any trailing backslash if needed */
1634     RtlInitUnicodeString(&Name, RootPath);
1635     TrimTrailingPathSeparators_UStr(&Name);
1636 
1637     InitializeObjectAttributes(&ObjectAttributes,
1638                                &Name,
1639                                OBJ_CASE_INSENSITIVE,
1640                                NULL,
1641                                NULL);
1642 
1643     Status = NtOpenFile(&FileHandle,
1644                         GENERIC_READ | SYNCHRONIZE,
1645                         &ObjectAttributes,
1646                         &IoStatusBlock,
1647                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1648                         FILE_SYNCHRONOUS_IO_NONALERT);
1649     if (!NT_SUCCESS(Status))
1650     {
1651         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1652         return Status;
1653     }
1654 
1655     /* Read current boot sector into buffer */
1656     FileOffset.QuadPart = 0ULL;
1657     Status = NtReadFile(FileHandle,
1658                         NULL,
1659                         NULL,
1660                         NULL,
1661                         &IoStatusBlock,
1662                         OrigBootSector,
1663                         SECTORSIZE,
1664                         &FileOffset,
1665                         NULL);
1666     NtClose(FileHandle);
1667     if (!NT_SUCCESS(Status))
1668     {
1669         RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1670         return Status;
1671     }
1672 #endif
1673 
1674     /* Allocate buffer for new bootsector */
1675     NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(BTRFS_BOOTSECTOR));
1676     if (NewBootSector == NULL)
1677     {
1678         // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1679         return STATUS_INSUFFICIENT_RESOURCES;
1680     }
1681 
1682     /* Read new bootsector from SrcPath */
1683     RtlInitUnicodeString(&Name, SrcPath);
1684 
1685     InitializeObjectAttributes(&ObjectAttributes,
1686                                &Name,
1687                                OBJ_CASE_INSENSITIVE,
1688                                NULL,
1689                                NULL);
1690 
1691     Status = NtOpenFile(&FileHandle,
1692                         GENERIC_READ | SYNCHRONIZE,
1693                         &ObjectAttributes,
1694                         &IoStatusBlock,
1695                         FILE_SHARE_READ,
1696                         FILE_SYNCHRONOUS_IO_NONALERT);
1697     if (!NT_SUCCESS(Status))
1698     {
1699         // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1700         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1701         return Status;
1702     }
1703 
1704     Status = NtReadFile(FileHandle,
1705                         NULL,
1706                         NULL,
1707                         NULL,
1708                         &IoStatusBlock,
1709                         NewBootSector,
1710                         sizeof(BTRFS_BOOTSECTOR),
1711                         NULL,
1712                         NULL);
1713     NtClose(FileHandle);
1714     if (!NT_SUCCESS(Status))
1715     {
1716         // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1717         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1718         return Status;
1719     }
1720 
1721 #if 0
1722     /* Adjust bootsector (copy a part of the FAT32 BPB) */
1723     memcpy(&NewBootSector->OemName,
1724            &OrigBootSector->OemName,
1725            FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1726            FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1727 
1728     /* Get the location of the backup boot sector */
1729     BackupBootSector = OrigBootSector->BackupBootSector;
1730 
1731     /* Free the original boot sector */
1732     // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1733 #endif
1734 
1735     /* Open the root partition - Remove any trailing backslash if needed */
1736     RtlInitUnicodeString(&Name, RootPath);
1737     TrimTrailingPathSeparators_UStr(&Name);
1738 
1739     InitializeObjectAttributes(&ObjectAttributes,
1740                                &Name,
1741                                OBJ_CASE_INSENSITIVE,
1742                                NULL,
1743                                NULL);
1744 
1745     Status = NtOpenFile(&FileHandle,
1746                         GENERIC_WRITE | SYNCHRONIZE,
1747                         &ObjectAttributes,
1748                         &IoStatusBlock,
1749                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1750                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1751     if (!NT_SUCCESS(Status))
1752     {
1753         DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1754         RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1755         return Status;
1756     }
1757 
1758     /*
1759      * The BTRFS driver requires the volume to be locked in order to modify
1760      * the first sectors of the partition, even though they are outside the
1761      * file-system space / in the reserved area (they are situated before
1762      * the super-block at 0x1000) and is in principle allowed by the NT
1763      * storage stack.
1764      * So we lock here in order to write the bootsector at sector 0.
1765      * If locking fails, we ignore and continue nonetheless.
1766      */
1767     LockStatus = NtFsControlFile(FileHandle,
1768                                  NULL,
1769                                  NULL,
1770                                  NULL,
1771                                  &IoStatusBlock,
1772                                  FSCTL_LOCK_VOLUME,
1773                                  NULL,
1774                                  0,
1775                                  NULL,
1776                                  0);
1777     if (!NT_SUCCESS(LockStatus))
1778     {
1779         DPRINT1("WARNING: Failed to lock BTRFS volume for writing bootsector! Operations may fail! (Status 0x%lx)\n", LockStatus);
1780     }
1781 
1782     /* Obtaining partition info and writing it to bootsector */
1783     Status = NtDeviceIoControlFile(FileHandle,
1784                                    NULL,
1785                                    NULL,
1786                                    NULL,
1787                                    &IoStatusBlock,
1788                                    IOCTL_DISK_GET_PARTITION_INFO_EX,
1789                                    NULL,
1790                                    0,
1791                                    &PartInfo,
1792                                    sizeof(PartInfo));
1793     if (!NT_SUCCESS(Status))
1794     {
1795         DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status);
1796         goto Quit;
1797     }
1798 
1799     /* Write new bootsector to RootPath */
1800 
1801     NewBootSector->PartitionStartLBA = PartInfo.StartingOffset.QuadPart / SECTORSIZE;
1802 
1803     /* Write sector 0 */
1804     FileOffset.QuadPart = 0ULL;
1805     Status = NtWriteFile(FileHandle,
1806                          NULL,
1807                          NULL,
1808                          NULL,
1809                          &IoStatusBlock,
1810                          NewBootSector,
1811                          sizeof(BTRFS_BOOTSECTOR),
1812                          &FileOffset,
1813                          NULL);
1814     if (!NT_SUCCESS(Status))
1815     {
1816         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1817         goto Quit;
1818     }
1819 
1820 #if 0
1821     /* Write backup boot sector */
1822     if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1823     {
1824         FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1825         Status = NtWriteFile(FileHandle,
1826                              NULL,
1827                              NULL,
1828                              NULL,
1829                              &IoStatusBlock,
1830                              NewBootSector,
1831                              SECTORSIZE,
1832                              &FileOffset,
1833                              NULL);
1834         if (!NT_SUCCESS(Status))
1835         {
1836             DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1837             goto Quit;
1838         }
1839     }
1840 
1841     /* Write sector 14 */
1842     FileOffset.QuadPart = 14 * SECTORSIZE;
1843     Status = NtWriteFile(FileHandle,
1844                          NULL,
1845                          NULL,
1846                          NULL,
1847                          &IoStatusBlock,
1848                          ((PUCHAR)NewBootSector + SECTORSIZE),
1849                          SECTORSIZE,
1850                          &FileOffset,
1851                          NULL);
1852     if (!NT_SUCCESS(Status))
1853     {
1854         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1855     }
1856 #endif
1857 
1858 Quit:
1859     /* Unlock the volume */
1860     LockStatus = NtFsControlFile(FileHandle,
1861                                  NULL,
1862                                  NULL,
1863                                  NULL,
1864                                  &IoStatusBlock,
1865                                  FSCTL_UNLOCK_VOLUME,
1866                                  NULL,
1867                                  0,
1868                                  NULL,
1869                                  0);
1870     if (!NT_SUCCESS(LockStatus))
1871     {
1872         DPRINT1("Failed to unlock BTRFS volume (Status 0x%lx)\n", LockStatus);
1873     }
1874 
1875     /* Close the volume */
1876     NtClose(FileHandle);
1877 
1878     /* Free the new boot sector */
1879     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1880 
1881     return Status;
1882 }
1883 
1884 
1885 static
1886 NTSTATUS
1887 InstallFatBootcodeToPartition(
1888     IN PUNICODE_STRING SystemRootPath,
1889     IN PUNICODE_STRING SourceRootPath,
1890     IN PUNICODE_STRING DestinationArcPath,
1891     IN UCHAR PartitionType)
1892 {
1893     NTSTATUS Status;
1894     BOOLEAN DoesFreeLdrExist;
1895     WCHAR SrcPath[MAX_PATH];
1896     WCHAR DstPath[MAX_PATH];
1897 
1898     /* FAT or FAT32 partition */
1899     DPRINT("System path: '%wZ'\n", SystemRootPath);
1900 
1901     /* Copy FreeLoader to the system partition, always overwriting the older version */
1902     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
1903     CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
1904 
1905     DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
1906     Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1907     if (!NT_SUCCESS(Status))
1908     {
1909         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1910         return Status;
1911     }
1912 
1913     /* Prepare for possibly updating 'freeldr.ini' */
1914     DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini");
1915     if (DoesFreeLdrExist)
1916     {
1917         /* Update existing 'freeldr.ini' */
1918         DPRINT1("Update existing 'freeldr.ini'\n");
1919         Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1920         if (!NT_SUCCESS(Status))
1921         {
1922             DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
1923             return Status;
1924         }
1925     }
1926 
1927     /* Check for NT and other bootloaders */
1928 
1929     // FIXME: Check for Vista+ bootloader!
1930     /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/
1931     /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/
1932     if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE ||
1933         DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE)
1934     {
1935         /* Search root directory for 'NTLDR' and 'BOOT.INI' */
1936         DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
1937 
1938         /* Create or update 'freeldr.ini' */
1939         if (DoesFreeLdrExist == FALSE)
1940         {
1941             /* Create new 'freeldr.ini' */
1942             DPRINT1("Create new 'freeldr.ini'\n");
1943             Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1944             if (!NT_SUCCESS(Status))
1945             {
1946                 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
1947                 return Status;
1948             }
1949 
1950             /* Install new bootcode into a file */
1951             CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"bootsect.ros");
1952 
1953             if (PartitionType == PARTITION_FAT32 ||
1954                 PartitionType == PARTITION_FAT32_XINT13)
1955             {
1956                 /* Install FAT32 bootcode */
1957                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin");
1958 
1959                 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
1960                 Status = InstallFat32BootCodeToFile(SrcPath, DstPath,
1961                                                     SystemRootPath->Buffer);
1962                 if (!NT_SUCCESS(Status))
1963                 {
1964                     DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
1965                     return Status;
1966                 }
1967             }
1968             else
1969             {
1970                 /* Install FAT16 bootcode */
1971                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
1972 
1973                 DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
1974                 Status = InstallFat16BootCodeToFile(SrcPath, DstPath,
1975                                                     SystemRootPath->Buffer);
1976                 if (!NT_SUCCESS(Status))
1977                 {
1978                     DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
1979                     return Status;
1980                 }
1981             }
1982         }
1983 
1984         /* Update 'boot.ini' */
1985         /* Windows' NTLDR loads an external bootsector file when the specified drive
1986            letter is C:, otherwise it will interpret it as a boot DOS path specifier. */
1987         DPRINT1("Update 'boot.ini'\n");
1988         Status = UpdateBootIni(SystemRootPath->Buffer,
1989                                L"C:\\bootsect.ros",
1990                                L"\"ReactOS\"");
1991         if (!NT_SUCCESS(Status))
1992         {
1993             DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
1994             return Status;
1995         }
1996     }
1997     else
1998     {
1999         /* Non-NT bootloaders: install our own bootloader */
2000 
2001         PCWSTR Section;
2002         PCWSTR Description;
2003         PCWSTR BootDrive;
2004         PCWSTR BootPartition;
2005         PCWSTR BootSector;
2006 
2007         /* Search for COMPAQ MS-DOS 1.x (1.11, 1.12, based on MS-DOS 1.25) boot loader */
2008         if (DoesFileExist_2(SystemRootPath->Buffer, L"IOSYS.COM") == TRUE ||
2009             DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.COM") == TRUE)
2010         {
2011             DPRINT1("Found COMPAQ MS-DOS 1.x (1.11, 1.12) / MS-DOS 1.25 boot loader\n");
2012 
2013             Section       = L"CPQDOS";
2014             Description   = L"\"COMPAQ MS-DOS 1.x / MS-DOS 1.25\"";
2015             BootDrive     = L"hd0";
2016             BootPartition = L"1";
2017             BootSector    = L"BOOTSECT.DOS";
2018         }
2019         else
2020         /* Search for Microsoft DOS or Windows 9x boot loader */
2021         if (DoesFileExist_2(SystemRootPath->Buffer, L"IO.SYS") == TRUE ||
2022             DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.SYS") == TRUE)
2023             // WINBOOT.SYS
2024         {
2025             DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
2026 
2027             Section       = L"MSDOS";
2028             Description   = L"\"MS-DOS/Windows\"";
2029             BootDrive     = L"hd0";
2030             BootPartition = L"1";
2031             BootSector    = L"BOOTSECT.DOS";
2032         }
2033         else
2034         /* Search for IBM PC-DOS or DR-DOS 5.x boot loader */
2035         if (DoesFileExist_2(SystemRootPath->Buffer, L"IBMIO.COM" ) == TRUE || // Some people refer to this file instead of IBMBIO.COM...
2036             DoesFileExist_2(SystemRootPath->Buffer, L"IBMBIO.COM") == TRUE ||
2037             DoesFileExist_2(SystemRootPath->Buffer, L"IBMDOS.COM") == TRUE)
2038         {
2039             DPRINT1("Found IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\n");
2040 
2041             Section       = L"IBMDOS";
2042             Description   = L"\"IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\"";
2043             BootDrive     = L"hd0";
2044             BootPartition = L"1";
2045             BootSector    = L"BOOTSECT.DOS";
2046         }
2047         else
2048         /* Search for DR-DOS 3.x boot loader */
2049         if (DoesFileExist_2(SystemRootPath->Buffer, L"DRBIOS.SYS") == TRUE ||
2050             DoesFileExist_2(SystemRootPath->Buffer, L"DRBDOS.SYS") == TRUE)
2051         {
2052             DPRINT1("Found DR-DOS 3.x\n");
2053 
2054             Section       = L"DRDOS";
2055             Description   = L"\"DR-DOS 3.x\"";
2056             BootDrive     = L"hd0";
2057             BootPartition = L"1";
2058             BootSector    = L"BOOTSECT.DOS";
2059         }
2060         else
2061         /* Search for Dell Real-Mode Kernel (DRMK) OS */
2062         if (DoesFileExist_2(SystemRootPath->Buffer, L"DELLBIO.BIN") == TRUE ||
2063             DoesFileExist_2(SystemRootPath->Buffer, L"DELLRMK.BIN") == TRUE)
2064         {
2065             DPRINT1("Found Dell Real-Mode Kernel OS\n");
2066 
2067             Section       = L"DRMK";
2068             Description   = L"\"Dell Real-Mode Kernel OS\"";
2069             BootDrive     = L"hd0";
2070             BootPartition = L"1";
2071             BootSector    = L"BOOTSECT.DOS";
2072         }
2073         else
2074         /* Search for MS OS/2 1.x */
2075         if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT.COM") == TRUE ||
2076             DoesFileExist_2(SystemRootPath->Buffer, L"OS2BIO.COM" ) == TRUE ||
2077             DoesFileExist_2(SystemRootPath->Buffer, L"OS2DOS.COM" ) == TRUE)
2078         {
2079             DPRINT1("Found MS OS/2 1.x\n");
2080 
2081             Section       = L"MSOS2";
2082             Description   = L"\"MS OS/2 1.x\"";
2083             BootDrive     = L"hd0";
2084             BootPartition = L"1";
2085             BootSector    = L"BOOTSECT.OS2";
2086         }
2087         else
2088         /* Search for MS or IBM OS/2 */
2089         if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT") == TRUE ||
2090             DoesFileExist_2(SystemRootPath->Buffer, L"OS2LDR" ) == TRUE ||
2091             DoesFileExist_2(SystemRootPath->Buffer, L"OS2KRNL") == TRUE)
2092         {
2093             DPRINT1("Found MS/IBM OS/2\n");
2094 
2095             Section       = L"IBMOS2";
2096             Description   = L"\"MS/IBM OS/2\"";
2097             BootDrive     = L"hd0";
2098             BootPartition = L"1";
2099             BootSector    = L"BOOTSECT.OS2";
2100         }
2101         else
2102         /* Search for FreeDOS boot loader */
2103         if (DoesFileExist_2(SystemRootPath->Buffer, L"kernel.sys") == TRUE)
2104         {
2105             DPRINT1("Found FreeDOS boot loader\n");
2106 
2107             Section       = L"FDOS";
2108             Description   = L"\"FreeDOS\"";
2109             BootDrive     = L"hd0";
2110             BootPartition = L"1";
2111             BootSector    = L"BOOTSECT.DOS";
2112         }
2113         else
2114         {
2115             /* No or unknown boot loader */
2116             DPRINT1("No or unknown boot loader found\n");
2117 
2118             Section       = L"Unknown";
2119             Description   = L"\"Unknown Operating System\"";
2120             BootDrive     = L"hd0";
2121             BootPartition = L"1";
2122             BootSector    = L"BOOTSECT.OLD";
2123         }
2124 
2125         /* Create or update 'freeldr.ini' */
2126         if (DoesFreeLdrExist == FALSE)
2127         {
2128             /* Create new 'freeldr.ini' */
2129             DPRINT1("Create new 'freeldr.ini'\n");
2130 
2131             if (IsThereAValidBootSector(SystemRootPath->Buffer))
2132             {
2133                 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2134                              SystemRootPath->Buffer, DestinationArcPath->Buffer,
2135                              Section, Description,
2136                              BootDrive, BootPartition, BootSector);
2137                 if (!NT_SUCCESS(Status))
2138                 {
2139                     DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2140                     return Status;
2141                 }
2142 
2143                 /* Save current bootsector */
2144                 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
2145 
2146                 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2147                 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE);
2148                 if (!NT_SUCCESS(Status))
2149                 {
2150                     DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
2151                     return Status;
2152                 }
2153             }
2154             else
2155             {
2156                 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
2157                 if (!NT_SUCCESS(Status))
2158                 {
2159                     DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2160                     return Status;
2161                 }
2162             }
2163 
2164             /* Install new bootsector on the disk */
2165             if (PartitionType == PARTITION_FAT32 ||
2166                 PartitionType == PARTITION_FAT32_XINT13)
2167             {
2168                 /* Install FAT32 bootcode */
2169                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin");
2170 
2171                 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2172                 Status = InstallFat32BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2173                 if (!NT_SUCCESS(Status))
2174                 {
2175                     DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
2176                     return Status;
2177                 }
2178             }
2179             else
2180             {
2181                 /* Install FAT16 bootcode */
2182                 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
2183 
2184                 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2185                 Status = InstallFat16BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2186                 if (!NT_SUCCESS(Status))
2187                 {
2188                     DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2189                     return Status;
2190                 }
2191             }
2192         }
2193     }
2194 
2195     return STATUS_SUCCESS;
2196 }
2197 
2198 static
2199 NTSTATUS
2200 InstallBtrfsBootcodeToPartition(
2201     IN PUNICODE_STRING SystemRootPath,
2202     IN PUNICODE_STRING SourceRootPath,
2203     IN PUNICODE_STRING DestinationArcPath,
2204     IN UCHAR PartitionType)
2205 {
2206     NTSTATUS Status;
2207     BOOLEAN DoesFreeLdrExist;
2208     WCHAR SrcPath[MAX_PATH];
2209     WCHAR DstPath[MAX_PATH];
2210 
2211     /* BTRFS partition */
2212     DPRINT("System path: '%wZ'\n", SystemRootPath);
2213 
2214     /* Copy FreeLoader to the system partition, always overwriting the older version */
2215     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
2216     CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
2217 
2218     DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2219     Status = SetupCopyFile(SrcPath, DstPath, FALSE);
2220     if (!NT_SUCCESS(Status))
2221     {
2222         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2223         return Status;
2224     }
2225 
2226     /* Prepare for possibly updating 'freeldr.ini' */
2227     DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini");
2228     if (DoesFreeLdrExist)
2229     {
2230         /* Update existing 'freeldr.ini' */
2231         DPRINT1("Update existing 'freeldr.ini'\n");
2232         Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer);
2233         if (!NT_SUCCESS(Status))
2234         {
2235             DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2236             return Status;
2237         }
2238     }
2239 
2240     /* Check for *nix bootloaders */
2241 
2242     /* Create or update 'freeldr.ini' */
2243     if (DoesFreeLdrExist == FALSE)
2244     {
2245         /* Create new 'freeldr.ini' */
2246         DPRINT1("Create new 'freeldr.ini'\n");
2247 
2248         /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */
2249         DPRINT1("*nix or unknown boot loader found\n");
2250 
2251         if (IsThereAValidBootSector(SystemRootPath->Buffer))
2252         {
2253             PCWSTR BootSector = L"BOOTSECT.OLD";
2254 
2255             Status = CreateFreeLoaderIniForReactOSAndBootSector(
2256                          SystemRootPath->Buffer, DestinationArcPath->Buffer,
2257                          L"Linux", L"\"Linux\"",
2258                          L"hd0", L"1", BootSector);
2259             if (!NT_SUCCESS(Status))
2260             {
2261                 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2262                 return Status;
2263             }
2264 
2265             /* Save current bootsector */
2266             CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
2267 
2268             DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2269             Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(BTRFS_BOOTSECTOR));
2270             if (!NT_SUCCESS(Status))
2271             {
2272                 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
2273                 return Status;
2274             }
2275         }
2276         else
2277         {
2278             Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
2279             if (!NT_SUCCESS(Status))
2280             {
2281                 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2282                 return Status;
2283             }
2284         }
2285 
2286         /* Install new bootsector on the disk */
2287         // if (PartitionType == PARTITION_EXT2)
2288         {
2289             /* Install BTRFS bootcode */
2290             CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin");
2291 
2292             DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2293             Status = InstallBtrfsBootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2294             if (!NT_SUCCESS(Status))
2295             {
2296                 DPRINT1("InstallBtrfsBootCodeToDisk() failed (Status %lx)\n", Status);
2297                 return Status;
2298             }
2299         }
2300     }
2301 
2302     return STATUS_SUCCESS;
2303 }
2304 
2305 
2306 NTSTATUS
2307 InstallVBRToPartition(
2308     IN PUNICODE_STRING SystemRootPath,
2309     IN PUNICODE_STRING SourceRootPath,
2310     IN PUNICODE_STRING DestinationArcPath,
2311     IN UCHAR PartitionType)
2312 {
2313     switch (PartitionType)
2314     {
2315         case PARTITION_FAT_12:
2316         case PARTITION_FAT_16:
2317         case PARTITION_HUGE:
2318         case PARTITION_XINT13:
2319         case PARTITION_FAT32:
2320         case PARTITION_FAT32_XINT13:
2321         {
2322             return InstallFatBootcodeToPartition(SystemRootPath,
2323                                                  SourceRootPath,
2324                                                  DestinationArcPath,
2325                                                  PartitionType);
2326         }
2327 
2328         case PARTITION_LINUX:
2329         {
2330             return InstallBtrfsBootcodeToPartition(SystemRootPath,
2331                                                    SourceRootPath,
2332                                                    DestinationArcPath,
2333                                                    PartitionType);
2334         }
2335 
2336         case PARTITION_IFS:
2337             DPRINT1("Partitions of type NTFS or HPFS are not supported yet!\n");
2338             break;
2339 
2340         default:
2341             DPRINT1("PartitionType 0x%02X unknown!\n", PartitionType);
2342             break;
2343     }
2344 
2345     return STATUS_UNSUCCESSFUL;
2346 }
2347 
2348 
2349 NTSTATUS
2350 InstallFatBootcodeToFloppy(
2351     IN PUNICODE_STRING SourceRootPath,
2352     IN PUNICODE_STRING DestinationArcPath)
2353 {
2354     static const PCWSTR FloppyDevice = L"\\Device\\Floppy0\\";
2355 
2356     NTSTATUS Status;
2357     WCHAR SrcPath[MAX_PATH];
2358     WCHAR DstPath[MAX_PATH];
2359 
2360     /* Verify that the floppy disk is accessible */
2361     if (DoesDirExist(NULL, FloppyDevice) == FALSE)
2362         return STATUS_DEVICE_NOT_READY;
2363 
2364     /* Format the floppy disk */
2365     // FormatPartition(...)
2366     Status = FormatFileSystem(FloppyDevice,
2367                               L"FAT",
2368                               FMIFS_FLOPPY,
2369                               NULL,
2370                               TRUE,
2371                               0,
2372                               NULL);
2373     if (!NT_SUCCESS(Status))
2374     {
2375         if (Status == STATUS_NOT_SUPPORTED)
2376             DPRINT1("FAT FS non existent on this system?!\n");
2377         else
2378             DPRINT1("VfatFormat() failed (Status %lx)\n", Status);
2379 
2380         return Status;
2381     }
2382 
2383     /* Copy FreeLoader to the boot partition */
2384     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
2385     CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice, L"freeldr.sys");
2386 
2387     DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2388     Status = SetupCopyFile(SrcPath, DstPath, FALSE);
2389     if (!NT_SUCCESS(Status))
2390     {
2391         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2392         return Status;
2393     }
2394 
2395     /* Create new 'freeldr.ini' */
2396     DPRINT("Create new 'freeldr.ini'\n");
2397     Status = CreateFreeLoaderIniForReactOS(FloppyDevice, DestinationArcPath->Buffer);
2398     if (!NT_SUCCESS(Status))
2399     {
2400         DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2401         return Status;
2402     }
2403 
2404     /* Install FAT12 boosector */
2405     CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
2406     CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice);
2407 
2408     DPRINT("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2409     Status = InstallFat12BootCodeToFloppy(SrcPath, DstPath);
2410     if (!NT_SUCCESS(Status))
2411     {
2412         DPRINT1("InstallFat12BootCodeToFloppy() failed (Status %lx)\n", Status);
2413         return Status;
2414     }
2415 
2416     return STATUS_SUCCESS;
2417 }
2418 
2419 /* EOF */
2420