2f7b43fee3ad0ab37324e0b83dba4162ca957fa9
[reactos.git] / base / setup / lib / bootsup.c
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 PENUM_REACTOS_ENTRIES_DATA Data = (PENUM_REACTOS_ENTRIES_DATA)Parameter;
345 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
346 WCHAR SystemPath[MAX_PATH];
347
348 /* We have a boot entry */
349
350 /* Check for supported boot type "Windows2003" */
351 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) ||
352 RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
353 NTOS_OPTIONS_SIGNATURE,
354 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) !=
355 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature))
356 {
357 /* This is not a ReactOS entry */
358 // DPRINT1(" An installation '%S' of unsupported type '%S'\n",
359 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a");
360 DPRINT1(" An installation '%S' of unsupported type %lu\n",
361 BootEntry->FriendlyName, BootEntry->OsOptionsLength);
362 /* Continue the enumeration */
363 goto SkipThisEntry;
364 }
365
366 /* BootType is Windows2003, now check OsLoadPath */
367 if (!Options->OsLoadPath || !*Options->OsLoadPath)
368 {
369 /* Certainly not a ReactOS installation */
370 DPRINT1(" A Win2k3 install '%S' without an ARC path?!\n", BootEntry->FriendlyName);
371 /* Continue the enumeration */
372 goto SkipThisEntry;
373 }
374
375 RtlStringCchPrintfW(SystemPath, ARRAYSIZE(SystemPath), L"\"%s\"", Data->ArcPath);
376 if ((_wcsicmp(Options->OsLoadPath, Data->ArcPath) != 0) &&
377 (_wcsicmp(Options->OsLoadPath, SystemPath) != 0))
378 {
379 /*
380 * This entry is a ReactOS entry, but the SystemRoot
381 * does not match the one we are looking for.
382 */
383 /* Continue the enumeration */
384 goto SkipThisEntry;
385 }
386
387 DPRINT1(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n",
388 BootEntry->FriendlyName, Options->OsLoadPath);
389 // DPRINT1(" Found a Win2k3 install '%S' with ARC path '%S'\n",
390 // BootEntry->FriendlyName, Options->OsLoadPath);
391
392 DPRINT1("EnumerateReactOSEntries: OsLoadPath: '%S'\n", Options->OsLoadPath);
393
394 Data->UseExistingEntry = TRUE;
395 RtlStringCchCopyW(Data->OsName, ARRAYSIZE(Data->OsName), BootEntry->FriendlyName);
396
397 /* We have found our entry, stop the enumeration now! */
398 return STATUS_NO_MORE_ENTRIES;
399
400 SkipThisEntry:
401 Data->UseExistingEntry = FALSE;
402 if (Type == FreeLdr && wcscmp(Data->SectionName, (PWSTR)BootEntry->BootEntryKey)== 0)
403 {
404 RtlStringCchPrintfW(Data->SectionName, ARRAYSIZE(Data->SectionName),
405 L"ReactOS_%lu", Data->i);
406 RtlStringCchPrintfW(Data->OsName, ARRAYSIZE(Data->OsName),
407 L"\"ReactOS %lu\"", Data->i);
408 Data->i++;
409 }
410 return STATUS_SUCCESS;
411 }
412
413 static
414 NTSTATUS
415 UpdateFreeLoaderIni(
416 IN PCWSTR IniPath,
417 IN PCWSTR ArcPath)
418 {
419 NTSTATUS Status;
420 PVOID BootStoreHandle;
421 ENUM_REACTOS_ENTRIES_DATA Data;
422 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
423 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
424 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
425
426 /* Open the INI file */
427 Status = OpenBootStore(&BootStoreHandle, IniPath, FreeLdr, /*TRUE*/ FALSE);
428 if (!NT_SUCCESS(Status))
429 return Status;
430
431 /* Find an existing usable or an unused section name */
432 Data.UseExistingEntry = TRUE;
433 Data.i = 1;
434 Data.ArcPath = ArcPath;
435 RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS");
436 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\"");
437
438 //
439 // FIXME: We temporarily use EnumerateBootStoreEntries, until
440 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented.
441 //
442 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data);
443
444 /* Create a new "ReactOS" entry if there is none already existing that suits us */
445 if (!Data.UseExistingEntry)
446 {
447 // RtlStringCchPrintfW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS_%lu", Data.i);
448 // RtlStringCchPrintfW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS %lu\"", Data.i);
449
450 BootEntry->Version = FreeLdr;
451 BootEntry->BootFilePath = NULL;
452
453 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
454 RtlCopyMemory(Options->Signature,
455 NTOS_OPTIONS_SIGNATURE,
456 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
457
458 Options->OsLoadPath = ArcPath;
459
460 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName);
461 BootEntry->FriendlyName = Data.OsName;
462 Options->OsLoadOptions = NULL; // L"";
463 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(Data.SectionName));
464 }
465
466 /* Close the INI file */
467 CloseBootStore(BootStoreHandle);
468 return STATUS_SUCCESS;
469 }
470
471 static
472 NTSTATUS
473 UpdateBootIni(
474 IN PCWSTR IniPath,
475 IN PCWSTR EntryName, // ~= ArcPath
476 IN PCWSTR EntryValue)
477 {
478 NTSTATUS Status;
479 PVOID BootStoreHandle;
480 ENUM_REACTOS_ENTRIES_DATA Data;
481
482 // NOTE: Technically it would be "BootSector"...
483 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
484 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
485 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
486
487 /* Open the INI file */
488 Status = OpenBootStore(&BootStoreHandle, IniPath, NtLdr, FALSE);
489 if (!NT_SUCCESS(Status))
490 return Status;
491
492 /* Find an existing usable or an unused section name */
493 Data.UseExistingEntry = TRUE;
494 // Data.i = 1;
495 Data.ArcPath = EntryName;
496 // RtlStringCchCopyW(Data.SectionName, ARRAYSIZE(Data.SectionName), L"ReactOS");
497 RtlStringCchCopyW(Data.OsName, ARRAYSIZE(Data.OsName), L"\"ReactOS\"");
498
499 //
500 // FIXME: We temporarily use EnumerateBootStoreEntries, until
501 // both QueryBootStoreEntry and ModifyBootStoreEntry get implemented.
502 //
503 Status = EnumerateBootStoreEntries(BootStoreHandle, EnumerateReactOSEntries, &Data);
504
505 /* If either the key was not found, or contains something else, add a new one */
506 if (!Data.UseExistingEntry /* ||
507 ( (Status == STATUS_NO_MORE_ENTRIES) && wcscmp(Data.OsName, EntryValue) ) */)
508 {
509 BootEntry->Version = NtLdr;
510 BootEntry->BootFilePath = NULL;
511
512 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
513 RtlCopyMemory(Options->Signature,
514 NTOS_OPTIONS_SIGNATURE,
515 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
516
517 Options->OsLoadPath = EntryName;
518
519 // BootEntry->BootEntryKey = MAKESTRKEY(Data.SectionName);
520 // BootEntry->FriendlyName = Data.OsName;
521 BootEntry->FriendlyName = EntryValue;
522 Options->OsLoadOptions = NULL; // L"";
523 AddBootStoreEntry(BootStoreHandle, BootEntry, MAKESTRKEY(0 /*Data.SectionName*/));
524 }
525
526 /* Close the INI file */
527 CloseBootStore(BootStoreHandle);
528 return STATUS_SUCCESS; // Status;
529 }
530
531
532 static
533 BOOLEAN
534 IsThereAValidBootSector(
535 IN PCWSTR RootPath)
536 {
537 /*
538 * We first demand that the bootsector has a valid signature at its end.
539 * We then check the first 3 bytes (as a ULONG) of the bootsector for a
540 * potential "valid" instruction (the BIOS starts execution of the bootsector
541 * at its beginning). Currently this criterium is that this ULONG must be
542 * non-zero. If both these tests pass, then the bootsector is valid; otherwise
543 * it is invalid and certainly needs to be overwritten.
544 */
545
546 BOOLEAN IsValid = FALSE;
547 NTSTATUS Status;
548 UNICODE_STRING RootPartition;
549 OBJECT_ATTRIBUTES ObjectAttributes;
550 IO_STATUS_BLOCK IoStatusBlock;
551 HANDLE FileHandle;
552 LARGE_INTEGER FileOffset;
553 PUCHAR BootSector;
554 ULONG Instruction;
555
556 /* Allocate buffer for bootsector */
557 BootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
558 if (BootSector == NULL)
559 return FALSE; // STATUS_INSUFFICIENT_RESOURCES;
560 RtlZeroMemory(BootSector, SECTORSIZE);
561
562 /* Open the root partition - Remove any trailing backslash if needed */
563 RtlInitUnicodeString(&RootPartition, RootPath);
564 TrimTrailingPathSeparators_UStr(&RootPartition);
565
566 InitializeObjectAttributes(&ObjectAttributes,
567 &RootPartition,
568 OBJ_CASE_INSENSITIVE,
569 NULL,
570 NULL);
571
572 Status = NtOpenFile(&FileHandle,
573 GENERIC_READ | SYNCHRONIZE,
574 &ObjectAttributes,
575 &IoStatusBlock,
576 0,
577 FILE_SYNCHRONOUS_IO_NONALERT);
578 if (!NT_SUCCESS(Status))
579 goto Quit;
580
581 /* Read current boot sector into buffer */
582 FileOffset.QuadPart = 0ULL;
583 Status = NtReadFile(FileHandle,
584 NULL,
585 NULL,
586 NULL,
587 &IoStatusBlock,
588 BootSector,
589 SECTORSIZE,
590 &FileOffset,
591 NULL);
592 NtClose(FileHandle);
593 if (!NT_SUCCESS(Status))
594 goto Quit;
595
596 /* Check the instruction; we use a ULONG to read three bytes */
597 Instruction = (*(PULONG)BootSector) & 0x00FFFFFF;
598 IsValid = (Instruction != 0x00000000);
599
600 /* Check the bootsector signature */
601 IsValid &= (*(PUSHORT)(BootSector + 0x1fe) == 0xaa55);
602
603 Quit:
604 /* Free the boot sector */
605 RtlFreeHeap(ProcessHeap, 0, BootSector);
606 return IsValid; // Status;
607 }
608
609 static
610 NTSTATUS
611 SaveBootSector(
612 IN PCWSTR RootPath,
613 IN PCWSTR DstPath,
614 IN ULONG Length)
615 {
616 NTSTATUS Status;
617 UNICODE_STRING Name;
618 OBJECT_ATTRIBUTES ObjectAttributes;
619 IO_STATUS_BLOCK IoStatusBlock;
620 HANDLE FileHandle;
621 LARGE_INTEGER FileOffset;
622 PUCHAR BootSector;
623
624 /* Allocate buffer for bootsector */
625 BootSector = RtlAllocateHeap(ProcessHeap, 0, Length);
626 if (BootSector == NULL)
627 return STATUS_INSUFFICIENT_RESOURCES;
628
629 /* Open the root partition - Remove any trailing backslash if needed */
630 RtlInitUnicodeString(&Name, RootPath);
631 TrimTrailingPathSeparators_UStr(&Name);
632
633 InitializeObjectAttributes(&ObjectAttributes,
634 &Name,
635 OBJ_CASE_INSENSITIVE,
636 NULL,
637 NULL);
638
639 Status = NtOpenFile(&FileHandle,
640 GENERIC_READ | SYNCHRONIZE,
641 &ObjectAttributes,
642 &IoStatusBlock,
643 0,
644 FILE_SYNCHRONOUS_IO_NONALERT);
645 if (!NT_SUCCESS(Status))
646 {
647 RtlFreeHeap(ProcessHeap, 0, BootSector);
648 return Status;
649 }
650
651 /* Read current boot sector into buffer */
652 FileOffset.QuadPart = 0ULL;
653 Status = NtReadFile(FileHandle,
654 NULL,
655 NULL,
656 NULL,
657 &IoStatusBlock,
658 BootSector,
659 Length,
660 &FileOffset,
661 NULL);
662 NtClose(FileHandle);
663 if (!NT_SUCCESS(Status))
664 {
665 RtlFreeHeap(ProcessHeap, 0, BootSector);
666 return Status;
667 }
668
669 /* Write bootsector to DstPath */
670 RtlInitUnicodeString(&Name, DstPath);
671
672 InitializeObjectAttributes(&ObjectAttributes,
673 &Name,
674 0,
675 NULL,
676 NULL);
677
678 Status = NtCreateFile(&FileHandle,
679 GENERIC_WRITE | SYNCHRONIZE,
680 &ObjectAttributes,
681 &IoStatusBlock,
682 NULL,
683 FILE_ATTRIBUTE_NORMAL,
684 0,
685 FILE_SUPERSEDE,
686 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
687 NULL,
688 0);
689 if (!NT_SUCCESS(Status))
690 {
691 RtlFreeHeap(ProcessHeap, 0, BootSector);
692 return Status;
693 }
694
695 Status = NtWriteFile(FileHandle,
696 NULL,
697 NULL,
698 NULL,
699 &IoStatusBlock,
700 BootSector,
701 Length,
702 NULL,
703 NULL);
704 NtClose(FileHandle);
705
706 /* Free the boot sector */
707 RtlFreeHeap(ProcessHeap, 0, BootSector);
708
709 return Status;
710 }
711
712
713 static
714 NTSTATUS
715 InstallMbrBootCodeToDiskHelper(
716 IN PCWSTR SrcPath,
717 IN PCWSTR RootPath)
718 {
719 NTSTATUS Status;
720 UNICODE_STRING Name;
721 OBJECT_ATTRIBUTES ObjectAttributes;
722 IO_STATUS_BLOCK IoStatusBlock;
723 HANDLE FileHandle;
724 LARGE_INTEGER FileOffset;
725 PPARTITION_SECTOR OrigBootSector;
726 PPARTITION_SECTOR NewBootSector;
727
728 /* Allocate buffer for original bootsector */
729 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTITION_SECTOR));
730 if (OrigBootSector == NULL)
731 return STATUS_INSUFFICIENT_RESOURCES;
732
733 /* Open the root partition - Remove any trailing backslash if needed */
734 RtlInitUnicodeString(&Name, RootPath);
735 TrimTrailingPathSeparators_UStr(&Name);
736
737 InitializeObjectAttributes(&ObjectAttributes,
738 &Name,
739 OBJ_CASE_INSENSITIVE,
740 NULL,
741 NULL);
742
743 Status = NtOpenFile(&FileHandle,
744 GENERIC_READ | SYNCHRONIZE,
745 &ObjectAttributes,
746 &IoStatusBlock,
747 0,
748 FILE_SYNCHRONOUS_IO_NONALERT);
749 if (!NT_SUCCESS(Status))
750 {
751 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
752 return Status;
753 }
754
755 /* Read current boot sector into buffer */
756 FileOffset.QuadPart = 0ULL;
757 Status = NtReadFile(FileHandle,
758 NULL,
759 NULL,
760 NULL,
761 &IoStatusBlock,
762 OrigBootSector,
763 sizeof(PARTITION_SECTOR),
764 &FileOffset,
765 NULL);
766 NtClose(FileHandle);
767 if (!NT_SUCCESS(Status))
768 {
769 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
770 return Status;
771 }
772
773 /* Allocate buffer for new bootsector */
774 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTITION_SECTOR));
775 if (NewBootSector == NULL)
776 {
777 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
778 return STATUS_INSUFFICIENT_RESOURCES;
779 }
780
781 /* Read new bootsector from SrcPath */
782 RtlInitUnicodeString(&Name, SrcPath);
783
784 InitializeObjectAttributes(&ObjectAttributes,
785 &Name,
786 OBJ_CASE_INSENSITIVE,
787 NULL,
788 NULL);
789
790 Status = NtOpenFile(&FileHandle,
791 GENERIC_READ | SYNCHRONIZE,
792 &ObjectAttributes,
793 &IoStatusBlock,
794 0,
795 FILE_SYNCHRONOUS_IO_NONALERT);
796 if (!NT_SUCCESS(Status))
797 {
798 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
799 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
800 return Status;
801 }
802
803 Status = NtReadFile(FileHandle,
804 NULL,
805 NULL,
806 NULL,
807 &IoStatusBlock,
808 NewBootSector,
809 sizeof(PARTITION_SECTOR),
810 NULL,
811 NULL);
812 NtClose(FileHandle);
813 if (!NT_SUCCESS(Status))
814 {
815 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
816 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
817 return Status;
818 }
819
820 /*
821 * Copy the disk signature, the reserved fields and
822 * the partition table from the old MBR to the new one.
823 */
824 RtlCopyMemory(&NewBootSector->Signature,
825 &OrigBootSector->Signature,
826 sizeof(PARTITION_SECTOR) - offsetof(PARTITION_SECTOR, Signature)
827 /* Length of partition table */);
828
829 /* Free the original boot sector */
830 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
831
832 /* Open the root partition - Remove any trailing backslash if needed */
833 RtlInitUnicodeString(&Name, RootPath);
834 TrimTrailingPathSeparators_UStr(&Name);
835
836 InitializeObjectAttributes(&ObjectAttributes,
837 &Name,
838 0,
839 NULL,
840 NULL);
841
842 Status = NtOpenFile(&FileHandle,
843 GENERIC_WRITE | SYNCHRONIZE,
844 &ObjectAttributes,
845 &IoStatusBlock,
846 0,
847 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
848 if (!NT_SUCCESS(Status))
849 {
850 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
851 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
852 return Status;
853 }
854
855 /* Write new bootsector to RootPath */
856 FileOffset.QuadPart = 0ULL;
857 Status = NtWriteFile(FileHandle,
858 NULL,
859 NULL,
860 NULL,
861 &IoStatusBlock,
862 NewBootSector,
863 sizeof(PARTITION_SECTOR),
864 &FileOffset,
865 NULL);
866 NtClose(FileHandle);
867
868 /* Free the new boot sector */
869 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
870
871 return Status;
872 }
873
874 NTSTATUS
875 InstallMbrBootCodeToDisk(
876 IN PUNICODE_STRING SystemRootPath,
877 IN PUNICODE_STRING SourceRootPath,
878 IN PCWSTR DestinationDevicePathBuffer)
879 {
880 NTSTATUS Status;
881 WCHAR SourceMbrPathBuffer[MAX_PATH];
882 WCHAR DstPath[MAX_PATH];
883
884 #if 0
885 WCHAR DestinationDevicePathBuffer[MAX_PATH];
886 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
887 L"\\Device\\Harddisk%d\\Partition0",
888 DiskNumber);
889 #endif
890
891 CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2,
892 SourceRootPath->Buffer, L"\\loader\\dosmbr.bin");
893
894 if (IsThereAValidBootSector(DestinationDevicePathBuffer))
895 {
896 /* Save current MBR */
897 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2,
898 SystemRootPath->Buffer, L"mbr.old");
899
900 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
901 Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
902 if (!NT_SUCCESS(Status))
903 {
904 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
905 // Don't care if we succeeded or not saving the old MBR, just go ahead.
906 }
907 }
908
909 DPRINT1("Install MBR bootcode: %S ==> %S\n",
910 SourceMbrPathBuffer, DestinationDevicePathBuffer);
911
912 return InstallMbrBootCodeToDiskHelper(SourceMbrPathBuffer,
913 DestinationDevicePathBuffer);
914 }
915
916
917 static
918 NTSTATUS
919 InstallFat12BootCodeToFloppy(
920 IN PCWSTR SrcPath,
921 IN PCWSTR RootPath)
922 {
923 NTSTATUS Status;
924 UNICODE_STRING Name;
925 OBJECT_ATTRIBUTES ObjectAttributes;
926 IO_STATUS_BLOCK IoStatusBlock;
927 HANDLE FileHandle;
928 LARGE_INTEGER FileOffset;
929 PFAT_BOOTSECTOR OrigBootSector;
930 PFAT_BOOTSECTOR NewBootSector;
931
932 /* Allocate buffer for original bootsector */
933 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
934 if (OrigBootSector == NULL)
935 return STATUS_INSUFFICIENT_RESOURCES;
936
937 /* Open the root partition - Remove any trailing backslash if needed */
938 RtlInitUnicodeString(&Name, RootPath);
939 TrimTrailingPathSeparators_UStr(&Name);
940
941 InitializeObjectAttributes(&ObjectAttributes,
942 &Name,
943 OBJ_CASE_INSENSITIVE,
944 NULL,
945 NULL);
946
947 Status = NtOpenFile(&FileHandle,
948 GENERIC_READ | SYNCHRONIZE,
949 &ObjectAttributes,
950 &IoStatusBlock,
951 0,
952 FILE_SYNCHRONOUS_IO_NONALERT);
953 if (!NT_SUCCESS(Status))
954 {
955 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
956 return Status;
957 }
958
959 /* Read current boot sector into buffer */
960 FileOffset.QuadPart = 0ULL;
961 Status = NtReadFile(FileHandle,
962 NULL,
963 NULL,
964 NULL,
965 &IoStatusBlock,
966 OrigBootSector,
967 SECTORSIZE,
968 &FileOffset,
969 NULL);
970 NtClose(FileHandle);
971 if (!NT_SUCCESS(Status))
972 {
973 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
974 return Status;
975 }
976
977 /* Allocate buffer for new bootsector */
978 NewBootSector = RtlAllocateHeap(ProcessHeap,
979 0,
980 SECTORSIZE);
981 if (NewBootSector == NULL)
982 {
983 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
984 return STATUS_INSUFFICIENT_RESOURCES;
985 }
986
987 /* Read new bootsector from SrcPath */
988 RtlInitUnicodeString(&Name, SrcPath);
989
990 InitializeObjectAttributes(&ObjectAttributes,
991 &Name,
992 OBJ_CASE_INSENSITIVE,
993 NULL,
994 NULL);
995
996 Status = NtOpenFile(&FileHandle,
997 GENERIC_READ | SYNCHRONIZE,
998 &ObjectAttributes,
999 &IoStatusBlock,
1000 0,
1001 FILE_SYNCHRONOUS_IO_NONALERT);
1002 if (!NT_SUCCESS(Status))
1003 {
1004 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1005 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1006 return Status;
1007 }
1008
1009 Status = NtReadFile(FileHandle,
1010 NULL,
1011 NULL,
1012 NULL,
1013 &IoStatusBlock,
1014 NewBootSector,
1015 SECTORSIZE,
1016 NULL,
1017 NULL);
1018 NtClose(FileHandle);
1019 if (!NT_SUCCESS(Status))
1020 {
1021 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1022 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1023 return Status;
1024 }
1025
1026 /* Adjust bootsector (copy a part of the FAT16 BPB) */
1027 memcpy(&NewBootSector->OemName,
1028 &OrigBootSector->OemName,
1029 FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
1030 FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
1031
1032 /* Free the original boot sector */
1033 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1034
1035 /* Open the root partition - Remove any trailing backslash if needed */
1036 RtlInitUnicodeString(&Name, RootPath);
1037 TrimTrailingPathSeparators_UStr(&Name);
1038
1039 InitializeObjectAttributes(&ObjectAttributes,
1040 &Name,
1041 0,
1042 NULL,
1043 NULL);
1044
1045 Status = NtOpenFile(&FileHandle,
1046 GENERIC_WRITE | SYNCHRONIZE,
1047 &ObjectAttributes,
1048 &IoStatusBlock,
1049 0,
1050 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1051 if (!NT_SUCCESS(Status))
1052 {
1053 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1054 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1055 return Status;
1056 }
1057
1058 /* Write new bootsector to RootPath */
1059 FileOffset.QuadPart = 0ULL;
1060 Status = NtWriteFile(FileHandle,
1061 NULL,
1062 NULL,
1063 NULL,
1064 &IoStatusBlock,
1065 NewBootSector,
1066 SECTORSIZE,
1067 &FileOffset,
1068 NULL);
1069 NtClose(FileHandle);
1070
1071 /* Free the new boot sector */
1072 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1073
1074 return Status;
1075 }
1076
1077 static
1078 NTSTATUS
1079 InstallFat16BootCode(
1080 IN PCWSTR SrcPath, // FAT16 bootsector source file (on the installation medium)
1081 IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information
1082 IN HANDLE RootPartition) // Partition holding the (old) FAT16 information
1083 {
1084 NTSTATUS Status;
1085 UNICODE_STRING Name;
1086 OBJECT_ATTRIBUTES ObjectAttributes;
1087 IO_STATUS_BLOCK IoStatusBlock;
1088 HANDLE FileHandle;
1089 LARGE_INTEGER FileOffset;
1090 PFAT_BOOTSECTOR OrigBootSector;
1091 PFAT_BOOTSECTOR NewBootSector;
1092
1093 /* Allocate a buffer for the original bootsector */
1094 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1095 if (OrigBootSector == NULL)
1096 return STATUS_INSUFFICIENT_RESOURCES;
1097
1098 /* Read the current partition boot sector into the buffer */
1099 FileOffset.QuadPart = 0ULL;
1100 Status = NtReadFile(RootPartition,
1101 NULL,
1102 NULL,
1103 NULL,
1104 &IoStatusBlock,
1105 OrigBootSector,
1106 SECTORSIZE,
1107 &FileOffset,
1108 NULL);
1109 if (!NT_SUCCESS(Status))
1110 {
1111 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1112 return Status;
1113 }
1114
1115 /* Allocate a buffer for the new bootsector */
1116 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1117 if (NewBootSector == NULL)
1118 {
1119 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1120 return STATUS_INSUFFICIENT_RESOURCES;
1121 }
1122
1123 /* Read the new bootsector from SrcPath */
1124 RtlInitUnicodeString(&Name, SrcPath);
1125 InitializeObjectAttributes(&ObjectAttributes,
1126 &Name,
1127 OBJ_CASE_INSENSITIVE,
1128 NULL,
1129 NULL);
1130 Status = NtOpenFile(&FileHandle,
1131 GENERIC_READ | SYNCHRONIZE,
1132 &ObjectAttributes,
1133 &IoStatusBlock,
1134 0,
1135 FILE_SYNCHRONOUS_IO_NONALERT);
1136 if (!NT_SUCCESS(Status))
1137 {
1138 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1139 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1140 return Status;
1141 }
1142
1143 FileOffset.QuadPart = 0ULL;
1144 Status = NtReadFile(FileHandle,
1145 NULL,
1146 NULL,
1147 NULL,
1148 &IoStatusBlock,
1149 NewBootSector,
1150 SECTORSIZE,
1151 &FileOffset,
1152 NULL);
1153 NtClose(FileHandle);
1154 if (!NT_SUCCESS(Status))
1155 {
1156 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1157 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1158 return Status;
1159 }
1160
1161 /* Adjust the bootsector (copy a part of the FAT16 BPB) */
1162 memcpy(&NewBootSector->OemName,
1163 &OrigBootSector->OemName,
1164 FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
1165 FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
1166
1167 /* Free the original boot sector */
1168 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1169
1170 /* Write the new bootsector to DstPath */
1171 FileOffset.QuadPart = 0ULL;
1172 Status = NtWriteFile(DstPath,
1173 NULL,
1174 NULL,
1175 NULL,
1176 &IoStatusBlock,
1177 NewBootSector,
1178 SECTORSIZE,
1179 &FileOffset,
1180 NULL);
1181
1182 /* Free the new boot sector */
1183 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1184
1185 return Status;
1186 }
1187
1188 static
1189 NTSTATUS
1190 InstallFat16BootCodeToFile(
1191 IN PCWSTR SrcPath,
1192 IN PCWSTR DstPath,
1193 IN PCWSTR RootPath)
1194 {
1195 NTSTATUS Status;
1196 UNICODE_STRING Name;
1197 OBJECT_ATTRIBUTES ObjectAttributes;
1198 IO_STATUS_BLOCK IoStatusBlock;
1199 HANDLE PartitionHandle, FileHandle;
1200
1201 /*
1202 * Open the root partition from which the boot sector
1203 * parameters will be obtained.
1204 * Remove any trailing backslash if needed.
1205 */
1206 RtlInitUnicodeString(&Name, RootPath);
1207 TrimTrailingPathSeparators_UStr(&Name);
1208
1209 InitializeObjectAttributes(&ObjectAttributes,
1210 &Name,
1211 OBJ_CASE_INSENSITIVE,
1212 NULL,
1213 NULL);
1214 Status = NtOpenFile(&PartitionHandle,
1215 GENERIC_READ | SYNCHRONIZE,
1216 &ObjectAttributes,
1217 &IoStatusBlock,
1218 0,
1219 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
1220 if (!NT_SUCCESS(Status))
1221 return Status;
1222
1223 /* Open or create the file where the new bootsector will be saved */
1224 RtlInitUnicodeString(&Name, DstPath);
1225 InitializeObjectAttributes(&ObjectAttributes,
1226 &Name,
1227 0, // OBJ_CASE_INSENSITIVE,
1228 NULL,
1229 NULL);
1230 Status = NtCreateFile(&FileHandle,
1231 GENERIC_WRITE | SYNCHRONIZE,
1232 &ObjectAttributes,
1233 &IoStatusBlock,
1234 NULL,
1235 FILE_ATTRIBUTE_NORMAL,
1236 0,
1237 FILE_OVERWRITE_IF,
1238 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1239 NULL,
1240 0);
1241 if (!NT_SUCCESS(Status))
1242 {
1243 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
1244 NtClose(PartitionHandle);
1245 return Status;
1246 }
1247
1248 /* Install the FAT16 boot sector */
1249 Status = InstallFat16BootCode(SrcPath, FileHandle, PartitionHandle);
1250
1251 /* Close the file and the partition */
1252 NtClose(FileHandle);
1253 NtClose(PartitionHandle);
1254
1255 return Status;
1256 }
1257
1258 static
1259 NTSTATUS
1260 InstallFat16BootCodeToDisk(
1261 IN PCWSTR SrcPath,
1262 IN PCWSTR RootPath)
1263 {
1264 NTSTATUS Status;
1265 UNICODE_STRING Name;
1266 OBJECT_ATTRIBUTES ObjectAttributes;
1267 IO_STATUS_BLOCK IoStatusBlock;
1268 HANDLE PartitionHandle;
1269
1270 /*
1271 * Open the root partition from which the boot sector parameters will be
1272 * obtained; this is also where we will write the updated boot sector.
1273 * Remove any trailing backslash if needed.
1274 */
1275 RtlInitUnicodeString(&Name, RootPath);
1276 TrimTrailingPathSeparators_UStr(&Name);
1277
1278 InitializeObjectAttributes(&ObjectAttributes,
1279 &Name,
1280 OBJ_CASE_INSENSITIVE,
1281 NULL,
1282 NULL);
1283 Status = NtOpenFile(&PartitionHandle,
1284 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1285 &ObjectAttributes,
1286 &IoStatusBlock,
1287 0,
1288 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1289 if (!NT_SUCCESS(Status))
1290 return Status;
1291
1292 /* Install the FAT16 boot sector */
1293 Status = InstallFat16BootCode(SrcPath, PartitionHandle, PartitionHandle);
1294
1295 /* Close the partition */
1296 NtClose(PartitionHandle);
1297
1298 return Status;
1299 }
1300
1301
1302 static
1303 NTSTATUS
1304 InstallFat32BootCode(
1305 IN PCWSTR SrcPath, // FAT32 bootsector source file (on the installation medium)
1306 IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information
1307 IN HANDLE RootPartition) // Partition holding the (old) FAT32 information
1308 {
1309 NTSTATUS Status;
1310 UNICODE_STRING Name;
1311 OBJECT_ATTRIBUTES ObjectAttributes;
1312 IO_STATUS_BLOCK IoStatusBlock;
1313 HANDLE FileHandle;
1314 LARGE_INTEGER FileOffset;
1315 PFAT32_BOOTSECTOR OrigBootSector;
1316 PFAT32_BOOTSECTOR NewBootSector;
1317 USHORT BackupBootSector;
1318
1319 /* Allocate a buffer for the original bootsector */
1320 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1321 if (OrigBootSector == NULL)
1322 return STATUS_INSUFFICIENT_RESOURCES;
1323
1324 /* Read the current boot sector into the buffer */
1325 FileOffset.QuadPart = 0ULL;
1326 Status = NtReadFile(RootPartition,
1327 NULL,
1328 NULL,
1329 NULL,
1330 &IoStatusBlock,
1331 OrigBootSector,
1332 SECTORSIZE,
1333 &FileOffset,
1334 NULL);
1335 if (!NT_SUCCESS(Status))
1336 {
1337 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1338 return Status;
1339 }
1340
1341 /* Allocate a buffer for the new bootsector (2 sectors) */
1342 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE);
1343 if (NewBootSector == NULL)
1344 {
1345 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1346 return STATUS_INSUFFICIENT_RESOURCES;
1347 }
1348
1349 /* Read the new bootsector from SrcPath */
1350 RtlInitUnicodeString(&Name, SrcPath);
1351 InitializeObjectAttributes(&ObjectAttributes,
1352 &Name,
1353 OBJ_CASE_INSENSITIVE,
1354 NULL,
1355 NULL);
1356 Status = NtOpenFile(&FileHandle,
1357 GENERIC_READ | SYNCHRONIZE,
1358 &ObjectAttributes,
1359 &IoStatusBlock,
1360 0,
1361 FILE_SYNCHRONOUS_IO_NONALERT);
1362 if (!NT_SUCCESS(Status))
1363 {
1364 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1365 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1366 return Status;
1367 }
1368
1369 FileOffset.QuadPart = 0ULL;
1370 Status = NtReadFile(FileHandle,
1371 NULL,
1372 NULL,
1373 NULL,
1374 &IoStatusBlock,
1375 NewBootSector,
1376 2 * SECTORSIZE,
1377 &FileOffset,
1378 NULL);
1379 NtClose(FileHandle);
1380 if (!NT_SUCCESS(Status))
1381 {
1382 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1383 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1384 return Status;
1385 }
1386
1387 /* Adjust the bootsector (copy a part of the FAT32 BPB) */
1388 memcpy(&NewBootSector->OemName,
1389 &OrigBootSector->OemName,
1390 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1391 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1392
1393 /*
1394 * We know we copy the boot code to a file only when DstPath != RootPartition,
1395 * otherwise the boot code is copied to the specified root partition.
1396 */
1397 if (DstPath != RootPartition)
1398 {
1399 /* Copy to a file: Disable the backup boot sector */
1400 NewBootSector->BackupBootSector = 0;
1401 }
1402 else
1403 {
1404 /* Copy to a disk: Get the location of the backup boot sector */
1405 BackupBootSector = OrigBootSector->BackupBootSector;
1406 }
1407
1408 /* Free the original boot sector */
1409 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1410
1411 /* Write the first sector of the new bootcode to DstPath sector 0 */
1412 FileOffset.QuadPart = 0ULL;
1413 Status = NtWriteFile(DstPath,
1414 NULL,
1415 NULL,
1416 NULL,
1417 &IoStatusBlock,
1418 NewBootSector,
1419 SECTORSIZE,
1420 &FileOffset,
1421 NULL);
1422 if (!NT_SUCCESS(Status))
1423 {
1424 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1425 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1426 return Status;
1427 }
1428
1429 if (DstPath == RootPartition)
1430 {
1431 /* Copy to a disk: Write the backup boot sector */
1432 if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1433 {
1434 FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1435 Status = NtWriteFile(DstPath,
1436 NULL,
1437 NULL,
1438 NULL,
1439 &IoStatusBlock,
1440 NewBootSector,
1441 SECTORSIZE,
1442 &FileOffset,
1443 NULL);
1444 if (!NT_SUCCESS(Status))
1445 {
1446 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1447 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1448 return Status;
1449 }
1450 }
1451 }
1452
1453 /* Write the second sector of the new bootcode to boot disk sector 14 */
1454 // FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE);
1455 FileOffset.QuadPart = 14 * SECTORSIZE;
1456 Status = NtWriteFile(DstPath, // or really RootPartition ???
1457 NULL,
1458 NULL,
1459 NULL,
1460 &IoStatusBlock,
1461 ((PUCHAR)NewBootSector + SECTORSIZE),
1462 SECTORSIZE,
1463 &FileOffset,
1464 NULL);
1465 if (!NT_SUCCESS(Status))
1466 {
1467 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1468 }
1469
1470 /* Free the new boot sector */
1471 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1472
1473 return Status;
1474 }
1475
1476 static
1477 NTSTATUS
1478 InstallFat32BootCodeToFile(
1479 IN PCWSTR SrcPath,
1480 IN PCWSTR DstPath,
1481 IN PCWSTR RootPath)
1482 {
1483 NTSTATUS Status;
1484 UNICODE_STRING Name;
1485 OBJECT_ATTRIBUTES ObjectAttributes;
1486 IO_STATUS_BLOCK IoStatusBlock;
1487 HANDLE PartitionHandle, FileHandle;
1488
1489 /*
1490 * Open the root partition from which the boot sector parameters
1491 * will be obtained.
1492 * FIXME? It might be possible that we need to also open it for writing
1493 * access in case we really need to still write the second portion of
1494 * the boot sector ????
1495 *
1496 * Remove any trailing backslash if needed.
1497 */
1498 RtlInitUnicodeString(&Name, RootPath);
1499 TrimTrailingPathSeparators_UStr(&Name);
1500
1501 InitializeObjectAttributes(&ObjectAttributes,
1502 &Name,
1503 OBJ_CASE_INSENSITIVE,
1504 NULL,
1505 NULL);
1506 Status = NtOpenFile(&PartitionHandle,
1507 GENERIC_READ | SYNCHRONIZE,
1508 &ObjectAttributes,
1509 &IoStatusBlock,
1510 0,
1511 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
1512 if (!NT_SUCCESS(Status))
1513 return Status;
1514
1515 /* Open or create the file where (the first sector of ????) the new bootsector will be saved */
1516 RtlInitUnicodeString(&Name, DstPath);
1517 InitializeObjectAttributes(&ObjectAttributes,
1518 &Name,
1519 0, // OBJ_CASE_INSENSITIVE,
1520 NULL,
1521 NULL);
1522 Status = NtCreateFile(&FileHandle,
1523 GENERIC_WRITE | SYNCHRONIZE,
1524 &ObjectAttributes,
1525 &IoStatusBlock,
1526 NULL,
1527 FILE_ATTRIBUTE_NORMAL,
1528 0,
1529 FILE_SUPERSEDE, // FILE_OVERWRITE_IF, <- is used for FAT16
1530 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1531 NULL,
1532 0);
1533 if (!NT_SUCCESS(Status))
1534 {
1535 DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
1536 NtClose(PartitionHandle);
1537 return Status;
1538 }
1539
1540 /* Install the FAT32 boot sector */
1541 Status = InstallFat32BootCode(SrcPath, FileHandle, PartitionHandle);
1542
1543 /* Close the file and the partition */
1544 NtClose(FileHandle);
1545 NtClose(PartitionHandle);
1546
1547 return Status;
1548 }
1549
1550 static
1551 NTSTATUS
1552 InstallFat32BootCodeToDisk(
1553 IN PCWSTR SrcPath,
1554 IN PCWSTR RootPath)
1555 {
1556 NTSTATUS Status;
1557 UNICODE_STRING Name;
1558 OBJECT_ATTRIBUTES ObjectAttributes;
1559 IO_STATUS_BLOCK IoStatusBlock;
1560 HANDLE PartitionHandle;
1561
1562 /*
1563 * Open the root partition from which the boot sector parameters will be
1564 * obtained; this is also where we will write the updated boot sector.
1565 * Remove any trailing backslash if needed.
1566 */
1567 RtlInitUnicodeString(&Name, RootPath);
1568 TrimTrailingPathSeparators_UStr(&Name);
1569
1570 InitializeObjectAttributes(&ObjectAttributes,
1571 &Name,
1572 OBJ_CASE_INSENSITIVE,
1573 NULL,
1574 NULL);
1575 Status = NtOpenFile(&PartitionHandle,
1576 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1577 &ObjectAttributes,
1578 &IoStatusBlock,
1579 0,
1580 FILE_SYNCHRONOUS_IO_NONALERT /* | FILE_SEQUENTIAL_ONLY */);
1581 if (!NT_SUCCESS(Status))
1582 return Status;
1583
1584 /* Install the FAT32 boot sector */
1585 Status = InstallFat32BootCode(SrcPath, PartitionHandle, PartitionHandle);
1586
1587 /* Close the partition */
1588 NtClose(PartitionHandle);
1589
1590 return Status;
1591 }
1592
1593 static
1594 NTSTATUS
1595 InstallBtrfsBootCodeToDisk(
1596 IN PCWSTR SrcPath,
1597 IN PCWSTR RootPath)
1598 {
1599 NTSTATUS Status;
1600 UNICODE_STRING Name;
1601 OBJECT_ATTRIBUTES ObjectAttributes;
1602 IO_STATUS_BLOCK IoStatusBlock;
1603 HANDLE FileHandle;
1604 LARGE_INTEGER FileOffset;
1605 // PEXT2_BOOTSECTOR OrigBootSector;
1606 PBTRFS_BOOTSECTOR NewBootSector;
1607 // USHORT BackupBootSector;
1608 PARTITION_INFORMATION_EX PartInfo;
1609
1610 #if 0
1611 /* Allocate buffer for original bootsector */
1612 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1613 if (OrigBootSector == NULL)
1614 return STATUS_INSUFFICIENT_RESOURCES;
1615
1616 /* Open the root partition - Remove any trailing backslash if needed */
1617 RtlInitUnicodeString(&Name, RootPath);
1618 TrimTrailingPathSeparators_UStr(&Name);
1619
1620 InitializeObjectAttributes(&ObjectAttributes,
1621 &Name,
1622 OBJ_CASE_INSENSITIVE,
1623 NULL,
1624 NULL);
1625
1626 Status = NtOpenFile(&FileHandle,
1627 GENERIC_READ | SYNCHRONIZE,
1628 &ObjectAttributes,
1629 &IoStatusBlock,
1630 0,
1631 FILE_SYNCHRONOUS_IO_NONALERT);
1632 if (!NT_SUCCESS(Status))
1633 {
1634 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1635 return Status;
1636 }
1637
1638 /* Read current boot sector into buffer */
1639 FileOffset.QuadPart = 0ULL;
1640 Status = NtReadFile(FileHandle,
1641 NULL,
1642 NULL,
1643 NULL,
1644 &IoStatusBlock,
1645 OrigBootSector,
1646 SECTORSIZE,
1647 &FileOffset,
1648 NULL);
1649 NtClose(FileHandle);
1650 if (!NT_SUCCESS(Status))
1651 {
1652 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1653 return Status;
1654 }
1655 #endif
1656
1657 /* Allocate buffer for new bootsector */
1658 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(BTRFS_BOOTSECTOR));
1659 if (NewBootSector == NULL)
1660 {
1661 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1662 return STATUS_INSUFFICIENT_RESOURCES;
1663 }
1664
1665 /* Read new bootsector from SrcPath */
1666 RtlInitUnicodeString(&Name, SrcPath);
1667
1668 InitializeObjectAttributes(&ObjectAttributes,
1669 &Name,
1670 OBJ_CASE_INSENSITIVE,
1671 NULL,
1672 NULL);
1673
1674 Status = NtOpenFile(&FileHandle,
1675 GENERIC_READ | SYNCHRONIZE,
1676 &ObjectAttributes,
1677 &IoStatusBlock,
1678 0,
1679 FILE_SYNCHRONOUS_IO_NONALERT);
1680 if (!NT_SUCCESS(Status))
1681 {
1682 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1683 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1684 return Status;
1685 }
1686
1687 Status = NtReadFile(FileHandle,
1688 NULL,
1689 NULL,
1690 NULL,
1691 &IoStatusBlock,
1692 NewBootSector,
1693 sizeof(BTRFS_BOOTSECTOR),
1694 NULL,
1695 NULL);
1696 NtClose(FileHandle);
1697 if (!NT_SUCCESS(Status))
1698 {
1699 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1700 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1701 return Status;
1702 }
1703
1704 #if 0
1705 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1706 memcpy(&NewBootSector->OemName,
1707 &OrigBootSector->OemName,
1708 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1709 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1710
1711 /* Get the location of the backup boot sector */
1712 BackupBootSector = OrigBootSector->BackupBootSector;
1713
1714 /* Free the original boot sector */
1715 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1716 #endif
1717
1718 /* Open the root partition - Remove any trailing backslash if needed */
1719 RtlInitUnicodeString(&Name, RootPath);
1720 TrimTrailingPathSeparators_UStr(&Name);
1721
1722 InitializeObjectAttributes(&ObjectAttributes,
1723 &Name,
1724 0,
1725 NULL,
1726 NULL);
1727
1728 Status = NtOpenFile(&FileHandle,
1729 GENERIC_WRITE | SYNCHRONIZE,
1730 &ObjectAttributes,
1731 &IoStatusBlock,
1732 0,
1733 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1734 if (!NT_SUCCESS(Status))
1735 {
1736 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1737 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1738 return Status;
1739 }
1740
1741 /* Obtaining partition info and writing it to bootsector */
1742 Status = NtDeviceIoControlFile(FileHandle,
1743 NULL,
1744 NULL,
1745 NULL,
1746 &IoStatusBlock,
1747 IOCTL_DISK_GET_PARTITION_INFO_EX,
1748 NULL,
1749 0,
1750 &PartInfo,
1751 sizeof(PartInfo));
1752 if (!NT_SUCCESS(Status))
1753 {
1754 DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status);
1755 NtClose(FileHandle);
1756 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1757 return Status;
1758 }
1759
1760 /* Write new bootsector to RootPath */
1761
1762 NewBootSector->PartitionStartLBA = PartInfo.StartingOffset.QuadPart / SECTORSIZE;
1763
1764 /* Write sector 0 */
1765 FileOffset.QuadPart = 0ULL;
1766 Status = NtWriteFile(FileHandle,
1767 NULL,
1768 NULL,
1769 NULL,
1770 &IoStatusBlock,
1771 NewBootSector,
1772 sizeof(BTRFS_BOOTSECTOR),
1773 &FileOffset,
1774 NULL);
1775 #if 0
1776 if (!NT_SUCCESS(Status))
1777 {
1778 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1779 NtClose(FileHandle);
1780 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1781 return Status;
1782 }
1783
1784 /* Write backup boot sector */
1785 if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1786 {
1787 FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1788 Status = NtWriteFile(FileHandle,
1789 NULL,
1790 NULL,
1791 NULL,
1792 &IoStatusBlock,
1793 NewBootSector,
1794 SECTORSIZE,
1795 &FileOffset,
1796 NULL);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1800 NtClose(FileHandle);
1801 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1802 return Status;
1803 }
1804 }
1805
1806 /* Write sector 14 */
1807 FileOffset.QuadPart = 14 * SECTORSIZE;
1808 Status = NtWriteFile(FileHandle,
1809 NULL,
1810 NULL,
1811 NULL,
1812 &IoStatusBlock,
1813 ((PUCHAR)NewBootSector + SECTORSIZE),
1814 SECTORSIZE,
1815 &FileOffset,
1816 NULL);
1817 if (!NT_SUCCESS(Status))
1818 {
1819 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1820 }
1821 #endif
1822 NtClose(FileHandle);
1823
1824 /* Free the new boot sector */
1825 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1826
1827 return Status;
1828 }
1829
1830
1831 static
1832 NTSTATUS
1833 InstallFatBootcodeToPartition(
1834 IN PUNICODE_STRING SystemRootPath,
1835 IN PUNICODE_STRING SourceRootPath,
1836 IN PUNICODE_STRING DestinationArcPath,
1837 IN UCHAR PartitionType)
1838 {
1839 NTSTATUS Status;
1840 BOOLEAN DoesFreeLdrExist;
1841 WCHAR SrcPath[MAX_PATH];
1842 WCHAR DstPath[MAX_PATH];
1843
1844 /* FAT or FAT32 partition */
1845 DPRINT("System path: '%wZ'\n", SystemRootPath);
1846
1847 /* Copy FreeLoader to the system partition, always overwriting the older version */
1848 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
1849 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
1850
1851 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
1852 Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1853 if (!NT_SUCCESS(Status))
1854 {
1855 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1856 return Status;
1857 }
1858
1859 /* Prepare for possibly updating 'freeldr.ini' */
1860 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini");
1861 if (DoesFreeLdrExist)
1862 {
1863 /* Update existing 'freeldr.ini' */
1864 DPRINT1("Update existing 'freeldr.ini'\n");
1865 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1866 if (!NT_SUCCESS(Status))
1867 {
1868 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
1869 return Status;
1870 }
1871 }
1872
1873 /* Check for NT and other bootloaders */
1874
1875 // FIXME: Check for Vista+ bootloader!
1876 /*** Status = FindBootStore(PartitionHandle, NtLdr, &Version); ***/
1877 /*** Status = FindBootStore(PartitionHandle, BootMgr, &Version); ***/
1878 if (DoesFileExist_2(SystemRootPath->Buffer, L"NTLDR") == TRUE ||
1879 DoesFileExist_2(SystemRootPath->Buffer, L"BOOT.INI") == TRUE)
1880 {
1881 /* Search root directory for 'NTLDR' and 'BOOT.INI' */
1882 DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
1883
1884 /* Create or update 'freeldr.ini' */
1885 if (DoesFreeLdrExist == FALSE)
1886 {
1887 /* Create new 'freeldr.ini' */
1888 DPRINT1("Create new 'freeldr.ini'\n");
1889 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
1890 if (!NT_SUCCESS(Status))
1891 {
1892 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
1893 return Status;
1894 }
1895
1896 /* Install new bootcode into a file */
1897 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"bootsect.ros");
1898
1899 if (PartitionType == PARTITION_FAT32 ||
1900 PartitionType == PARTITION_FAT32_XINT13)
1901 {
1902 /* Install FAT32 bootcode */
1903 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin");
1904
1905 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
1906 Status = InstallFat32BootCodeToFile(SrcPath, DstPath,
1907 SystemRootPath->Buffer);
1908 if (!NT_SUCCESS(Status))
1909 {
1910 DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
1911 return Status;
1912 }
1913 }
1914 else
1915 {
1916 /* Install FAT16 bootcode */
1917 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
1918
1919 DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
1920 Status = InstallFat16BootCodeToFile(SrcPath, DstPath,
1921 SystemRootPath->Buffer);
1922 if (!NT_SUCCESS(Status))
1923 {
1924 DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
1925 return Status;
1926 }
1927 }
1928 }
1929
1930 /* Update 'boot.ini' */
1931 /* Windows' NTLDR loads an external bootsector file when the specified drive
1932 letter is C:, otherwise it will interpret it as a boot DOS path specifier. */
1933 DPRINT1("Update 'boot.ini'\n");
1934 Status = UpdateBootIni(SystemRootPath->Buffer,
1935 L"C:\\bootsect.ros",
1936 L"\"ReactOS\"");
1937 if (!NT_SUCCESS(Status))
1938 {
1939 DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
1940 return Status;
1941 }
1942 }
1943 else
1944 {
1945 /* Non-NT bootloaders: install our own bootloader */
1946
1947 PCWSTR Section;
1948 PCWSTR Description;
1949 PCWSTR BootDrive;
1950 PCWSTR BootPartition;
1951 PCWSTR BootSector;
1952
1953 /* Search for COMPAQ MS-DOS 1.x (1.11, 1.12, based on MS-DOS 1.25) boot loader */
1954 if (DoesFileExist_2(SystemRootPath->Buffer, L"IOSYS.COM") == TRUE ||
1955 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.COM") == TRUE)
1956 {
1957 DPRINT1("Found COMPAQ MS-DOS 1.x (1.11, 1.12) / MS-DOS 1.25 boot loader\n");
1958
1959 Section = L"CPQDOS";
1960 Description = L"\"COMPAQ MS-DOS 1.x / MS-DOS 1.25\"";
1961 BootDrive = L"hd0";
1962 BootPartition = L"1";
1963 BootSector = L"BOOTSECT.DOS";
1964 }
1965 else
1966 /* Search for Microsoft DOS or Windows 9x boot loader */
1967 if (DoesFileExist_2(SystemRootPath->Buffer, L"IO.SYS") == TRUE ||
1968 DoesFileExist_2(SystemRootPath->Buffer, L"MSDOS.SYS") == TRUE)
1969 // WINBOOT.SYS
1970 {
1971 DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
1972
1973 Section = L"MSDOS";
1974 Description = L"\"MS-DOS/Windows\"";
1975 BootDrive = L"hd0";
1976 BootPartition = L"1";
1977 BootSector = L"BOOTSECT.DOS";
1978 }
1979 else
1980 /* Search for IBM PC-DOS or DR-DOS 5.x boot loader */
1981 if (DoesFileExist_2(SystemRootPath->Buffer, L"IBMIO.COM" ) == TRUE || // Some people refer to this file instead of IBMBIO.COM...
1982 DoesFileExist_2(SystemRootPath->Buffer, L"IBMBIO.COM") == TRUE ||
1983 DoesFileExist_2(SystemRootPath->Buffer, L"IBMDOS.COM") == TRUE)
1984 {
1985 DPRINT1("Found IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\n");
1986
1987 Section = L"IBMDOS";
1988 Description = L"\"IBM PC-DOS or DR-DOS 5.x or IBM OS/2 1.0\"";
1989 BootDrive = L"hd0";
1990 BootPartition = L"1";
1991 BootSector = L"BOOTSECT.DOS";
1992 }
1993 else
1994 /* Search for DR-DOS 3.x boot loader */
1995 if (DoesFileExist_2(SystemRootPath->Buffer, L"DRBIOS.SYS") == TRUE ||
1996 DoesFileExist_2(SystemRootPath->Buffer, L"DRBDOS.SYS") == TRUE)
1997 {
1998 DPRINT1("Found DR-DOS 3.x\n");
1999
2000 Section = L"DRDOS";
2001 Description = L"\"DR-DOS 3.x\"";
2002 BootDrive = L"hd0";
2003 BootPartition = L"1";
2004 BootSector = L"BOOTSECT.DOS";
2005 }
2006 else
2007 /* Search for Dell Real-Mode Kernel (DRMK) OS */
2008 if (DoesFileExist_2(SystemRootPath->Buffer, L"DELLBIO.BIN") == TRUE ||
2009 DoesFileExist_2(SystemRootPath->Buffer, L"DELLRMK.BIN") == TRUE)
2010 {
2011 DPRINT1("Found Dell Real-Mode Kernel OS\n");
2012
2013 Section = L"DRMK";
2014 Description = L"\"Dell Real-Mode Kernel OS\"";
2015 BootDrive = L"hd0";
2016 BootPartition = L"1";
2017 BootSector = L"BOOTSECT.DOS";
2018 }
2019 else
2020 /* Search for MS OS/2 1.x */
2021 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT.COM") == TRUE ||
2022 DoesFileExist_2(SystemRootPath->Buffer, L"OS2BIO.COM" ) == TRUE ||
2023 DoesFileExist_2(SystemRootPath->Buffer, L"OS2DOS.COM" ) == TRUE)
2024 {
2025 DPRINT1("Found MS OS/2 1.x\n");
2026
2027 Section = L"MSOS2";
2028 Description = L"\"MS OS/2 1.x\"";
2029 BootDrive = L"hd0";
2030 BootPartition = L"1";
2031 BootSector = L"BOOTSECT.OS2";
2032 }
2033 else
2034 /* Search for MS or IBM OS/2 */
2035 if (DoesFileExist_2(SystemRootPath->Buffer, L"OS2BOOT") == TRUE ||
2036 DoesFileExist_2(SystemRootPath->Buffer, L"OS2LDR" ) == TRUE ||
2037 DoesFileExist_2(SystemRootPath->Buffer, L"OS2KRNL") == TRUE)
2038 {
2039 DPRINT1("Found MS/IBM OS/2\n");
2040
2041 Section = L"IBMOS2";
2042 Description = L"\"MS/IBM OS/2\"";
2043 BootDrive = L"hd0";
2044 BootPartition = L"1";
2045 BootSector = L"BOOTSECT.OS2";
2046 }
2047 else
2048 /* Search for FreeDOS boot loader */
2049 if (DoesFileExist_2(SystemRootPath->Buffer, L"kernel.sys") == TRUE)
2050 {
2051 DPRINT1("Found FreeDOS boot loader\n");
2052
2053 Section = L"FDOS";
2054 Description = L"\"FreeDOS\"";
2055 BootDrive = L"hd0";
2056 BootPartition = L"1";
2057 BootSector = L"BOOTSECT.DOS";
2058 }
2059 else
2060 {
2061 /* No or unknown boot loader */
2062 DPRINT1("No or unknown boot loader found\n");
2063
2064 Section = L"Unknown";
2065 Description = L"\"Unknown Operating System\"";
2066 BootDrive = L"hd0";
2067 BootPartition = L"1";
2068 BootSector = L"BOOTSECT.OLD";
2069 }
2070
2071 /* Create or update 'freeldr.ini' */
2072 if (DoesFreeLdrExist == FALSE)
2073 {
2074 /* Create new 'freeldr.ini' */
2075 DPRINT1("Create new 'freeldr.ini'\n");
2076
2077 if (IsThereAValidBootSector(SystemRootPath->Buffer))
2078 {
2079 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2080 SystemRootPath->Buffer, DestinationArcPath->Buffer,
2081 Section, Description,
2082 BootDrive, BootPartition, BootSector);
2083 if (!NT_SUCCESS(Status))
2084 {
2085 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2086 return Status;
2087 }
2088
2089 /* Save current bootsector */
2090 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
2091
2092 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2093 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE);
2094 if (!NT_SUCCESS(Status))
2095 {
2096 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
2097 return Status;
2098 }
2099 }
2100 else
2101 {
2102 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
2103 if (!NT_SUCCESS(Status))
2104 {
2105 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2106 return Status;
2107 }
2108 }
2109
2110 /* Install new bootsector on the disk */
2111 if (PartitionType == PARTITION_FAT32 ||
2112 PartitionType == PARTITION_FAT32_XINT13)
2113 {
2114 /* Install FAT32 bootcode */
2115 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat32.bin");
2116
2117 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2118 Status = InstallFat32BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2119 if (!NT_SUCCESS(Status))
2120 {
2121 DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
2122 return Status;
2123 }
2124 }
2125 else
2126 {
2127 /* Install FAT16 bootcode */
2128 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
2129
2130 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2131 Status = InstallFat16BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2132 if (!NT_SUCCESS(Status))
2133 {
2134 DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2135 return Status;
2136 }
2137 }
2138 }
2139 }
2140
2141 return STATUS_SUCCESS;
2142 }
2143
2144 static
2145 NTSTATUS
2146 InstallBtrfsBootcodeToPartition(
2147 IN PUNICODE_STRING SystemRootPath,
2148 IN PUNICODE_STRING SourceRootPath,
2149 IN PUNICODE_STRING DestinationArcPath,
2150 IN UCHAR PartitionType)
2151 {
2152 NTSTATUS Status;
2153 BOOLEAN DoesFreeLdrExist;
2154 WCHAR SrcPath[MAX_PATH];
2155 WCHAR DstPath[MAX_PATH];
2156
2157 /* BTRFS partition */
2158 DPRINT("System path: '%wZ'\n", SystemRootPath);
2159
2160 /* Copy FreeLoader to the system partition, always overwriting the older version */
2161 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
2162 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
2163
2164 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2165 Status = SetupCopyFile(SrcPath, DstPath, FALSE);
2166 if (!NT_SUCCESS(Status))
2167 {
2168 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2169 return Status;
2170 }
2171
2172 /* Prepare for possibly updating 'freeldr.ini' */
2173 DoesFreeLdrExist = DoesFileExist_2(SystemRootPath->Buffer, L"freeldr.ini");
2174 if (DoesFreeLdrExist)
2175 {
2176 /* Update existing 'freeldr.ini' */
2177 DPRINT1("Update existing 'freeldr.ini'\n");
2178 Status = UpdateFreeLoaderIni(SystemRootPath->Buffer, DestinationArcPath->Buffer);
2179 if (!NT_SUCCESS(Status))
2180 {
2181 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2182 return Status;
2183 }
2184 }
2185
2186 /* Check for *nix bootloaders */
2187
2188 /* Create or update 'freeldr.ini' */
2189 if (DoesFreeLdrExist == FALSE)
2190 {
2191 /* Create new 'freeldr.ini' */
2192 DPRINT1("Create new 'freeldr.ini'\n");
2193
2194 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */
2195 DPRINT1("*nix or unknown boot loader found\n");
2196
2197 if (IsThereAValidBootSector(SystemRootPath->Buffer))
2198 {
2199 PCWSTR BootSector = L"BOOTSECT.OLD";
2200
2201 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2202 SystemRootPath->Buffer, DestinationArcPath->Buffer,
2203 L"Linux", L"\"Linux\"",
2204 L"hd0", L"1", BootSector);
2205 if (!NT_SUCCESS(Status))
2206 {
2207 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2208 return Status;
2209 }
2210
2211 /* Save current bootsector */
2212 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, BootSector);
2213
2214 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2215 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(BTRFS_BOOTSECTOR));
2216 if (!NT_SUCCESS(Status))
2217 {
2218 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
2219 return Status;
2220 }
2221 }
2222 else
2223 {
2224 Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer);
2225 if (!NT_SUCCESS(Status))
2226 {
2227 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2228 return Status;
2229 }
2230 }
2231
2232 /* Install new bootsector on the disk */
2233 // if (PartitionType == PARTITION_EXT2)
2234 {
2235 /* Install BTRFS bootcode */
2236 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\btrfs.bin");
2237
2238 DPRINT1("Install BTRFS bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2239 Status = InstallBtrfsBootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2240 if (!NT_SUCCESS(Status))
2241 {
2242 DPRINT1("InstallBtrfsBootCodeToDisk() failed (Status %lx)\n", Status);
2243 return Status;
2244 }
2245 }
2246 }
2247
2248 return STATUS_SUCCESS;
2249 }
2250
2251
2252 NTSTATUS
2253 InstallVBRToPartition(
2254 IN PUNICODE_STRING SystemRootPath,
2255 IN PUNICODE_STRING SourceRootPath,
2256 IN PUNICODE_STRING DestinationArcPath,
2257 IN UCHAR PartitionType)
2258 {
2259 switch (PartitionType)
2260 {
2261 case PARTITION_FAT_12:
2262 case PARTITION_FAT_16:
2263 case PARTITION_HUGE:
2264 case PARTITION_XINT13:
2265 case PARTITION_FAT32:
2266 case PARTITION_FAT32_XINT13:
2267 {
2268 return InstallFatBootcodeToPartition(SystemRootPath,
2269 SourceRootPath,
2270 DestinationArcPath,
2271 PartitionType);
2272 }
2273
2274 case PARTITION_LINUX:
2275 {
2276 return InstallBtrfsBootcodeToPartition(SystemRootPath,
2277 SourceRootPath,
2278 DestinationArcPath,
2279 PartitionType);
2280 }
2281
2282 case PARTITION_IFS:
2283 DPRINT1("Partitions of type NTFS or HPFS are not supported yet!\n");
2284 break;
2285
2286 default:
2287 DPRINT1("PartitionType 0x%02X unknown!\n", PartitionType);
2288 break;
2289 }
2290
2291 return STATUS_UNSUCCESSFUL;
2292 }
2293
2294
2295 NTSTATUS
2296 InstallFatBootcodeToFloppy(
2297 IN PUNICODE_STRING SourceRootPath,
2298 IN PUNICODE_STRING DestinationArcPath)
2299 {
2300 NTSTATUS Status;
2301 PFILE_SYSTEM FatFS;
2302 UNICODE_STRING FloppyDevice = RTL_CONSTANT_STRING(L"\\Device\\Floppy0\\");
2303 WCHAR SrcPath[MAX_PATH];
2304 WCHAR DstPath[MAX_PATH];
2305
2306 /* Verify that the floppy disk is accessible */
2307 if (DoesDirExist(NULL, FloppyDevice.Buffer) == FALSE)
2308 return STATUS_DEVICE_NOT_READY;
2309
2310 /* Format the floppy disk */
2311 FatFS = GetFileSystemByName(L"FAT");
2312 if (!FatFS)
2313 {
2314 DPRINT1("FAT FS non existent on this system?!\n");
2315 return STATUS_NOT_SUPPORTED;
2316 }
2317 Status = FatFS->FormatFunc(&FloppyDevice,
2318 FMIFS_FLOPPY,
2319 NULL,
2320 TRUE,
2321 0,
2322 NULL);
2323 if (!NT_SUCCESS(Status))
2324 {
2325 DPRINT1("VfatFormat() failed (Status %lx)\n", Status);
2326 return Status;
2327 }
2328
2329 /* Copy FreeLoader to the boot partition */
2330 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys");
2331 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice.Buffer, L"freeldr.sys");
2332
2333 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2334 Status = SetupCopyFile(SrcPath, DstPath, FALSE);
2335 if (!NT_SUCCESS(Status))
2336 {
2337 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2338 return Status;
2339 }
2340
2341 /* Create new 'freeldr.ini' */
2342 DPRINT("Create new 'freeldr.ini'\n");
2343 Status = CreateFreeLoaderIniForReactOS(FloppyDevice.Buffer, DestinationArcPath->Buffer);
2344 if (!NT_SUCCESS(Status))
2345 {
2346 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2347 return Status;
2348 }
2349
2350 /* Install FAT12 boosector */
2351 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin");
2352 CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice.Buffer);
2353
2354 DPRINT("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2355 Status = InstallFat12BootCodeToFloppy(SrcPath, DstPath);
2356 if (!NT_SUCCESS(Status))
2357 {
2358 DPRINT1("InstallFat12BootCodeToFloppy() failed (Status %lx)\n", Status);
2359 return Status;
2360 }
2361
2362 return STATUS_SUCCESS;
2363 }
2364
2365 /* EOF */