68b64aa4cf6f1bd81b3f72a8012bef07351d43f6
[reactos.git] / reactos / 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 * PROGRAMMER: Eric Kohl
7 */
8
9 #include "usetup.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #define SECTORSIZE 512
15
16 #include <pshpack1.h>
17 typedef struct _FAT_BOOTSECTOR
18 {
19 UCHAR JumpBoot[3]; // Jump instruction to boot code
20 CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes
21 USHORT BytesPerSector; // Bytes per sector
22 UCHAR SectorsPerCluster; // Number of sectors in a cluster
23 USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector)
24 UCHAR NumberOfFats; // Number of FAT tables
25 USHORT RootDirEntries; // Number of root directory entries (fat12/16)
26 USHORT TotalSectors; // Number of total sectors on the drive, 16-bit
27 UCHAR MediaDescriptor; // Media descriptor byte
28 USHORT SectorsPerFat; // Sectors per FAT table (fat12/16)
29 USHORT SectorsPerTrack; // Number of sectors in a track
30 USHORT NumberOfHeads; // Number of heads on the disk
31 ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table)
32 ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume
33 UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80)
34 UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
35 UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
36 ULONG VolumeSerialNumber; // Volume serial number
37 CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory
38 CHAR FileSystemType[8]; // One of the strings "FAT12 ", "FAT16 ", or "FAT "
39
40 UCHAR BootCodeAndData[448]; // The remainder of the boot sector
41
42 USHORT BootSectorMagic; // 0xAA55
43
44 } FAT_BOOTSECTOR, *PFAT_BOOTSECTOR;
45
46 typedef struct _FAT32_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 ULONG SectorsPerFatBig; // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0
63 USHORT ExtendedFlags; // Extended flags (fat32)
64 USHORT FileSystemVersion; // File system version (fat32)
65 ULONG RootDirStartCluster; // Starting cluster of the root directory (fat32)
66 USHORT FsInfo; // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1.
67 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.
68 UCHAR Reserved[12]; // Reserved for future expansion
69 UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80)
70 UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
71 UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
72 ULONG VolumeSerialNumber; // Volume serial number
73 CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory
74 CHAR FileSystemType[8]; // Always set to the string "FAT32 "
75
76 UCHAR BootCodeAndData[420]; // The remainder of the boot sector
77
78 USHORT BootSectorMagic; // 0xAA55
79
80 } FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR;
81
82 typedef struct _EXT2_BOOTSECTOR
83 {
84 // The EXT2 bootsector is completely user-specific.
85 // No FS data is stored there.
86 UCHAR Fill[1024];
87 } EXT2_BOOTSECTOR, *PEXT2_BOOTSECTOR;
88
89 // TODO: Add more bootsector structures!
90
91 #include <poppack.h>
92
93 extern PPARTLIST PartitionList;
94
95 /* FUNCTIONS ****************************************************************/
96
97
98 static
99 VOID
100 CreateCommonFreeLoaderSections(
101 PINICACHE IniCache)
102 {
103 PINICACHESECTION IniSection;
104
105 /* Create "FREELOADER" section */
106 IniSection = IniCacheAppendSection(IniCache, L"FREELOADER");
107
108 #if DBG
109 if (IsUnattendedSetup)
110 {
111 /* DefaultOS=ReactOS */
112 IniCacheInsertKey(IniSection,
113 NULL,
114 INSERT_LAST,
115 L"DefaultOS",
116 #ifndef _WINKD_
117 L"ReactOS_KdSerial");
118 #else
119 L"ReactOS_Debug");
120 #endif
121 }
122 else
123 #endif
124 {
125 /* DefaultOS=ReactOS */
126 IniCacheInsertKey(IniSection,
127 NULL,
128 INSERT_LAST,
129 L"DefaultOS",
130 L"ReactOS");
131 }
132
133 #if DBG
134 if (IsUnattendedSetup)
135 #endif
136 {
137 /* Timeout=0 for unattended or non debug*/
138 IniCacheInsertKey(IniSection,
139 NULL,
140 INSERT_LAST,
141 L"TimeOut",
142 L"0");
143 }
144 #if DBG
145 else
146 {
147 /* Timeout=0 or 10 */
148 IniCacheInsertKey(IniSection,
149 NULL,
150 INSERT_LAST,
151 L"TimeOut",
152 L"10");
153 }
154 #endif
155
156 /* Create "Display" section */
157 IniSection = IniCacheAppendSection(IniCache, L"Display");
158
159 /* TitleText=ReactOS Boot Manager */
160 IniCacheInsertKey(IniSection,
161 NULL,
162 INSERT_LAST,
163 L"TitleText",
164 L"ReactOS Boot Manager");
165
166 /* StatusBarColor=Cyan */
167 IniCacheInsertKey(IniSection,
168 NULL,
169 INSERT_LAST,
170 L"StatusBarColor",
171 L"Cyan");
172
173 /* StatusBarTextColor=Black */
174 IniCacheInsertKey(IniSection,
175 NULL,
176 INSERT_LAST,
177 L"StatusBarTextColor",
178 L"Black");
179
180 /* BackdropTextColor=White */
181 IniCacheInsertKey(IniSection,
182 NULL,
183 INSERT_LAST,
184 L"BackdropTextColor",
185 L"White");
186
187 /* BackdropColor=Blue */
188 IniCacheInsertKey(IniSection,
189 NULL,
190 INSERT_LAST,
191 L"BackdropColor",
192 L"Blue");
193
194 /* BackdropFillStyle=Medium */
195 IniCacheInsertKey(IniSection,
196 NULL,
197 INSERT_LAST,
198 L"BackdropFillStyle",
199 L"Medium");
200
201 /* TitleBoxTextColor=White */
202 IniCacheInsertKey(IniSection,
203 NULL,
204 INSERT_LAST,
205 L"TitleBoxTextColor",
206 L"White");
207
208 /* TitleBoxColor=Red */
209 IniCacheInsertKey(IniSection,
210 NULL,
211 INSERT_LAST,
212 L"TitleBoxColor",
213 L"Red");
214
215 /* MessageBoxTextColor=White */
216 IniCacheInsertKey(IniSection,
217 NULL,
218 INSERT_LAST,
219 L"MessageBoxTextColor",
220 L"White");
221
222 /* MessageBoxColor=Blue */
223 IniCacheInsertKey(IniSection,
224 NULL,
225 INSERT_LAST,
226 L"MessageBoxColor",
227 L"Blue");
228
229 /* MenuTextColor=White */
230 IniCacheInsertKey(IniSection,
231 NULL,
232 INSERT_LAST,
233 L"MenuTextColor",
234 L"Gray");
235
236 /* MenuColor=Blue */
237 IniCacheInsertKey(IniSection,
238 NULL,
239 INSERT_LAST,
240 L"MenuColor",
241 L"Black");
242
243 /* TextColor=Yellow */
244 IniCacheInsertKey(IniSection,
245 NULL,
246 INSERT_LAST,
247 L"TextColor",
248 L"Gray");
249
250 /* SelectedTextColor=Black */
251 IniCacheInsertKey(IniSection,
252 NULL,
253 INSERT_LAST,
254 L"SelectedTextColor",
255 L"Black");
256
257 /* SelectedColor=Gray */
258 IniCacheInsertKey(IniSection,
259 NULL,
260 INSERT_LAST,
261 L"SelectedColor",
262 L"Gray");
263
264 /* SelectedColor=Gray */
265 IniCacheInsertKey(IniSection,
266 NULL,
267 INSERT_LAST,
268 L"ShowTime",
269 L"No");
270
271 /* SelectedColor=Gray */
272 IniCacheInsertKey(IniSection,
273 NULL,
274 INSERT_LAST,
275 L"MenuBox",
276 L"No");
277
278 /* SelectedColor=Gray */
279 IniCacheInsertKey(IniSection,
280 NULL,
281 INSERT_LAST,
282 L"CenterMenu",
283 L"No");
284
285 /* SelectedColor=Gray */
286 IniCacheInsertKey(IniSection,
287 NULL,
288 INSERT_LAST,
289 L"MinimalUI",
290 L"Yes");
291
292 /* SelectedColor=Gray */
293 IniCacheInsertKey(IniSection,
294 NULL,
295 INSERT_LAST,
296 L"TimeText",
297 L"Seconds until highlighted choice will be started automatically: ");
298 }
299
300 static
301 NTSTATUS
302 CreateNTOSEntry(
303 PINICACHE IniCache,
304 PINICACHESECTION OSSection,
305 PWCHAR Section,
306 PWCHAR Description,
307 PWCHAR BootType,
308 PWCHAR ArcPath,
309 PWCHAR Options)
310 {
311 PINICACHESECTION IniSection;
312
313 /* Insert entry into "Operating Systems" section */
314 IniCacheInsertKey(OSSection,
315 NULL,
316 INSERT_LAST,
317 Section,
318 Description);
319
320 /* Create new section */
321 IniSection = IniCacheAppendSection(IniCache, Section);
322
323 /* BootType= */
324 IniCacheInsertKey(IniSection,
325 NULL,
326 INSERT_LAST,
327 L"BootType",
328 BootType);
329
330 /* SystemPath= */
331 IniCacheInsertKey(IniSection,
332 NULL,
333 INSERT_LAST,
334 L"SystemPath",
335 ArcPath);
336
337 /* Options= */
338 IniCacheInsertKey(IniSection,
339 NULL,
340 INSERT_LAST,
341 L"Options",
342 Options);
343
344 return STATUS_SUCCESS;
345 }
346
347 static
348 VOID
349 CreateFreeLoaderReactOSEntries(
350 PINICACHE IniCache,
351 PWCHAR ArcPath)
352 {
353 PINICACHESECTION IniSection;
354
355 /* Create "Operating Systems" section */
356 IniSection = IniCacheAppendSection(IniCache, L"Operating Systems");
357
358 /* ReactOS */
359 CreateNTOSEntry(IniCache, IniSection,
360 L"ReactOS", L"\"ReactOS\"",
361 L"Windows2003", ArcPath,
362 L"");
363
364 /* ReactOS_Debug */
365 CreateNTOSEntry(IniCache, IniSection,
366 L"ReactOS_Debug", L"\"ReactOS (Debug)\"",
367 L"Windows2003", ArcPath,
368 L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS");
369 #ifdef _WINKD_
370 /* ReactOS_VBoxDebug */
371 CreateNTOSEntry(IniCache, IniSection,
372 L"ReactOS_VBoxDebug", L"\"ReactOS (VBoxDebug)\"",
373 L"Windows2003", ArcPath,
374 L"/DEBUG /DEBUGPORT=VBOX /SOS");
375 #endif
376 #if DBG
377 #ifndef _WINKD_
378 /* ReactOS_KdSerial */
379 CreateNTOSEntry(IniCache, IniSection,
380 L"ReactOS_KdSerial", L"\"ReactOS (RosDbg)\"",
381 L"Windows2003", ArcPath,
382 L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /KDSERIAL");
383 #endif
384
385 /* ReactOS_Screen */
386 CreateNTOSEntry(IniCache, IniSection,
387 L"ReactOS_Screen", L"\"ReactOS (Screen)\"",
388 L"Windows2003", ArcPath,
389 L"/DEBUG /DEBUGPORT=SCREEN /SOS");
390
391 /* ReactOS_LogFile */
392 CreateNTOSEntry(IniCache, IniSection,
393 L"ReactOS_LogFile", L"\"ReactOS (Log file)\"",
394 L"Windows2003", ArcPath,
395 L"/DEBUG /DEBUGPORT=FILE /SOS");
396
397 /* ReactOS_Ram */
398 CreateNTOSEntry(IniCache, IniSection,
399 L"ReactOS_Ram", L"\"ReactOS (RAM Disk)\"",
400 L"Windows2003", L"ramdisk(0)\\ReactOS",
401 L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /RDPATH=reactos.img /RDIMAGEOFFSET=32256");
402
403 /* ReactOS_EMS */
404 CreateNTOSEntry(IniCache, IniSection,
405 L"ReactOS_EMS", L"\"ReactOS (Emergency Management Services)\"",
406 L"Windows2003", ArcPath,
407 L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /redirect=com2 /redirectbaudrate=115200");
408 #endif
409 }
410
411 static
412 NTSTATUS
413 CreateFreeLoaderIniForReactOS(
414 PWCHAR IniPath,
415 PWCHAR ArcPath)
416 {
417 PINICACHE IniCache;
418
419 /* Initialize the INI file */
420 IniCache = IniCacheCreate();
421
422 /* Create the common FreeLdr sections */
423 CreateCommonFreeLoaderSections(IniCache);
424
425 /* Add the ReactOS entries */
426 CreateFreeLoaderReactOSEntries(IniCache, ArcPath);
427
428 /* Save the INI file */
429 IniCacheSave(IniCache, IniPath);
430 IniCacheDestroy(IniCache);
431
432 return STATUS_SUCCESS;
433 }
434
435 static
436 NTSTATUS
437 CreateFreeLoaderIniForReactOSAndBootSector(
438 PWCHAR IniPath,
439 PWCHAR ArcPath,
440 PWCHAR Section,
441 PWCHAR Description,
442 PWCHAR BootDrive,
443 PWCHAR BootPartition,
444 PWCHAR BootSector)
445 {
446 PINICACHE IniCache;
447 PINICACHESECTION IniSection;
448
449 /* Initialize the INI file */
450 IniCache = IniCacheCreate();
451
452 /* Create the common FreeLdr sections */
453 CreateCommonFreeLoaderSections(IniCache);
454
455 /* Add the ReactOS entries */
456 CreateFreeLoaderReactOSEntries(IniCache, ArcPath);
457
458 /* Get "Operating Systems" section */
459 IniSection = IniCacheGetSection(IniCache, L"Operating Systems");
460
461 /* Insert entry into "Operating Systems" section */
462 IniCacheInsertKey(IniSection,
463 NULL,
464 INSERT_LAST,
465 Section,
466 Description);
467
468 /* Create new section */
469 IniSection = IniCacheAppendSection(IniCache, Section);
470
471 /* BootType=BootSector */
472 IniCacheInsertKey(IniSection,
473 NULL,
474 INSERT_LAST,
475 L"BootType",
476 L"BootSector");
477
478 /* BootDrive= */
479 IniCacheInsertKey(IniSection,
480 NULL,
481 INSERT_LAST,
482 L"BootDrive",
483 BootDrive);
484
485 /* BootPartition= */
486 IniCacheInsertKey(IniSection,
487 NULL,
488 INSERT_LAST,
489 L"BootPartition",
490 BootPartition);
491
492 /* BootSector= */
493 IniCacheInsertKey(IniSection,
494 NULL,
495 INSERT_LAST,
496 L"BootSectorFile",
497 BootSector);
498
499 /* Save the INI file */
500 IniCacheSave(IniCache, IniPath);
501 IniCacheDestroy(IniCache);
502
503 return STATUS_SUCCESS;
504 }
505
506 static
507 NTSTATUS
508 UpdateFreeLoaderIni(
509 PWCHAR IniPath,
510 PWCHAR ArcPath)
511 {
512 NTSTATUS Status;
513 PINICACHE IniCache;
514 PINICACHESECTION IniSection;
515 PINICACHESECTION OsIniSection;
516 WCHAR SectionName[80];
517 WCHAR OsName[80];
518 WCHAR SystemPath[200];
519 WCHAR SectionName2[200];
520 PWCHAR KeyData;
521 ULONG i,j;
522
523 Status = IniCacheLoad(&IniCache, IniPath, FALSE);
524 if (!NT_SUCCESS(Status))
525 return Status;
526
527 /* Get "Operating Systems" section */
528 IniSection = IniCacheGetSection(IniCache, L"Operating Systems");
529 if (IniSection == NULL)
530 {
531 IniCacheDestroy(IniCache);
532 return STATUS_UNSUCCESSFUL;
533 }
534
535 /* Find an existing usable or an unused section name */
536 i = 1;
537 wcscpy(SectionName, L"ReactOS");
538 wcscpy(OsName, L"\"ReactOS\"");
539 while(TRUE)
540 {
541 Status = IniCacheGetKey(IniSection, SectionName, &KeyData);
542 if (!NT_SUCCESS(Status))
543 break;
544
545 /* Get operation system section */
546 if (KeyData[0] == '"')
547 {
548 wcscpy(SectionName2, &KeyData[1]);
549 j = wcslen(SectionName2);
550 if (j > 0)
551 {
552 SectionName2[j-1] = 0;
553 }
554 }
555 else
556 {
557 wcscpy(SectionName2, KeyData);
558 }
559
560 /* Search for an existing ReactOS entry */
561 OsIniSection = IniCacheGetSection(IniCache, SectionName2);
562 if (OsIniSection != NULL)
563 {
564 BOOLEAN UseExistingEntry = TRUE;
565
566 /* Check for boot type "Windows2003" */
567 Status = IniCacheGetKey(OsIniSection, L"BootType", &KeyData);
568 if (NT_SUCCESS(Status))
569 {
570 if ((KeyData == NULL) ||
571 ( (_wcsicmp(KeyData, L"Windows2003") != 0) &&
572 (_wcsicmp(KeyData, L"\"Windows2003\"") != 0) ))
573 {
574 /* This is not a ReactOS entry */
575 UseExistingEntry = FALSE;
576 }
577 }
578 else
579 {
580 UseExistingEntry = FALSE;
581 }
582
583 if (UseExistingEntry)
584 {
585 /* BootType is Windows2003. Now check SystemPath. */
586 Status = IniCacheGetKey(OsIniSection, L"SystemPath", &KeyData);
587 if (NT_SUCCESS(Status))
588 {
589 swprintf(SystemPath, L"\"%s\"", ArcPath);
590 if ((KeyData == NULL) ||
591 ( (_wcsicmp(KeyData, ArcPath) != 0) &&
592 (_wcsicmp(KeyData, SystemPath) != 0) ))
593 {
594 /* This entry is a ReactOS entry, but the SystemRoot
595 does not match the one we are looking for. */
596 UseExistingEntry = FALSE;
597 }
598 }
599 else
600 {
601 UseExistingEntry = FALSE;
602 }
603 }
604
605 if (UseExistingEntry)
606 {
607 IniCacheDestroy(IniCache);
608 return STATUS_SUCCESS;
609 }
610 }
611
612 swprintf(SectionName, L"ReactOS_%lu", i);
613 swprintf(OsName, L"\"ReactOS %lu\"", i);
614 i++;
615 }
616
617 /* Create a new "ReactOS" entry */
618 CreateNTOSEntry(IniCache, IniSection,
619 SectionName, OsName,
620 L"Windows2003", ArcPath,
621 L"");
622
623 IniCacheSave(IniCache, IniPath);
624 IniCacheDestroy(IniCache);
625
626 return STATUS_SUCCESS;
627 }
628
629 static
630 BOOLEAN
631 IsThereAValidBootSector(PWSTR RootPath)
632 {
633 /*
634 * Check the first DWORD (4 bytes) of the bootsector for a potential
635 * "valid" instruction (the BIOS starts execution of the bootsector
636 * at its beginning). Currently the criterium is that this DWORD must
637 * be non-zero.
638 */
639
640 NTSTATUS Status;
641 UNICODE_STRING Name;
642 OBJECT_ATTRIBUTES ObjectAttributes;
643 IO_STATUS_BLOCK IoStatusBlock;
644 HANDLE FileHandle;
645 LARGE_INTEGER FileOffset;
646 PUCHAR BootSector;
647 ULONG Instruction;
648
649 /* Allocate buffer for bootsector */
650 BootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
651 if (BootSector == NULL)
652 return FALSE; // STATUS_INSUFFICIENT_RESOURCES;
653
654 /* Read current boot sector into buffer */
655 RtlInitUnicodeString(&Name, RootPath);
656
657 InitializeObjectAttributes(&ObjectAttributes,
658 &Name,
659 OBJ_CASE_INSENSITIVE,
660 NULL,
661 NULL);
662
663 Status = NtOpenFile(&FileHandle,
664 GENERIC_READ | SYNCHRONIZE,
665 &ObjectAttributes,
666 &IoStatusBlock,
667 0,
668 FILE_SYNCHRONOUS_IO_NONALERT);
669 if (!NT_SUCCESS(Status))
670 {
671 RtlFreeHeap(ProcessHeap, 0, BootSector);
672 return FALSE; // Status;
673 }
674
675 FileOffset.QuadPart = 0ULL;
676 Status = NtReadFile(FileHandle,
677 NULL,
678 NULL,
679 NULL,
680 &IoStatusBlock,
681 BootSector,
682 SECTORSIZE,
683 &FileOffset,
684 NULL);
685 NtClose(FileHandle);
686
687 Instruction = *(PULONG)BootSector;
688
689 /* Free the boot sector */
690 RtlFreeHeap(ProcessHeap, 0, BootSector);
691
692 if (!NT_SUCCESS(Status))
693 return FALSE; // Status;
694
695 return (Instruction != 0x00000000);
696 }
697
698 static
699 NTSTATUS
700 SaveCurrentBootSector(
701 PWSTR RootPath,
702 PWSTR DstPath,
703 ULONG Length)
704 {
705 NTSTATUS Status;
706 UNICODE_STRING Name;
707 OBJECT_ATTRIBUTES ObjectAttributes;
708 IO_STATUS_BLOCK IoStatusBlock;
709 HANDLE FileHandle;
710 LARGE_INTEGER FileOffset;
711 PUCHAR BootSector;
712
713 /* Allocate buffer for bootsector */
714 BootSector = RtlAllocateHeap(ProcessHeap, 0, Length);
715 if (BootSector == NULL)
716 return STATUS_INSUFFICIENT_RESOURCES;
717
718 /* Read current boot sector into buffer */
719 RtlInitUnicodeString(&Name, RootPath);
720
721 InitializeObjectAttributes(&ObjectAttributes,
722 &Name,
723 OBJ_CASE_INSENSITIVE,
724 NULL,
725 NULL);
726
727 Status = NtOpenFile(&FileHandle,
728 GENERIC_READ | SYNCHRONIZE,
729 &ObjectAttributes,
730 &IoStatusBlock,
731 0,
732 FILE_SYNCHRONOUS_IO_NONALERT);
733 if (!NT_SUCCESS(Status))
734 {
735 RtlFreeHeap(ProcessHeap, 0, BootSector);
736 return Status;
737 }
738
739 FileOffset.QuadPart = 0ULL;
740 Status = NtReadFile(FileHandle,
741 NULL,
742 NULL,
743 NULL,
744 &IoStatusBlock,
745 BootSector,
746 Length,
747 &FileOffset,
748 NULL);
749 NtClose(FileHandle);
750 if (!NT_SUCCESS(Status))
751 {
752 RtlFreeHeap(ProcessHeap, 0, BootSector);
753 return Status;
754 }
755
756 /* Write bootsector to DstPath */
757 RtlInitUnicodeString(&Name, DstPath);
758
759 InitializeObjectAttributes(&ObjectAttributes,
760 &Name,
761 0,
762 NULL,
763 NULL);
764
765 Status = NtCreateFile(&FileHandle,
766 GENERIC_WRITE | SYNCHRONIZE,
767 &ObjectAttributes,
768 &IoStatusBlock,
769 NULL,
770 FILE_ATTRIBUTE_NORMAL,
771 0,
772 FILE_SUPERSEDE,
773 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
774 NULL,
775 0);
776 if (!NT_SUCCESS(Status))
777 {
778 RtlFreeHeap(ProcessHeap, 0, BootSector);
779 return Status;
780 }
781
782 Status = NtWriteFile(FileHandle,
783 NULL,
784 NULL,
785 NULL,
786 &IoStatusBlock,
787 BootSector,
788 Length,
789 NULL,
790 NULL);
791 NtClose(FileHandle);
792
793 /* Free the boot sector */
794 RtlFreeHeap(ProcessHeap, 0, BootSector);
795
796 return Status;
797 }
798
799 static
800 NTSTATUS
801 InstallFat16BootCodeToFile(
802 PWSTR SrcPath,
803 PWSTR DstPath,
804 PWSTR RootPath)
805 {
806 NTSTATUS Status;
807 UNICODE_STRING Name;
808 OBJECT_ATTRIBUTES ObjectAttributes;
809 IO_STATUS_BLOCK IoStatusBlock;
810 HANDLE FileHandle;
811 LARGE_INTEGER FileOffset;
812 PFAT_BOOTSECTOR OrigBootSector;
813 PFAT_BOOTSECTOR NewBootSector;
814
815 /* Allocate buffer for original bootsector */
816 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
817 if (OrigBootSector == NULL)
818 return STATUS_INSUFFICIENT_RESOURCES;
819
820 /* Read current boot sector into buffer */
821 RtlInitUnicodeString(&Name, RootPath);
822
823 InitializeObjectAttributes(&ObjectAttributes,
824 &Name,
825 OBJ_CASE_INSENSITIVE,
826 NULL,
827 NULL);
828
829 Status = NtOpenFile(&FileHandle,
830 GENERIC_READ | SYNCHRONIZE,
831 &ObjectAttributes,
832 &IoStatusBlock,
833 0,
834 FILE_SYNCHRONOUS_IO_NONALERT);
835 if (!NT_SUCCESS(Status))
836 {
837 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
838 return Status;
839 }
840
841 FileOffset.QuadPart = 0ULL;
842 Status = NtReadFile(FileHandle,
843 NULL,
844 NULL,
845 NULL,
846 &IoStatusBlock,
847 OrigBootSector,
848 SECTORSIZE,
849 &FileOffset,
850 NULL);
851 NtClose(FileHandle);
852 if (!NT_SUCCESS(Status))
853 {
854 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
855 return Status;
856 }
857
858 /* Allocate buffer for new bootsector */
859 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
860 if (NewBootSector == NULL)
861 {
862 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
863 return STATUS_INSUFFICIENT_RESOURCES;
864 }
865
866 /* Read new bootsector from SrcPath */
867 RtlInitUnicodeString(&Name, SrcPath);
868
869 InitializeObjectAttributes(&ObjectAttributes,
870 &Name,
871 OBJ_CASE_INSENSITIVE,
872 NULL,
873 NULL);
874
875 Status = NtOpenFile(&FileHandle,
876 GENERIC_READ | SYNCHRONIZE,
877 &ObjectAttributes,
878 &IoStatusBlock,
879 0,
880 FILE_SYNCHRONOUS_IO_NONALERT);
881 if (!NT_SUCCESS(Status))
882 {
883 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
884 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
885 return Status;
886 }
887
888 FileOffset.QuadPart = 0ULL;
889 Status = NtReadFile(FileHandle,
890 NULL,
891 NULL,
892 NULL,
893 &IoStatusBlock,
894 NewBootSector,
895 SECTORSIZE,
896 &FileOffset,
897 NULL);
898 NtClose(FileHandle);
899 if (!NT_SUCCESS(Status))
900 {
901 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
902 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
903 return Status;
904 }
905
906 /* Adjust bootsector (copy a part of the FAT BPB) */
907 memcpy(&NewBootSector->OemName,
908 &OrigBootSector->OemName,
909 FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
910 FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
911
912 /* Free the original boot sector */
913 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
914
915 /* Write new bootsector to DstPath */
916 RtlInitUnicodeString(&Name, DstPath);
917
918 InitializeObjectAttributes(&ObjectAttributes,
919 &Name,
920 0,
921 NULL,
922 NULL);
923
924 Status = NtCreateFile(&FileHandle,
925 GENERIC_WRITE | SYNCHRONIZE,
926 &ObjectAttributes,
927 &IoStatusBlock,
928 NULL,
929 FILE_ATTRIBUTE_NORMAL,
930 0,
931 FILE_OVERWRITE_IF,
932 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
933 NULL,
934 0);
935 if (!NT_SUCCESS(Status))
936 {
937 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
938 return Status;
939 }
940
941 FileOffset.QuadPart = 0ULL;
942 Status = NtWriteFile(FileHandle,
943 NULL,
944 NULL,
945 NULL,
946 &IoStatusBlock,
947 NewBootSector,
948 SECTORSIZE,
949 NULL,
950 NULL);
951 NtClose(FileHandle);
952
953 /* Free the new boot sector */
954 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
955
956 return Status;
957 }
958
959 static
960 NTSTATUS
961 InstallFat32BootCodeToFile(
962 PWSTR SrcPath,
963 PWSTR DstPath,
964 PWSTR RootPath)
965 {
966 NTSTATUS Status;
967 UNICODE_STRING Name;
968 OBJECT_ATTRIBUTES ObjectAttributes;
969 IO_STATUS_BLOCK IoStatusBlock;
970 HANDLE FileHandle;
971 LARGE_INTEGER FileOffset;
972 PFAT32_BOOTSECTOR OrigBootSector;
973 PFAT32_BOOTSECTOR NewBootSector;
974
975 /* Allocate buffer for original bootsector */
976 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
977 if (OrigBootSector == NULL)
978 return STATUS_INSUFFICIENT_RESOURCES;
979
980 /* Read current boot sector into buffer */
981 RtlInitUnicodeString(&Name, RootPath);
982
983 InitializeObjectAttributes(&ObjectAttributes,
984 &Name,
985 OBJ_CASE_INSENSITIVE,
986 NULL,
987 NULL);
988
989 Status = NtOpenFile(&FileHandle,
990 GENERIC_READ | SYNCHRONIZE,
991 &ObjectAttributes,
992 &IoStatusBlock,
993 0,
994 FILE_SYNCHRONOUS_IO_NONALERT);
995 if (!NT_SUCCESS(Status))
996 {
997 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
998 return Status;
999 }
1000
1001 FileOffset.QuadPart = 0ULL;
1002 Status = NtReadFile(FileHandle,
1003 NULL,
1004 NULL,
1005 NULL,
1006 &IoStatusBlock,
1007 OrigBootSector,
1008 SECTORSIZE,
1009 NULL,
1010 NULL);
1011 NtClose(FileHandle);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1015 return Status;
1016 }
1017
1018 /* Allocate buffer for new bootsector (2 sectors) */
1019 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE);
1020 if (NewBootSector == NULL)
1021 {
1022 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1023 return STATUS_INSUFFICIENT_RESOURCES;
1024 }
1025
1026 /* Read new bootsector from SrcPath */
1027 RtlInitUnicodeString(&Name, SrcPath);
1028
1029 InitializeObjectAttributes(&ObjectAttributes,
1030 &Name,
1031 OBJ_CASE_INSENSITIVE,
1032 NULL,
1033 NULL);
1034
1035 Status = NtOpenFile(&FileHandle,
1036 GENERIC_READ | SYNCHRONIZE,
1037 &ObjectAttributes,
1038 &IoStatusBlock,
1039 0,
1040 FILE_SYNCHRONOUS_IO_NONALERT);
1041 if (!NT_SUCCESS(Status))
1042 {
1043 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1044 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1045 return Status;
1046 }
1047
1048 Status = NtReadFile(FileHandle,
1049 NULL,
1050 NULL,
1051 NULL,
1052 &IoStatusBlock,
1053 NewBootSector,
1054 2 * SECTORSIZE,
1055 NULL,
1056 NULL);
1057 NtClose(FileHandle);
1058 if (!NT_SUCCESS(Status))
1059 {
1060 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1061 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1062 return Status;
1063 }
1064
1065 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1066 memcpy(&NewBootSector->OemName,
1067 &OrigBootSector->OemName,
1068 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1069 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1070
1071 /* Disable the backup boot sector */
1072 NewBootSector->BackupBootSector = 0;
1073
1074 /* Free the original boot sector */
1075 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1076
1077 /* Write the first sector of the new bootcode to DstPath */
1078 RtlInitUnicodeString(&Name, DstPath);
1079
1080 InitializeObjectAttributes(&ObjectAttributes,
1081 &Name,
1082 0,
1083 NULL,
1084 NULL);
1085
1086 Status = NtCreateFile(&FileHandle,
1087 GENERIC_WRITE | SYNCHRONIZE,
1088 &ObjectAttributes,
1089 &IoStatusBlock,
1090 NULL,
1091 FILE_ATTRIBUTE_NORMAL,
1092 0,
1093 FILE_SUPERSEDE,
1094 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1095 NULL,
1096 0);
1097 if (!NT_SUCCESS(Status))
1098 {
1099 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1100 return Status;
1101 }
1102
1103 FileOffset.QuadPart = 0ULL;
1104 Status = NtWriteFile(FileHandle,
1105 NULL,
1106 NULL,
1107 NULL,
1108 &IoStatusBlock,
1109 NewBootSector,
1110 SECTORSIZE,
1111 NULL,
1112 NULL);
1113 NtClose(FileHandle);
1114 if (!NT_SUCCESS(Status))
1115 {
1116 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1117 return Status;
1118 }
1119
1120 /* Write the second sector of the new bootcode to boot disk sector 14 */
1121 RtlInitUnicodeString(&Name, RootPath);
1122
1123 InitializeObjectAttributes(&ObjectAttributes,
1124 &Name,
1125 0,
1126 NULL,
1127 NULL);
1128
1129 Status = NtOpenFile(&FileHandle,
1130 GENERIC_WRITE | SYNCHRONIZE,
1131 &ObjectAttributes,
1132 &IoStatusBlock,
1133 0,
1134 FILE_SYNCHRONOUS_IO_NONALERT);
1135 if (!NT_SUCCESS(Status))
1136 {
1137 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1138 return Status;
1139 }
1140
1141 FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE);
1142 Status = NtWriteFile(FileHandle,
1143 NULL,
1144 NULL,
1145 NULL,
1146 &IoStatusBlock,
1147 ((PUCHAR)NewBootSector + SECTORSIZE),
1148 SECTORSIZE,
1149 &FileOffset,
1150 NULL);
1151 if (!NT_SUCCESS(Status))
1152 {
1153 }
1154 NtClose(FileHandle);
1155
1156 /* Free the new boot sector */
1157 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1158
1159 return Status;
1160 }
1161
1162
1163 NTSTATUS
1164 InstallMbrBootCodeToDisk(
1165 PWSTR SrcPath,
1166 PWSTR RootPath)
1167 {
1168 NTSTATUS Status;
1169 UNICODE_STRING Name;
1170 OBJECT_ATTRIBUTES ObjectAttributes;
1171 IO_STATUS_BLOCK IoStatusBlock;
1172 HANDLE FileHandle;
1173 LARGE_INTEGER FileOffset;
1174 PPARTITION_SECTOR OrigBootSector;
1175 PPARTITION_SECTOR NewBootSector;
1176
1177 /* Allocate buffer for original bootsector */
1178 OrigBootSector = (PPARTITION_SECTOR)RtlAllocateHeap(ProcessHeap,
1179 0,
1180 sizeof(PARTITION_SECTOR));
1181 if (OrigBootSector == NULL)
1182 return STATUS_INSUFFICIENT_RESOURCES;
1183
1184 /* Read current boot sector into buffer */
1185 RtlInitUnicodeString(&Name,
1186 RootPath);
1187
1188 InitializeObjectAttributes(&ObjectAttributes,
1189 &Name,
1190 OBJ_CASE_INSENSITIVE,
1191 NULL,
1192 NULL);
1193
1194 Status = NtOpenFile(&FileHandle,
1195 GENERIC_READ | SYNCHRONIZE,
1196 &ObjectAttributes,
1197 &IoStatusBlock,
1198 0,
1199 FILE_SYNCHRONOUS_IO_NONALERT);
1200 if (!NT_SUCCESS(Status))
1201 {
1202 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1203 return Status;
1204 }
1205
1206 FileOffset.QuadPart = 0ULL;
1207 Status = NtReadFile(FileHandle,
1208 NULL,
1209 NULL,
1210 NULL,
1211 &IoStatusBlock,
1212 OrigBootSector,
1213 SECTORSIZE,
1214 &FileOffset,
1215 NULL);
1216 NtClose(FileHandle);
1217 if (!NT_SUCCESS(Status))
1218 {
1219 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1220 return Status;
1221 }
1222
1223 /* Allocate buffer for new bootsector */
1224 NewBootSector = (PPARTITION_SECTOR)RtlAllocateHeap(ProcessHeap,
1225 0,
1226 sizeof(PARTITION_SECTOR));
1227 if (NewBootSector == NULL)
1228 {
1229 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1230 return STATUS_INSUFFICIENT_RESOURCES;
1231 }
1232
1233 /* Read new bootsector from SrcPath */
1234 RtlInitUnicodeString(&Name, SrcPath);
1235
1236 InitializeObjectAttributes(&ObjectAttributes,
1237 &Name,
1238 OBJ_CASE_INSENSITIVE,
1239 NULL,
1240 NULL);
1241
1242 Status = NtOpenFile(&FileHandle,
1243 GENERIC_READ | SYNCHRONIZE,
1244 &ObjectAttributes,
1245 &IoStatusBlock,
1246 0,
1247 FILE_SYNCHRONOUS_IO_NONALERT);
1248 if (!NT_SUCCESS(Status))
1249 {
1250 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1251 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1252 return Status;
1253 }
1254
1255 Status = NtReadFile(FileHandle,
1256 NULL,
1257 NULL,
1258 NULL,
1259 &IoStatusBlock,
1260 NewBootSector,
1261 sizeof(PARTITION_SECTOR),
1262 NULL,
1263 NULL);
1264 NtClose(FileHandle);
1265 if (!NT_SUCCESS(Status))
1266 {
1267 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1268 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1269 return Status;
1270 }
1271
1272 /* Copy partition table from old MBR to new */
1273 RtlCopyMemory(&NewBootSector->Signature,
1274 &OrigBootSector->Signature,
1275 sizeof(PARTITION_SECTOR) - offsetof(PARTITION_SECTOR, Signature) /* Length of partition table */);
1276
1277 /* Free the original boot sector */
1278 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1279
1280 /* Write new bootsector to RootPath */
1281 RtlInitUnicodeString(&Name, RootPath);
1282
1283 InitializeObjectAttributes(&ObjectAttributes,
1284 &Name,
1285 0,
1286 NULL,
1287 NULL);
1288
1289 Status = NtOpenFile(&FileHandle,
1290 GENERIC_WRITE | SYNCHRONIZE,
1291 &ObjectAttributes,
1292 &IoStatusBlock,
1293 0,
1294 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1295 if (!NT_SUCCESS(Status))
1296 {
1297 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1298 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1299 return Status;
1300 }
1301
1302 FileOffset.QuadPart = 0ULL;
1303 Status = NtWriteFile(FileHandle,
1304 NULL,
1305 NULL,
1306 NULL,
1307 &IoStatusBlock,
1308 NewBootSector,
1309 SECTORSIZE,
1310 &FileOffset,
1311 NULL);
1312 NtClose(FileHandle);
1313
1314 /* Free the new boot sector */
1315 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1316
1317 return Status;
1318 }
1319
1320 static
1321 NTSTATUS
1322 InstallFat12BootCodeToFloppy(
1323 PWSTR SrcPath,
1324 PWSTR RootPath)
1325 {
1326 NTSTATUS Status;
1327 UNICODE_STRING Name;
1328 OBJECT_ATTRIBUTES ObjectAttributes;
1329 IO_STATUS_BLOCK IoStatusBlock;
1330 HANDLE FileHandle;
1331 LARGE_INTEGER FileOffset;
1332 PFAT_BOOTSECTOR OrigBootSector;
1333 PFAT_BOOTSECTOR NewBootSector;
1334
1335 /* Allocate buffer for original bootsector */
1336 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1337 if (OrigBootSector == NULL)
1338 return STATUS_INSUFFICIENT_RESOURCES;
1339
1340 /* Read current boot sector into buffer */
1341 RtlInitUnicodeString(&Name, RootPath);
1342
1343 InitializeObjectAttributes(&ObjectAttributes,
1344 &Name,
1345 OBJ_CASE_INSENSITIVE,
1346 NULL,
1347 NULL);
1348
1349 Status = NtOpenFile(&FileHandle,
1350 GENERIC_READ | SYNCHRONIZE,
1351 &ObjectAttributes,
1352 &IoStatusBlock,
1353 0,
1354 FILE_SYNCHRONOUS_IO_NONALERT);
1355 if (!NT_SUCCESS(Status))
1356 {
1357 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1358 return Status;
1359 }
1360
1361 FileOffset.QuadPart = 0ULL;
1362 Status = NtReadFile(FileHandle,
1363 NULL,
1364 NULL,
1365 NULL,
1366 &IoStatusBlock,
1367 OrigBootSector,
1368 SECTORSIZE,
1369 &FileOffset,
1370 NULL);
1371 NtClose(FileHandle);
1372 if (!NT_SUCCESS(Status))
1373 {
1374 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1375 return Status;
1376 }
1377
1378 /* Allocate buffer for new bootsector */
1379 NewBootSector = RtlAllocateHeap(ProcessHeap,
1380 0,
1381 SECTORSIZE);
1382 if (NewBootSector == NULL)
1383 {
1384 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1385 return STATUS_INSUFFICIENT_RESOURCES;
1386 }
1387
1388 /* Read new bootsector from SrcPath */
1389 RtlInitUnicodeString(&Name, SrcPath);
1390
1391 InitializeObjectAttributes(&ObjectAttributes,
1392 &Name,
1393 OBJ_CASE_INSENSITIVE,
1394 NULL,
1395 NULL);
1396
1397 Status = NtOpenFile(&FileHandle,
1398 GENERIC_READ | SYNCHRONIZE,
1399 &ObjectAttributes,
1400 &IoStatusBlock,
1401 0,
1402 FILE_SYNCHRONOUS_IO_NONALERT);
1403 if (!NT_SUCCESS(Status))
1404 {
1405 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1406 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1407 return Status;
1408 }
1409
1410 Status = NtReadFile(FileHandle,
1411 NULL,
1412 NULL,
1413 NULL,
1414 &IoStatusBlock,
1415 NewBootSector,
1416 SECTORSIZE,
1417 NULL,
1418 NULL);
1419 NtClose(FileHandle);
1420 if (!NT_SUCCESS(Status))
1421 {
1422 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1423 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1424 return Status;
1425 }
1426
1427 /* Adjust bootsector (copy a part of the FAT16 BPB) */
1428 memcpy(&NewBootSector->OemName,
1429 &OrigBootSector->OemName,
1430 FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
1431 FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
1432
1433 /* Free the original boot sector */
1434 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1435
1436 /* Write new bootsector to RootPath */
1437 RtlInitUnicodeString(&Name, RootPath);
1438
1439 InitializeObjectAttributes(&ObjectAttributes,
1440 &Name,
1441 0,
1442 NULL,
1443 NULL);
1444
1445 Status = NtOpenFile(&FileHandle,
1446 GENERIC_WRITE | SYNCHRONIZE,
1447 &ObjectAttributes,
1448 &IoStatusBlock,
1449 0,
1450 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1451 if (!NT_SUCCESS(Status))
1452 {
1453 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1454 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1455 return Status;
1456 }
1457
1458 FileOffset.QuadPart = 0ULL;
1459 Status = NtWriteFile(FileHandle,
1460 NULL,
1461 NULL,
1462 NULL,
1463 &IoStatusBlock,
1464 NewBootSector,
1465 SECTORSIZE,
1466 &FileOffset,
1467 NULL);
1468 NtClose(FileHandle);
1469
1470 /* Free the new boot sector */
1471 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1472
1473 return Status;
1474 }
1475
1476 static
1477 NTSTATUS
1478 InstallFat16BootCodeToDisk(
1479 PWSTR SrcPath,
1480 PWSTR RootPath)
1481 {
1482 NTSTATUS Status;
1483 UNICODE_STRING Name;
1484 OBJECT_ATTRIBUTES ObjectAttributes;
1485 IO_STATUS_BLOCK IoStatusBlock;
1486 HANDLE FileHandle;
1487 LARGE_INTEGER FileOffset;
1488 PFAT_BOOTSECTOR OrigBootSector;
1489 PFAT_BOOTSECTOR NewBootSector;
1490
1491 /* Allocate buffer for original bootsector */
1492 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1493 if (OrigBootSector == NULL)
1494 return STATUS_INSUFFICIENT_RESOURCES;
1495
1496 /* Read current boot sector into buffer */
1497 RtlInitUnicodeString(&Name, RootPath);
1498
1499 InitializeObjectAttributes(&ObjectAttributes,
1500 &Name,
1501 OBJ_CASE_INSENSITIVE,
1502 NULL,
1503 NULL);
1504
1505 Status = NtOpenFile(&FileHandle,
1506 GENERIC_READ | SYNCHRONIZE,
1507 &ObjectAttributes,
1508 &IoStatusBlock,
1509 0,
1510 FILE_SYNCHRONOUS_IO_NONALERT);
1511 if (!NT_SUCCESS(Status))
1512 {
1513 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1514 return Status;
1515 }
1516
1517 FileOffset.QuadPart = 0ULL;
1518 Status = NtReadFile(FileHandle,
1519 NULL,
1520 NULL,
1521 NULL,
1522 &IoStatusBlock,
1523 OrigBootSector,
1524 SECTORSIZE,
1525 &FileOffset,
1526 NULL);
1527 NtClose(FileHandle);
1528 if (!NT_SUCCESS(Status))
1529 {
1530 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1531 return Status;
1532 }
1533
1534 /* Allocate buffer for new bootsector */
1535 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1536 if (NewBootSector == NULL)
1537 {
1538 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1539 return STATUS_INSUFFICIENT_RESOURCES;
1540 }
1541
1542 /* Read new bootsector from SrcPath */
1543 RtlInitUnicodeString(&Name, SrcPath);
1544
1545 InitializeObjectAttributes(&ObjectAttributes,
1546 &Name,
1547 OBJ_CASE_INSENSITIVE,
1548 NULL,
1549 NULL);
1550
1551 Status = NtOpenFile(&FileHandle,
1552 GENERIC_READ | SYNCHRONIZE,
1553 &ObjectAttributes,
1554 &IoStatusBlock,
1555 0,
1556 FILE_SYNCHRONOUS_IO_NONALERT);
1557 if (!NT_SUCCESS(Status))
1558 {
1559 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1560 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1561 return Status;
1562 }
1563
1564 Status = NtReadFile(FileHandle,
1565 NULL,
1566 NULL,
1567 NULL,
1568 &IoStatusBlock,
1569 NewBootSector,
1570 SECTORSIZE,
1571 NULL,
1572 NULL);
1573 NtClose(FileHandle);
1574 if (!NT_SUCCESS(Status))
1575 {
1576 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1577 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1578 return Status;
1579 }
1580
1581 /* Adjust bootsector (copy a part of the FAT16 BPB) */
1582 memcpy(&NewBootSector->OemName,
1583 &OrigBootSector->OemName,
1584 FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
1585 FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
1586
1587 NewBootSector->HiddenSectors = PartitionList->CurrentDisk->SectorsPerTrack;
1588
1589 /* Free the original boot sector */
1590 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1591
1592 /* Write new bootsector to RootPath */
1593 RtlInitUnicodeString(&Name, RootPath);
1594
1595 InitializeObjectAttributes(&ObjectAttributes,
1596 &Name,
1597 0,
1598 NULL,
1599 NULL);
1600
1601 Status = NtOpenFile(&FileHandle,
1602 GENERIC_WRITE | SYNCHRONIZE,
1603 &ObjectAttributes,
1604 &IoStatusBlock,
1605 0,
1606 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1607 if (!NT_SUCCESS(Status))
1608 {
1609 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1610 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1611 return Status;
1612 }
1613
1614 FileOffset.QuadPart = 0ULL;
1615 Status = NtWriteFile(FileHandle,
1616 NULL,
1617 NULL,
1618 NULL,
1619 &IoStatusBlock,
1620 NewBootSector,
1621 SECTORSIZE,
1622 &FileOffset,
1623 NULL);
1624 NtClose(FileHandle);
1625
1626 /* Free the new boot sector */
1627 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1628
1629 return Status;
1630 }
1631
1632 static
1633 NTSTATUS
1634 InstallFat32BootCodeToDisk(
1635 PWSTR SrcPath,
1636 PWSTR RootPath)
1637 {
1638 NTSTATUS Status;
1639 UNICODE_STRING Name;
1640 OBJECT_ATTRIBUTES ObjectAttributes;
1641 IO_STATUS_BLOCK IoStatusBlock;
1642 HANDLE FileHandle;
1643 LARGE_INTEGER FileOffset;
1644 PFAT32_BOOTSECTOR OrigBootSector;
1645 PFAT32_BOOTSECTOR NewBootSector;
1646 USHORT BackupBootSector;
1647
1648 /* Allocate buffer for original bootsector */
1649 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1650 if (OrigBootSector == NULL)
1651 return STATUS_INSUFFICIENT_RESOURCES;
1652
1653 /* Read current boot sector into buffer */
1654 RtlInitUnicodeString(&Name, RootPath);
1655
1656 InitializeObjectAttributes(&ObjectAttributes,
1657 &Name,
1658 OBJ_CASE_INSENSITIVE,
1659 NULL,
1660 NULL);
1661
1662 Status = NtOpenFile(&FileHandle,
1663 GENERIC_READ | SYNCHRONIZE,
1664 &ObjectAttributes,
1665 &IoStatusBlock,
1666 0,
1667 FILE_SYNCHRONOUS_IO_NONALERT);
1668 if (!NT_SUCCESS(Status))
1669 {
1670 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1671 return Status;
1672 }
1673
1674 FileOffset.QuadPart = 0ULL;
1675 Status = NtReadFile(FileHandle,
1676 NULL,
1677 NULL,
1678 NULL,
1679 &IoStatusBlock,
1680 OrigBootSector,
1681 SECTORSIZE,
1682 &FileOffset,
1683 NULL);
1684 NtClose(FileHandle);
1685 if (!NT_SUCCESS(Status))
1686 {
1687 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1688 return Status;
1689 }
1690
1691
1692 /* Allocate buffer for new bootsector (2 sectors) */
1693 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE);
1694 if (NewBootSector == NULL)
1695 {
1696 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1697 return STATUS_INSUFFICIENT_RESOURCES;
1698 }
1699
1700 /* Read new bootsector from SrcPath */
1701 RtlInitUnicodeString(&Name, SrcPath);
1702
1703 InitializeObjectAttributes(&ObjectAttributes,
1704 &Name,
1705 OBJ_CASE_INSENSITIVE,
1706 NULL,
1707 NULL);
1708
1709 Status = NtOpenFile(&FileHandle,
1710 GENERIC_READ | SYNCHRONIZE,
1711 &ObjectAttributes,
1712 &IoStatusBlock,
1713 0,
1714 FILE_SYNCHRONOUS_IO_NONALERT);
1715 if (!NT_SUCCESS(Status))
1716 {
1717 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1718 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1719 return Status;
1720 }
1721
1722 Status = NtReadFile(FileHandle,
1723 NULL,
1724 NULL,
1725 NULL,
1726 &IoStatusBlock,
1727 NewBootSector,
1728 2 * SECTORSIZE,
1729 NULL,
1730 NULL);
1731 NtClose(FileHandle);
1732 if (!NT_SUCCESS(Status))
1733 {
1734 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1735 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1736 return Status;
1737 }
1738
1739 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1740 memcpy(&NewBootSector->OemName,
1741 &OrigBootSector->OemName,
1742 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1743 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1744
1745 NewBootSector->HiddenSectors = PartitionList->CurrentDisk->SectorsPerTrack;
1746
1747 /* Get the location of the backup boot sector */
1748 BackupBootSector = OrigBootSector->BackupBootSector;
1749
1750 /* Free the original boot sector */
1751 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1752
1753 /* Write the first sector of the new bootcode to DstPath */
1754 RtlInitUnicodeString(&Name, RootPath);
1755
1756 InitializeObjectAttributes(&ObjectAttributes,
1757 &Name,
1758 0,
1759 NULL,
1760 NULL);
1761
1762 Status = NtOpenFile(&FileHandle,
1763 GENERIC_WRITE | SYNCHRONIZE,
1764 &ObjectAttributes,
1765 &IoStatusBlock,
1766 0,
1767 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1768 if (!NT_SUCCESS(Status))
1769 {
1770 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1771 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1772 return Status;
1773 }
1774
1775 /* Write sector 0 */
1776 FileOffset.QuadPart = 0ULL;
1777 Status = NtWriteFile(FileHandle,
1778 NULL,
1779 NULL,
1780 NULL,
1781 &IoStatusBlock,
1782 NewBootSector,
1783 SECTORSIZE,
1784 &FileOffset,
1785 NULL);
1786 if (!NT_SUCCESS(Status))
1787 {
1788 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1789 NtClose(FileHandle);
1790 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1791 return Status;
1792 }
1793
1794 /* Write backup boot sector */
1795 if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1796 {
1797 FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1798 Status = NtWriteFile(FileHandle,
1799 NULL,
1800 NULL,
1801 NULL,
1802 &IoStatusBlock,
1803 NewBootSector,
1804 SECTORSIZE,
1805 &FileOffset,
1806 NULL);
1807 if (!NT_SUCCESS(Status))
1808 {
1809 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1810 NtClose(FileHandle);
1811 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1812 return Status;
1813 }
1814 }
1815
1816 /* Write sector 14 */
1817 FileOffset.QuadPart = 14 * SECTORSIZE;
1818 Status = NtWriteFile(FileHandle,
1819 NULL,
1820 NULL,
1821 NULL,
1822 &IoStatusBlock,
1823 ((PUCHAR)NewBootSector + SECTORSIZE),
1824 SECTORSIZE,
1825 &FileOffset,
1826 NULL);
1827 if (!NT_SUCCESS(Status))
1828 {
1829 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1830 }
1831 NtClose(FileHandle);
1832
1833 /* Free the new boot sector */
1834 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1835
1836 return Status;
1837 }
1838
1839 static
1840 NTSTATUS
1841 InstallExt2BootCodeToDisk(
1842 PWSTR SrcPath,
1843 PWSTR RootPath)
1844 {
1845 NTSTATUS Status;
1846 UNICODE_STRING Name;
1847 OBJECT_ATTRIBUTES ObjectAttributes;
1848 IO_STATUS_BLOCK IoStatusBlock;
1849 HANDLE FileHandle;
1850 LARGE_INTEGER FileOffset;
1851 // PEXT2_BOOTSECTOR OrigBootSector;
1852 PEXT2_BOOTSECTOR NewBootSector;
1853 // USHORT BackupBootSector;
1854
1855 #if 0
1856 /* Allocate buffer for original bootsector */
1857 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1858 if (OrigBootSector == NULL)
1859 return STATUS_INSUFFICIENT_RESOURCES;
1860
1861 /* Read current boot sector into buffer */
1862 RtlInitUnicodeString(&Name, RootPath);
1863
1864 InitializeObjectAttributes(&ObjectAttributes,
1865 &Name,
1866 OBJ_CASE_INSENSITIVE,
1867 NULL,
1868 NULL);
1869
1870 Status = NtOpenFile(&FileHandle,
1871 GENERIC_READ | SYNCHRONIZE,
1872 &ObjectAttributes,
1873 &IoStatusBlock,
1874 0,
1875 FILE_SYNCHRONOUS_IO_NONALERT);
1876 if (!NT_SUCCESS(Status))
1877 {
1878 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1879 return Status;
1880 }
1881
1882 FileOffset.QuadPart = 0ULL;
1883 Status = NtReadFile(FileHandle,
1884 NULL,
1885 NULL,
1886 NULL,
1887 &IoStatusBlock,
1888 OrigBootSector,
1889 SECTORSIZE,
1890 &FileOffset,
1891 NULL);
1892 NtClose(FileHandle);
1893 if (!NT_SUCCESS(Status))
1894 {
1895 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1896 return Status;
1897 }
1898 #endif
1899
1900 /* Allocate buffer for new bootsector */
1901 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(EXT2_BOOTSECTOR));
1902 if (NewBootSector == NULL)
1903 {
1904 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1905 return STATUS_INSUFFICIENT_RESOURCES;
1906 }
1907
1908 /* Read new bootsector from SrcPath */
1909 RtlInitUnicodeString(&Name, SrcPath);
1910
1911 InitializeObjectAttributes(&ObjectAttributes,
1912 &Name,
1913 OBJ_CASE_INSENSITIVE,
1914 NULL,
1915 NULL);
1916
1917 Status = NtOpenFile(&FileHandle,
1918 GENERIC_READ | SYNCHRONIZE,
1919 &ObjectAttributes,
1920 &IoStatusBlock,
1921 0,
1922 FILE_SYNCHRONOUS_IO_NONALERT);
1923 if (!NT_SUCCESS(Status))
1924 {
1925 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1926 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1927 return Status;
1928 }
1929
1930 Status = NtReadFile(FileHandle,
1931 NULL,
1932 NULL,
1933 NULL,
1934 &IoStatusBlock,
1935 NewBootSector,
1936 sizeof(EXT2_BOOTSECTOR),
1937 NULL,
1938 NULL);
1939 NtClose(FileHandle);
1940 if (!NT_SUCCESS(Status))
1941 {
1942 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1943 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1944 return Status;
1945 }
1946
1947 #if 0
1948 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1949 memcpy(&NewBootSector->OemName,
1950 &OrigBootSector->OemName,
1951 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1952 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1953
1954 NewBootSector->HiddenSectors = PartitionList->CurrentDisk->SectorsPerTrack;
1955
1956 /* Get the location of the backup boot sector */
1957 BackupBootSector = OrigBootSector->BackupBootSector;
1958
1959 /* Free the original boot sector */
1960 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1961 #endif
1962
1963 /* Write new bootsector to RootPath */
1964 RtlInitUnicodeString(&Name, RootPath);
1965
1966 InitializeObjectAttributes(&ObjectAttributes,
1967 &Name,
1968 0,
1969 NULL,
1970 NULL);
1971
1972 Status = NtOpenFile(&FileHandle,
1973 GENERIC_WRITE | SYNCHRONIZE,
1974 &ObjectAttributes,
1975 &IoStatusBlock,
1976 0,
1977 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1978 if (!NT_SUCCESS(Status))
1979 {
1980 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1981 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1982 return Status;
1983 }
1984
1985 /* Write sector 0 */
1986 FileOffset.QuadPart = 0ULL;
1987 Status = NtWriteFile(FileHandle,
1988 NULL,
1989 NULL,
1990 NULL,
1991 &IoStatusBlock,
1992 NewBootSector,
1993 sizeof(EXT2_BOOTSECTOR),
1994 &FileOffset,
1995 NULL);
1996 #if 0
1997 if (!NT_SUCCESS(Status))
1998 {
1999 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
2000 NtClose(FileHandle);
2001 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
2002 return Status;
2003 }
2004
2005 /* Write backup boot sector */
2006 if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
2007 {
2008 FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
2009 Status = NtWriteFile(FileHandle,
2010 NULL,
2011 NULL,
2012 NULL,
2013 &IoStatusBlock,
2014 NewBootSector,
2015 SECTORSIZE,
2016 &FileOffset,
2017 NULL);
2018 if (!NT_SUCCESS(Status))
2019 {
2020 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
2021 NtClose(FileHandle);
2022 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
2023 return Status;
2024 }
2025 }
2026
2027 /* Write sector 14 */
2028 FileOffset.QuadPart = 14 * SECTORSIZE;
2029 Status = NtWriteFile(FileHandle,
2030 NULL,
2031 NULL,
2032 NULL,
2033 &IoStatusBlock,
2034 ((PUCHAR)NewBootSector + SECTORSIZE),
2035 SECTORSIZE,
2036 &FileOffset,
2037 NULL);
2038 if (!NT_SUCCESS(Status))
2039 {
2040 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
2041 }
2042 #endif
2043 NtClose(FileHandle);
2044
2045 /* Free the new boot sector */
2046 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
2047
2048 return Status;
2049 }
2050
2051 static
2052 NTSTATUS
2053 UnprotectBootIni(
2054 PWSTR FileName,
2055 PULONG Attributes)
2056 {
2057 NTSTATUS Status;
2058 UNICODE_STRING Name;
2059 OBJECT_ATTRIBUTES ObjectAttributes;
2060 IO_STATUS_BLOCK IoStatusBlock;
2061 FILE_BASIC_INFORMATION FileInfo;
2062 HANDLE FileHandle;
2063
2064 RtlInitUnicodeString(&Name, FileName);
2065
2066 InitializeObjectAttributes(&ObjectAttributes,
2067 &Name,
2068 OBJ_CASE_INSENSITIVE,
2069 NULL,
2070 NULL);
2071
2072 Status = NtOpenFile(&FileHandle,
2073 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2074 &ObjectAttributes,
2075 &IoStatusBlock,
2076 0,
2077 FILE_SYNCHRONOUS_IO_NONALERT);
2078 if (Status == STATUS_NO_SUCH_FILE)
2079 {
2080 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2081 *Attributes = 0;
2082 return STATUS_SUCCESS;
2083 }
2084 if (!NT_SUCCESS(Status))
2085 {
2086 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2087 return Status;
2088 }
2089
2090 Status = NtQueryInformationFile(FileHandle,
2091 &IoStatusBlock,
2092 &FileInfo,
2093 sizeof(FILE_BASIC_INFORMATION),
2094 FileBasicInformation);
2095 if (!NT_SUCCESS(Status))
2096 {
2097 DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
2098 NtClose(FileHandle);
2099 return Status;
2100 }
2101
2102 *Attributes = FileInfo.FileAttributes;
2103
2104 /* Delete attributes SYSTEM, HIDDEN and READONLY */
2105 FileInfo.FileAttributes = FileInfo.FileAttributes &
2106 ~(FILE_ATTRIBUTE_SYSTEM |
2107 FILE_ATTRIBUTE_HIDDEN |
2108 FILE_ATTRIBUTE_READONLY);
2109
2110 Status = NtSetInformationFile(FileHandle,
2111 &IoStatusBlock,
2112 &FileInfo,
2113 sizeof(FILE_BASIC_INFORMATION),
2114 FileBasicInformation);
2115 if (!NT_SUCCESS(Status))
2116 {
2117 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
2118 }
2119
2120 NtClose(FileHandle);
2121 return Status;
2122 }
2123
2124 static
2125 NTSTATUS
2126 ProtectBootIni(
2127 PWSTR FileName,
2128 ULONG Attributes)
2129 {
2130 NTSTATUS Status;
2131 UNICODE_STRING Name;
2132 OBJECT_ATTRIBUTES ObjectAttributes;
2133 IO_STATUS_BLOCK IoStatusBlock;
2134 FILE_BASIC_INFORMATION FileInfo;
2135 HANDLE FileHandle;
2136
2137 RtlInitUnicodeString(&Name, FileName);
2138
2139 InitializeObjectAttributes(&ObjectAttributes,
2140 &Name,
2141 OBJ_CASE_INSENSITIVE,
2142 NULL,
2143 NULL);
2144
2145 Status = NtOpenFile(&FileHandle,
2146 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2147 &ObjectAttributes,
2148 &IoStatusBlock,
2149 0,
2150 FILE_SYNCHRONOUS_IO_NONALERT);
2151 if (!NT_SUCCESS(Status))
2152 {
2153 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2154 return Status;
2155 }
2156
2157 Status = NtQueryInformationFile(FileHandle,
2158 &IoStatusBlock,
2159 &FileInfo,
2160 sizeof(FILE_BASIC_INFORMATION),
2161 FileBasicInformation);
2162 if (!NT_SUCCESS(Status))
2163 {
2164 DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
2165 NtClose(FileHandle);
2166 return Status;
2167 }
2168
2169 FileInfo.FileAttributes = FileInfo.FileAttributes | Attributes;
2170
2171 Status = NtSetInformationFile(FileHandle,
2172 &IoStatusBlock,
2173 &FileInfo,
2174 sizeof(FILE_BASIC_INFORMATION),
2175 FileBasicInformation);
2176 if (!NT_SUCCESS(Status))
2177 {
2178 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
2179 }
2180
2181 NtClose(FileHandle);
2182 return Status;
2183 }
2184
2185 static
2186 NTSTATUS
2187 UpdateBootIni(
2188 PWSTR BootIniPath,
2189 PWSTR EntryName,
2190 PWSTR EntryValue)
2191 {
2192 NTSTATUS Status;
2193 PINICACHE Cache = NULL;
2194 PINICACHESECTION Section = NULL;
2195 ULONG FileAttribute;
2196 PWCHAR OldValue = NULL;
2197
2198 Status = IniCacheLoad(&Cache, BootIniPath, FALSE);
2199 if (!NT_SUCCESS(Status))
2200 {
2201 return Status;
2202 }
2203
2204 Section = IniCacheGetSection(Cache,
2205 L"operating systems");
2206 if (Section == NULL)
2207 {
2208 IniCacheDestroy(Cache);
2209 return STATUS_UNSUCCESSFUL;
2210 }
2211
2212 /* Check - maybe record already exists */
2213 Status = IniCacheGetKey(Section, EntryName, &OldValue);
2214
2215 /* If either key was not found, or contains something else - add new one */
2216 if (!NT_SUCCESS(Status) || wcscmp(OldValue, EntryValue))
2217 {
2218 IniCacheInsertKey(Section,
2219 NULL,
2220 INSERT_LAST,
2221 EntryName,
2222 EntryValue);
2223 }
2224
2225 Status = UnprotectBootIni(BootIniPath,
2226 &FileAttribute);
2227 if (!NT_SUCCESS(Status))
2228 {
2229 IniCacheDestroy(Cache);
2230 return Status;
2231 }
2232
2233 Status = IniCacheSave(Cache, BootIniPath);
2234 if (!NT_SUCCESS(Status))
2235 {
2236 IniCacheDestroy(Cache);
2237 return Status;
2238 }
2239
2240 FileAttribute |= (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
2241 Status = ProtectBootIni(BootIniPath, FileAttribute);
2242
2243 IniCacheDestroy(Cache);
2244
2245 return Status;
2246 }
2247
2248 static
2249 NTSTATUS
2250 InstallFatBootcodeToPartition(
2251 PUNICODE_STRING SystemRootPath,
2252 PUNICODE_STRING SourceRootPath,
2253 PUNICODE_STRING DestinationArcPath,
2254 UCHAR PartitionType)
2255 {
2256 #ifdef __REACTOS__
2257 NTSTATUS Status;
2258 BOOLEAN DoesFreeLdrExist;
2259 WCHAR SrcPath[MAX_PATH];
2260 WCHAR DstPath[MAX_PATH];
2261
2262 /* FAT or FAT32 partition */
2263 DPRINT("System path: '%wZ'\n", SystemRootPath);
2264
2265 /* Copy FreeLoader to the system partition */
2266 wcscpy(SrcPath, SourceRootPath->Buffer);
2267 wcscat(SrcPath, L"\\loader\\freeldr.sys");
2268 wcscpy(DstPath, SystemRootPath->Buffer);
2269 wcscat(DstPath, L"\\freeldr.sys");
2270
2271 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2272 Status = SetupCopyFile(SrcPath, DstPath);
2273 if (!NT_SUCCESS(Status))
2274 {
2275 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2276 return Status;
2277 }
2278
2279 /* Prepare for possibly copying 'freeldr.ini' */
2280 wcscpy(DstPath, SystemRootPath->Buffer);
2281 wcscat(DstPath, L"\\freeldr.ini");
2282
2283 DoesFreeLdrExist = DoesFileExist(SystemRootPath->Buffer, L"freeldr.ini");
2284 if (DoesFreeLdrExist)
2285 {
2286 /* Update existing 'freeldr.ini' */
2287 DPRINT1("Update existing 'freeldr.ini'\n");
2288
2289 Status = UpdateFreeLoaderIni(DstPath, DestinationArcPath->Buffer);
2290 if (!NT_SUCCESS(Status))
2291 {
2292 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2293 return Status;
2294 }
2295 }
2296
2297 /* Check for NT and other bootloaders */
2298
2299 // FIXME: Check for Vista+ bootloader!
2300 if (DoesFileExist(SystemRootPath->Buffer, L"ntldr") == TRUE ||
2301 DoesFileExist(SystemRootPath->Buffer, L"boot.ini") == TRUE)
2302 {
2303 /* Search root directory for 'ntldr' and 'boot.ini' */
2304 DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
2305
2306 /* Create or update 'freeldr.ini' */
2307 if (DoesFreeLdrExist == FALSE)
2308 {
2309 /* Create new 'freeldr.ini' */
2310 DPRINT1("Create new 'freeldr.ini'\n");
2311 // wcscpy(DstPath, SystemRootPath->Buffer);
2312 // wcscat(DstPath, L"\\freeldr.ini");
2313
2314 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2315 if (!NT_SUCCESS(Status))
2316 {
2317 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2318 return Status;
2319 }
2320
2321 /* Install new bootcode into a file */
2322 wcscpy(DstPath, SystemRootPath->Buffer);
2323 wcscat(DstPath, L"\\bootsect.ros");
2324
2325 if (PartitionType == PARTITION_FAT32 ||
2326 PartitionType == PARTITION_FAT32_XINT13)
2327 {
2328 /* Install FAT32 bootcode */
2329 wcscpy(SrcPath, SourceRootPath->Buffer);
2330 wcscat(SrcPath, L"\\loader\\fat32.bin");
2331
2332 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
2333 Status = InstallFat32BootCodeToFile(SrcPath, DstPath,
2334 SystemRootPath->Buffer);
2335 if (!NT_SUCCESS(Status))
2336 {
2337 DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
2338 return Status;
2339 }
2340 }
2341 else
2342 {
2343 /* Install FAT16 bootcode */
2344 wcscpy(SrcPath, SourceRootPath->Buffer);
2345 wcscat(SrcPath, L"\\loader\\fat.bin");
2346
2347 DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2348 Status = InstallFat16BootCodeToFile(SrcPath, DstPath,
2349 SystemRootPath->Buffer);
2350 if (!NT_SUCCESS(Status))
2351 {
2352 DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
2353 return Status;
2354 }
2355 }
2356 }
2357
2358 /* Update 'boot.ini' */
2359 wcscpy(DstPath, SystemRootPath->Buffer);
2360 wcscat(DstPath, L"\\boot.ini");
2361
2362 DPRINT1("Update 'boot.ini': %S\n", DstPath);
2363 Status = UpdateBootIni(DstPath,
2364 L"C:\\bootsect.ros",
2365 L"\"ReactOS\"");
2366 if (!NT_SUCCESS(Status))
2367 {
2368 DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
2369 return Status;
2370 }
2371 }
2372 else
2373 {
2374 /* Non-NT bootloaders: install our own bootloader */
2375
2376 PWCHAR Section;
2377 PWCHAR Description;
2378 PWCHAR BootDrive;
2379 PWCHAR BootPartition;
2380 PWCHAR BootSector;
2381 PWCHAR BootSectorFileName;
2382
2383 if (DoesFileExist(SystemRootPath->Buffer, L"io.sys") == TRUE ||
2384 DoesFileExist(SystemRootPath->Buffer, L"msdos.sys") == TRUE)
2385 {
2386 /* Search for root directory for 'io.sys' and 'msdos.sys' */
2387 DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
2388
2389 Section = L"DOS";
2390 Description = L"\"DOS/Windows\"";
2391 BootDrive = L"hd0";
2392 BootPartition = L"1";
2393 BootSector = L"BOOTSECT.DOS";
2394
2395 BootSectorFileName = L"\\bootsect.dos";
2396 }
2397 else
2398 if (DoesFileExist(SystemRootPath->Buffer, L"kernel.sys") == TRUE)
2399 {
2400 /* Search for root directory for 'kernel.sys' */
2401 DPRINT1("Found FreeDOS boot loader\n");
2402
2403 Section = L"DOS";
2404 Description = L"\"FreeDOS\"";
2405 BootDrive = L"hd0";
2406 BootPartition = L"1";
2407 BootSector = L"BOOTSECT.DOS";
2408
2409 BootSectorFileName = L"\\bootsect.dos";
2410 }
2411 else
2412 {
2413 /* No or unknown boot loader */
2414 DPRINT1("No or unknown boot loader found\n");
2415
2416 Section = L"Unknown";
2417 Description = L"\"Unknown Operating System\"";
2418 BootDrive = L"hd0";
2419 BootPartition = L"1";
2420 BootSector = L"BOOTSECT.OLD";
2421
2422 BootSectorFileName = L"\\bootsect.old";
2423 }
2424
2425 /* Create or update 'freeldr.ini' */
2426 if (DoesFreeLdrExist == FALSE)
2427 {
2428 /* Create new 'freeldr.ini' */
2429 DPRINT1("Create new 'freeldr.ini'\n");
2430 // wcscpy(DstPath, SystemRootPath->Buffer);
2431 // wcscat(DstPath, L"\\freeldr.ini");
2432
2433 if (IsThereAValidBootSector(SystemRootPath->Buffer))
2434 {
2435 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2436 DstPath, DestinationArcPath->Buffer,
2437 Section, Description,
2438 BootDrive, BootPartition, BootSector);
2439 if (!NT_SUCCESS(Status))
2440 {
2441 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2442 return Status;
2443 }
2444
2445 /* Save current bootsector */
2446 wcscpy(DstPath, SystemRootPath->Buffer);
2447 wcscat(DstPath, BootSectorFileName);
2448
2449 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2450 Status = SaveCurrentBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE);
2451 if (!NT_SUCCESS(Status))
2452 {
2453 DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
2454 return Status;
2455 }
2456 }
2457 else
2458 {
2459 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2460 if (!NT_SUCCESS(Status))
2461 {
2462 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2463 return Status;
2464 }
2465 }
2466
2467 /* Install new bootsector on the disk */
2468 if (PartitionType == PARTITION_FAT32 ||
2469 PartitionType == PARTITION_FAT32_XINT13)
2470 {
2471 /* Install FAT32 bootcode */
2472 wcscpy(SrcPath, SourceRootPath->Buffer);
2473 wcscat(SrcPath, L"\\loader\\fat32.bin");
2474
2475 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2476 Status = InstallFat32BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2477 if (!NT_SUCCESS(Status))
2478 {
2479 DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
2480 return Status;
2481 }
2482 }
2483 else
2484 {
2485 /* Install FAT16 bootcode */
2486 wcscpy(SrcPath, SourceRootPath->Buffer);
2487 wcscat(SrcPath, L"\\loader\\fat.bin");
2488
2489 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2490 Status = InstallFat16BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2491 if (!NT_SUCCESS(Status))
2492 {
2493 DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2494 return Status;
2495 }
2496 }
2497 }
2498 }
2499
2500 return STATUS_SUCCESS;
2501 #else
2502 return STATUS_NOT_IMPLEMENTED;
2503 #endif
2504 }
2505
2506 static
2507 NTSTATUS
2508 InstallExt2BootcodeToPartition(
2509 PUNICODE_STRING SystemRootPath,
2510 PUNICODE_STRING SourceRootPath,
2511 PUNICODE_STRING DestinationArcPath,
2512 UCHAR PartitionType)
2513 {
2514 #ifdef __REACTOS__
2515 NTSTATUS Status;
2516 BOOLEAN DoesFreeLdrExist;
2517 WCHAR SrcPath[MAX_PATH];
2518 WCHAR DstPath[MAX_PATH];
2519
2520 /* EXT2 partition */
2521 DPRINT("System path: '%wZ'\n", SystemRootPath);
2522
2523 /* Copy FreeLoader to the system partition */
2524 wcscpy(SrcPath, SourceRootPath->Buffer);
2525 wcscat(SrcPath, L"\\loader\\freeldr.sys");
2526 wcscpy(DstPath, SystemRootPath->Buffer);
2527 wcscat(DstPath, L"\\freeldr.sys");
2528
2529 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2530 Status = SetupCopyFile(SrcPath, DstPath);
2531 if (!NT_SUCCESS(Status))
2532 {
2533 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2534 return Status;
2535 }
2536
2537 /* Prepare for possibly copying 'freeldr.ini' */
2538 wcscpy(DstPath, SystemRootPath->Buffer);
2539 wcscat(DstPath, L"\\freeldr.ini");
2540
2541 DoesFreeLdrExist = DoesFileExist(SystemRootPath->Buffer, L"freeldr.ini");
2542 if (DoesFreeLdrExist)
2543 {
2544 /* Update existing 'freeldr.ini' */
2545 DPRINT1("Update existing 'freeldr.ini'\n");
2546
2547 Status = UpdateFreeLoaderIni(DstPath, DestinationArcPath->Buffer);
2548 if (!NT_SUCCESS(Status))
2549 {
2550 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2551 return Status;
2552 }
2553 }
2554
2555 /* Check for *nix bootloaders */
2556
2557 /* Create or update 'freeldr.ini' */
2558 if (DoesFreeLdrExist == FALSE)
2559 {
2560 /* Create new 'freeldr.ini' */
2561 DPRINT1("Create new 'freeldr.ini'\n");
2562 wcscpy(DstPath, SystemRootPath->Buffer);
2563 wcscat(DstPath, L"\\freeldr.ini");
2564
2565 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */
2566 DPRINT1("*nix or unknown boot loader found\n");
2567
2568 if (IsThereAValidBootSector(SystemRootPath->Buffer))
2569 {
2570 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2571 DstPath, DestinationArcPath->Buffer,
2572 L"Linux", L"\"Linux\"",
2573 L"hd0", L"1", L"BOOTSECT.OLD");
2574 if (!NT_SUCCESS(Status))
2575 {
2576 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2577 return Status;
2578 }
2579
2580 /* Save current bootsector */
2581 wcscpy(DstPath, SystemRootPath->Buffer);
2582 wcscat(DstPath, L"\\bootsect.old");
2583
2584 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2585 Status = SaveCurrentBootSector(SystemRootPath->Buffer, DstPath, sizeof(EXT2_BOOTSECTOR));
2586 if (!NT_SUCCESS(Status))
2587 {
2588 DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
2589 return Status;
2590 }
2591 }
2592 else
2593 {
2594 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2595 if (!NT_SUCCESS(Status))
2596 {
2597 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2598 return Status;
2599 }
2600 }
2601
2602 /* Install new bootsector on the disk */
2603 // if (PartitionType == PARTITION_EXT2)
2604 {
2605 /* Install EXT2 bootcode */
2606 wcscpy(SrcPath, SourceRootPath->Buffer);
2607 wcscat(SrcPath, L"\\loader\\ext2.bin");
2608
2609 DPRINT1("Install EXT2 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2610 Status = InstallExt2BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2611 if (!NT_SUCCESS(Status))
2612 {
2613 DPRINT1("InstallExt2BootCodeToDisk() failed (Status %lx)\n", Status);
2614 return Status;
2615 }
2616 }
2617 }
2618
2619 return STATUS_SUCCESS;
2620 #else
2621 return STATUS_NOT_IMPLEMENTED;
2622 #endif
2623 }
2624
2625
2626 NTSTATUS
2627 InstallVBRToPartition(
2628 PUNICODE_STRING SystemRootPath,
2629 PUNICODE_STRING SourceRootPath,
2630 PUNICODE_STRING DestinationArcPath,
2631 UCHAR PartitionType)
2632 {
2633 switch (PartitionType)
2634 {
2635 case PARTITION_FAT_12:
2636 case PARTITION_FAT_16:
2637 case PARTITION_HUGE:
2638 case PARTITION_XINT13:
2639 case PARTITION_FAT32:
2640 case PARTITION_FAT32_XINT13:
2641 {
2642 return InstallFatBootcodeToPartition(SystemRootPath,
2643 SourceRootPath,
2644 DestinationArcPath,
2645 PartitionType);
2646 }
2647
2648 case PARTITION_EXT2:
2649 {
2650 return InstallExt2BootcodeToPartition(SystemRootPath,
2651 SourceRootPath,
2652 DestinationArcPath,
2653 PartitionType);
2654 }
2655
2656 case PARTITION_IFS:
2657 break;
2658
2659 default:
2660 DPRINT1("PartitionType 0x%02X unknown!\n", PartitionType);
2661 break;
2662 }
2663
2664 return STATUS_UNSUCCESSFUL;
2665 }
2666
2667
2668 NTSTATUS
2669 InstallFatBootcodeToFloppy(
2670 PUNICODE_STRING SourceRootPath,
2671 PUNICODE_STRING DestinationArcPath)
2672 {
2673 #ifdef __REACTOS__
2674 NTSTATUS Status;
2675 UNICODE_STRING FloppyDevice = RTL_CONSTANT_STRING(L"\\Device\\Floppy0");
2676 WCHAR SrcPath[MAX_PATH];
2677 WCHAR DstPath[MAX_PATH];
2678
2679 /* Format the floppy first */
2680 Status = VfatFormat(&FloppyDevice,
2681 FMIFS_FLOPPY,
2682 NULL,
2683 TRUE,
2684 0,
2685 NULL);
2686 if (!NT_SUCCESS(Status))
2687 {
2688 DPRINT1("VfatFormat() failed (Status %lx)\n", Status);
2689 return Status;
2690 }
2691
2692 /* Copy FreeLoader to the boot partition */
2693 wcscpy(SrcPath, SourceRootPath->Buffer);
2694 wcscat(SrcPath, L"\\loader\\freeldr.sys");
2695
2696 wcscpy(DstPath, L"\\Device\\Floppy0\\freeldr.sys");
2697
2698 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2699 Status = SetupCopyFile(SrcPath, DstPath);
2700 if (!NT_SUCCESS(Status))
2701 {
2702 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2703 return Status;
2704 }
2705
2706 /* Create new 'freeldr.ini' */
2707 wcscpy(DstPath, L"\\Device\\Floppy0\\freeldr.ini");
2708
2709 DPRINT("Create new 'freeldr.ini'\n");
2710 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2711 if (!NT_SUCCESS(Status))
2712 {
2713 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2714 return Status;
2715 }
2716
2717 /* Install FAT12/16 boosector */
2718 wcscpy(SrcPath, SourceRootPath->Buffer);
2719 wcscat(SrcPath, L"\\loader\\fat.bin");
2720
2721 wcscpy(DstPath, L"\\Device\\Floppy0");
2722
2723 DPRINT("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2724 Status = InstallFat12BootCodeToFloppy(SrcPath, DstPath);
2725 if (!NT_SUCCESS(Status))
2726 {
2727 DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2728 return Status;
2729 }
2730
2731 return STATUS_SUCCESS;
2732 #else
2733 return STATUS_NOT_IMPLEMENTED;
2734 #endif
2735 }
2736
2737 /* EOF */