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