[SETUPLIB][USETUP] Move some code to the SetupLib.
[reactos.git] / base / setup / usetup / bootsup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: base/setup/usetup/bootsup.c
5 * PURPOSE: Bootloader support functions
6 * PROGRAMMER:
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 BOOLEAN
630 IsThereAValidBootSector(PWSTR RootPath)
631 {
632 /*
633 * We first demand that the bootsector has a valid signature at its end.
634 * We then check the first 3 bytes (as a ULONG) of the bootsector for a
635 * potential "valid" instruction (the BIOS starts execution of the bootsector
636 * at its beginning). Currently this criterium is that this ULONG must be
637 * non-zero. If both these tests pass, then the bootsector is valid; otherwise
638 * it is invalid and certainly needs to be overwritten.
639 */
640 BOOLEAN IsValid = FALSE;
641 NTSTATUS Status;
642 UNICODE_STRING Name;
643 OBJECT_ATTRIBUTES ObjectAttributes;
644 IO_STATUS_BLOCK IoStatusBlock;
645 HANDLE FileHandle;
646 LARGE_INTEGER FileOffset;
647 PUCHAR BootSector;
648 ULONG Instruction;
649
650 /* Allocate buffer for bootsector */
651 BootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
652 if (BootSector == NULL)
653 return FALSE; // STATUS_INSUFFICIENT_RESOURCES;
654
655 /* Read current boot sector into buffer */
656 RtlInitUnicodeString(&Name, RootPath);
657
658 InitializeObjectAttributes(&ObjectAttributes,
659 &Name,
660 OBJ_CASE_INSENSITIVE,
661 NULL,
662 NULL);
663
664 Status = NtOpenFile(&FileHandle,
665 GENERIC_READ | SYNCHRONIZE,
666 &ObjectAttributes,
667 &IoStatusBlock,
668 0,
669 FILE_SYNCHRONOUS_IO_NONALERT);
670 if (!NT_SUCCESS(Status))
671 goto Quit;
672
673 RtlZeroMemory(BootSector, SECTORSIZE);
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 if (!NT_SUCCESS(Status))
687 goto Quit;
688
689 /* Check the instruction; we use a ULONG to read three bytes */
690 Instruction = (*(PULONG)BootSector) & 0x00FFFFFF;
691 IsValid = (Instruction != 0x00000000);
692
693 /* Check the bootsector signature */
694 IsValid &= (*(PUSHORT)(BootSector + 0x1fe) == 0xaa55);
695
696 Quit:
697 /* Free the boot sector */
698 RtlFreeHeap(ProcessHeap, 0, BootSector);
699 return IsValid; // Status;
700 }
701
702 NTSTATUS
703 SaveBootSector(
704 PWSTR RootPath,
705 PWSTR DstPath,
706 ULONG Length)
707 {
708 NTSTATUS Status;
709 UNICODE_STRING Name;
710 OBJECT_ATTRIBUTES ObjectAttributes;
711 IO_STATUS_BLOCK IoStatusBlock;
712 HANDLE FileHandle;
713 LARGE_INTEGER FileOffset;
714 PUCHAR BootSector;
715
716 /* Allocate buffer for bootsector */
717 BootSector = RtlAllocateHeap(ProcessHeap, 0, Length);
718 if (BootSector == NULL)
719 return STATUS_INSUFFICIENT_RESOURCES;
720
721 /* Read current boot sector into buffer */
722 RtlInitUnicodeString(&Name, RootPath);
723
724 InitializeObjectAttributes(&ObjectAttributes,
725 &Name,
726 OBJ_CASE_INSENSITIVE,
727 NULL,
728 NULL);
729
730 Status = NtOpenFile(&FileHandle,
731 GENERIC_READ | SYNCHRONIZE,
732 &ObjectAttributes,
733 &IoStatusBlock,
734 0,
735 FILE_SYNCHRONOUS_IO_NONALERT);
736 if (!NT_SUCCESS(Status))
737 {
738 RtlFreeHeap(ProcessHeap, 0, BootSector);
739 return Status;
740 }
741
742 FileOffset.QuadPart = 0ULL;
743 Status = NtReadFile(FileHandle,
744 NULL,
745 NULL,
746 NULL,
747 &IoStatusBlock,
748 BootSector,
749 Length,
750 &FileOffset,
751 NULL);
752 NtClose(FileHandle);
753 if (!NT_SUCCESS(Status))
754 {
755 RtlFreeHeap(ProcessHeap, 0, BootSector);
756 return Status;
757 }
758
759 /* Write bootsector to DstPath */
760 RtlInitUnicodeString(&Name, DstPath);
761
762 InitializeObjectAttributes(&ObjectAttributes,
763 &Name,
764 0,
765 NULL,
766 NULL);
767
768 Status = NtCreateFile(&FileHandle,
769 GENERIC_WRITE | SYNCHRONIZE,
770 &ObjectAttributes,
771 &IoStatusBlock,
772 NULL,
773 FILE_ATTRIBUTE_NORMAL,
774 0,
775 FILE_SUPERSEDE,
776 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
777 NULL,
778 0);
779 if (!NT_SUCCESS(Status))
780 {
781 RtlFreeHeap(ProcessHeap, 0, BootSector);
782 return Status;
783 }
784
785 Status = NtWriteFile(FileHandle,
786 NULL,
787 NULL,
788 NULL,
789 &IoStatusBlock,
790 BootSector,
791 Length,
792 NULL,
793 NULL);
794 NtClose(FileHandle);
795
796 /* Free the boot sector */
797 RtlFreeHeap(ProcessHeap, 0, BootSector);
798
799 return Status;
800 }
801
802 static
803 NTSTATUS
804 InstallFat16BootCodeToFile(
805 PWSTR SrcPath,
806 PWSTR DstPath,
807 PWSTR RootPath)
808 {
809 NTSTATUS Status;
810 UNICODE_STRING Name;
811 OBJECT_ATTRIBUTES ObjectAttributes;
812 IO_STATUS_BLOCK IoStatusBlock;
813 HANDLE FileHandle;
814 LARGE_INTEGER FileOffset;
815 PFAT_BOOTSECTOR OrigBootSector;
816 PFAT_BOOTSECTOR NewBootSector;
817
818 /* Allocate buffer for original bootsector */
819 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
820 if (OrigBootSector == NULL)
821 return STATUS_INSUFFICIENT_RESOURCES;
822
823 /* Read current boot sector into buffer */
824 RtlInitUnicodeString(&Name, RootPath);
825
826 InitializeObjectAttributes(&ObjectAttributes,
827 &Name,
828 OBJ_CASE_INSENSITIVE,
829 NULL,
830 NULL);
831
832 Status = NtOpenFile(&FileHandle,
833 GENERIC_READ | SYNCHRONIZE,
834 &ObjectAttributes,
835 &IoStatusBlock,
836 0,
837 FILE_SYNCHRONOUS_IO_NONALERT);
838 if (!NT_SUCCESS(Status))
839 {
840 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
841 return Status;
842 }
843
844 FileOffset.QuadPart = 0ULL;
845 Status = NtReadFile(FileHandle,
846 NULL,
847 NULL,
848 NULL,
849 &IoStatusBlock,
850 OrigBootSector,
851 SECTORSIZE,
852 &FileOffset,
853 NULL);
854 NtClose(FileHandle);
855 if (!NT_SUCCESS(Status))
856 {
857 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
858 return Status;
859 }
860
861 /* Allocate buffer for new bootsector */
862 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
863 if (NewBootSector == NULL)
864 {
865 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
866 return STATUS_INSUFFICIENT_RESOURCES;
867 }
868
869 /* Read new bootsector from SrcPath */
870 RtlInitUnicodeString(&Name, SrcPath);
871
872 InitializeObjectAttributes(&ObjectAttributes,
873 &Name,
874 OBJ_CASE_INSENSITIVE,
875 NULL,
876 NULL);
877
878 Status = NtOpenFile(&FileHandle,
879 GENERIC_READ | SYNCHRONIZE,
880 &ObjectAttributes,
881 &IoStatusBlock,
882 0,
883 FILE_SYNCHRONOUS_IO_NONALERT);
884 if (!NT_SUCCESS(Status))
885 {
886 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
887 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
888 return Status;
889 }
890
891 FileOffset.QuadPart = 0ULL;
892 Status = NtReadFile(FileHandle,
893 NULL,
894 NULL,
895 NULL,
896 &IoStatusBlock,
897 NewBootSector,
898 SECTORSIZE,
899 &FileOffset,
900 NULL);
901 NtClose(FileHandle);
902 if (!NT_SUCCESS(Status))
903 {
904 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
905 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
906 return Status;
907 }
908
909 /* Adjust bootsector (copy a part of the FAT BPB) */
910 memcpy(&NewBootSector->OemName,
911 &OrigBootSector->OemName,
912 FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
913 FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
914
915 /* Free the original boot sector */
916 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
917
918 /* Write new bootsector to DstPath */
919 RtlInitUnicodeString(&Name, DstPath);
920
921 InitializeObjectAttributes(&ObjectAttributes,
922 &Name,
923 0,
924 NULL,
925 NULL);
926
927 Status = NtCreateFile(&FileHandle,
928 GENERIC_WRITE | SYNCHRONIZE,
929 &ObjectAttributes,
930 &IoStatusBlock,
931 NULL,
932 FILE_ATTRIBUTE_NORMAL,
933 0,
934 FILE_OVERWRITE_IF,
935 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
936 NULL,
937 0);
938 if (!NT_SUCCESS(Status))
939 {
940 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
941 return Status;
942 }
943
944 Status = NtWriteFile(FileHandle,
945 NULL,
946 NULL,
947 NULL,
948 &IoStatusBlock,
949 NewBootSector,
950 SECTORSIZE,
951 NULL,
952 NULL);
953 NtClose(FileHandle);
954
955 /* Free the new boot sector */
956 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
957
958 return Status;
959 }
960
961 static
962 NTSTATUS
963 InstallFat32BootCodeToFile(
964 PWSTR SrcPath,
965 PWSTR DstPath,
966 PWSTR RootPath)
967 {
968 NTSTATUS Status;
969 UNICODE_STRING Name;
970 OBJECT_ATTRIBUTES ObjectAttributes;
971 IO_STATUS_BLOCK IoStatusBlock;
972 HANDLE FileHandle;
973 LARGE_INTEGER FileOffset;
974 PFAT32_BOOTSECTOR OrigBootSector;
975 PFAT32_BOOTSECTOR NewBootSector;
976
977 /* Allocate buffer for original bootsector */
978 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
979 if (OrigBootSector == NULL)
980 return STATUS_INSUFFICIENT_RESOURCES;
981
982 /* Read current boot sector into buffer */
983 RtlInitUnicodeString(&Name, RootPath);
984
985 InitializeObjectAttributes(&ObjectAttributes,
986 &Name,
987 OBJ_CASE_INSENSITIVE,
988 NULL,
989 NULL);
990
991 Status = NtOpenFile(&FileHandle,
992 GENERIC_READ | SYNCHRONIZE,
993 &ObjectAttributes,
994 &IoStatusBlock,
995 0,
996 FILE_SYNCHRONOUS_IO_NONALERT);
997 if (!NT_SUCCESS(Status))
998 {
999 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1000 return Status;
1001 }
1002
1003 Status = NtReadFile(FileHandle,
1004 NULL,
1005 NULL,
1006 NULL,
1007 &IoStatusBlock,
1008 OrigBootSector,
1009 SECTORSIZE,
1010 NULL,
1011 NULL);
1012 NtClose(FileHandle);
1013 if (!NT_SUCCESS(Status))
1014 {
1015 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1016 return Status;
1017 }
1018
1019 /* Allocate buffer for new bootsector (2 sectors) */
1020 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE);
1021 if (NewBootSector == NULL)
1022 {
1023 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1024 return STATUS_INSUFFICIENT_RESOURCES;
1025 }
1026
1027 /* Read new bootsector from SrcPath */
1028 RtlInitUnicodeString(&Name, SrcPath);
1029
1030 InitializeObjectAttributes(&ObjectAttributes,
1031 &Name,
1032 OBJ_CASE_INSENSITIVE,
1033 NULL,
1034 NULL);
1035
1036 Status = NtOpenFile(&FileHandle,
1037 GENERIC_READ | SYNCHRONIZE,
1038 &ObjectAttributes,
1039 &IoStatusBlock,
1040 0,
1041 FILE_SYNCHRONOUS_IO_NONALERT);
1042 if (!NT_SUCCESS(Status))
1043 {
1044 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1045 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1046 return Status;
1047 }
1048
1049 Status = NtReadFile(FileHandle,
1050 NULL,
1051 NULL,
1052 NULL,
1053 &IoStatusBlock,
1054 NewBootSector,
1055 2 * SECTORSIZE,
1056 NULL,
1057 NULL);
1058 NtClose(FileHandle);
1059 if (!NT_SUCCESS(Status))
1060 {
1061 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1062 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1063 return Status;
1064 }
1065
1066 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1067 memcpy(&NewBootSector->OemName,
1068 &OrigBootSector->OemName,
1069 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1070 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1071
1072 /* Disable the backup boot sector */
1073 NewBootSector->BackupBootSector = 0;
1074
1075 /* Free the original boot sector */
1076 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1077
1078 /* Write the first sector of the new bootcode to DstPath */
1079 RtlInitUnicodeString(&Name, DstPath);
1080
1081 InitializeObjectAttributes(&ObjectAttributes,
1082 &Name,
1083 0,
1084 NULL,
1085 NULL);
1086
1087 Status = NtCreateFile(&FileHandle,
1088 GENERIC_WRITE | SYNCHRONIZE,
1089 &ObjectAttributes,
1090 &IoStatusBlock,
1091 NULL,
1092 FILE_ATTRIBUTE_NORMAL,
1093 0,
1094 FILE_SUPERSEDE,
1095 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1096 NULL,
1097 0);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1101 return Status;
1102 }
1103
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 sizeof(PARTITION_SECTOR),
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 sizeof(PARTITION_SECTOR),
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 /* Free the original boot sector */
1588 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1589
1590 /* Write new bootsector to RootPath */
1591 RtlInitUnicodeString(&Name, RootPath);
1592
1593 InitializeObjectAttributes(&ObjectAttributes,
1594 &Name,
1595 0,
1596 NULL,
1597 NULL);
1598
1599 Status = NtOpenFile(&FileHandle,
1600 GENERIC_WRITE | SYNCHRONIZE,
1601 &ObjectAttributes,
1602 &IoStatusBlock,
1603 0,
1604 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1605 if (!NT_SUCCESS(Status))
1606 {
1607 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1608 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1609 return Status;
1610 }
1611
1612 FileOffset.QuadPart = 0ULL;
1613 Status = NtWriteFile(FileHandle,
1614 NULL,
1615 NULL,
1616 NULL,
1617 &IoStatusBlock,
1618 NewBootSector,
1619 SECTORSIZE,
1620 &FileOffset,
1621 NULL);
1622 NtClose(FileHandle);
1623
1624 /* Free the new boot sector */
1625 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1626
1627 return Status;
1628 }
1629
1630 static
1631 NTSTATUS
1632 InstallFat32BootCodeToDisk(
1633 PWSTR SrcPath,
1634 PWSTR RootPath)
1635 {
1636 NTSTATUS Status;
1637 UNICODE_STRING Name;
1638 OBJECT_ATTRIBUTES ObjectAttributes;
1639 IO_STATUS_BLOCK IoStatusBlock;
1640 HANDLE FileHandle;
1641 LARGE_INTEGER FileOffset;
1642 PFAT32_BOOTSECTOR OrigBootSector;
1643 PFAT32_BOOTSECTOR NewBootSector;
1644 USHORT BackupBootSector;
1645
1646 /* Allocate buffer for original bootsector */
1647 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1648 if (OrigBootSector == NULL)
1649 return STATUS_INSUFFICIENT_RESOURCES;
1650
1651 /* Read current boot sector into buffer */
1652 RtlInitUnicodeString(&Name, RootPath);
1653
1654 InitializeObjectAttributes(&ObjectAttributes,
1655 &Name,
1656 OBJ_CASE_INSENSITIVE,
1657 NULL,
1658 NULL);
1659
1660 Status = NtOpenFile(&FileHandle,
1661 GENERIC_READ | SYNCHRONIZE,
1662 &ObjectAttributes,
1663 &IoStatusBlock,
1664 0,
1665 FILE_SYNCHRONOUS_IO_NONALERT);
1666 if (!NT_SUCCESS(Status))
1667 {
1668 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1669 return Status;
1670 }
1671
1672 FileOffset.QuadPart = 0ULL;
1673 Status = NtReadFile(FileHandle,
1674 NULL,
1675 NULL,
1676 NULL,
1677 &IoStatusBlock,
1678 OrigBootSector,
1679 SECTORSIZE,
1680 &FileOffset,
1681 NULL);
1682 NtClose(FileHandle);
1683 if (!NT_SUCCESS(Status))
1684 {
1685 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1686 return Status;
1687 }
1688
1689
1690 /* Allocate buffer for new bootsector (2 sectors) */
1691 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, 2 * SECTORSIZE);
1692 if (NewBootSector == NULL)
1693 {
1694 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1695 return STATUS_INSUFFICIENT_RESOURCES;
1696 }
1697
1698 /* Read new bootsector from SrcPath */
1699 RtlInitUnicodeString(&Name, SrcPath);
1700
1701 InitializeObjectAttributes(&ObjectAttributes,
1702 &Name,
1703 OBJ_CASE_INSENSITIVE,
1704 NULL,
1705 NULL);
1706
1707 Status = NtOpenFile(&FileHandle,
1708 GENERIC_READ | SYNCHRONIZE,
1709 &ObjectAttributes,
1710 &IoStatusBlock,
1711 0,
1712 FILE_SYNCHRONOUS_IO_NONALERT);
1713 if (!NT_SUCCESS(Status))
1714 {
1715 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1716 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1717 return Status;
1718 }
1719
1720 Status = NtReadFile(FileHandle,
1721 NULL,
1722 NULL,
1723 NULL,
1724 &IoStatusBlock,
1725 NewBootSector,
1726 2 * SECTORSIZE,
1727 NULL,
1728 NULL);
1729 NtClose(FileHandle);
1730 if (!NT_SUCCESS(Status))
1731 {
1732 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1733 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1734 return Status;
1735 }
1736
1737 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1738 memcpy(&NewBootSector->OemName,
1739 &OrigBootSector->OemName,
1740 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1741 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1742
1743 /* Get the location of the backup boot sector */
1744 BackupBootSector = OrigBootSector->BackupBootSector;
1745
1746 /* Free the original boot sector */
1747 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1748
1749 /* Write the first sector of the new bootcode to DstPath */
1750 RtlInitUnicodeString(&Name, RootPath);
1751
1752 InitializeObjectAttributes(&ObjectAttributes,
1753 &Name,
1754 0,
1755 NULL,
1756 NULL);
1757
1758 Status = NtOpenFile(&FileHandle,
1759 GENERIC_WRITE | SYNCHRONIZE,
1760 &ObjectAttributes,
1761 &IoStatusBlock,
1762 0,
1763 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1764 if (!NT_SUCCESS(Status))
1765 {
1766 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1767 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1768 return Status;
1769 }
1770
1771 /* Write sector 0 */
1772 FileOffset.QuadPart = 0ULL;
1773 Status = NtWriteFile(FileHandle,
1774 NULL,
1775 NULL,
1776 NULL,
1777 &IoStatusBlock,
1778 NewBootSector,
1779 SECTORSIZE,
1780 &FileOffset,
1781 NULL);
1782 if (!NT_SUCCESS(Status))
1783 {
1784 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1785 NtClose(FileHandle);
1786 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1787 return Status;
1788 }
1789
1790 /* Write backup boot sector */
1791 if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1792 {
1793 FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1794 Status = NtWriteFile(FileHandle,
1795 NULL,
1796 NULL,
1797 NULL,
1798 &IoStatusBlock,
1799 NewBootSector,
1800 SECTORSIZE,
1801 &FileOffset,
1802 NULL);
1803 if (!NT_SUCCESS(Status))
1804 {
1805 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1806 NtClose(FileHandle);
1807 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1808 return Status;
1809 }
1810 }
1811
1812 /* Write sector 14 */
1813 FileOffset.QuadPart = 14 * SECTORSIZE;
1814 Status = NtWriteFile(FileHandle,
1815 NULL,
1816 NULL,
1817 NULL,
1818 &IoStatusBlock,
1819 ((PUCHAR)NewBootSector + SECTORSIZE),
1820 SECTORSIZE,
1821 &FileOffset,
1822 NULL);
1823 if (!NT_SUCCESS(Status))
1824 {
1825 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1826 }
1827 NtClose(FileHandle);
1828
1829 /* Free the new boot sector */
1830 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1831
1832 return Status;
1833 }
1834
1835 static
1836 NTSTATUS
1837 InstallExt2BootCodeToDisk(
1838 PWSTR SrcPath,
1839 PWSTR RootPath)
1840 {
1841 NTSTATUS Status;
1842 UNICODE_STRING Name;
1843 OBJECT_ATTRIBUTES ObjectAttributes;
1844 IO_STATUS_BLOCK IoStatusBlock;
1845 HANDLE FileHandle;
1846 LARGE_INTEGER FileOffset;
1847 // PEXT2_BOOTSECTOR OrigBootSector;
1848 PEXT2_BOOTSECTOR NewBootSector;
1849 // USHORT BackupBootSector;
1850
1851 #if 0
1852 /* Allocate buffer for original bootsector */
1853 OrigBootSector = RtlAllocateHeap(ProcessHeap, 0, SECTORSIZE);
1854 if (OrigBootSector == NULL)
1855 return STATUS_INSUFFICIENT_RESOURCES;
1856
1857 /* Read current boot sector into buffer */
1858 RtlInitUnicodeString(&Name, RootPath);
1859
1860 InitializeObjectAttributes(&ObjectAttributes,
1861 &Name,
1862 OBJ_CASE_INSENSITIVE,
1863 NULL,
1864 NULL);
1865
1866 Status = NtOpenFile(&FileHandle,
1867 GENERIC_READ | SYNCHRONIZE,
1868 &ObjectAttributes,
1869 &IoStatusBlock,
1870 0,
1871 FILE_SYNCHRONOUS_IO_NONALERT);
1872 if (!NT_SUCCESS(Status))
1873 {
1874 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1875 return Status;
1876 }
1877
1878 FileOffset.QuadPart = 0ULL;
1879 Status = NtReadFile(FileHandle,
1880 NULL,
1881 NULL,
1882 NULL,
1883 &IoStatusBlock,
1884 OrigBootSector,
1885 SECTORSIZE,
1886 &FileOffset,
1887 NULL);
1888 NtClose(FileHandle);
1889 if (!NT_SUCCESS(Status))
1890 {
1891 RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1892 return Status;
1893 }
1894 #endif
1895
1896 /* Allocate buffer for new bootsector */
1897 NewBootSector = RtlAllocateHeap(ProcessHeap, 0, sizeof(EXT2_BOOTSECTOR));
1898 if (NewBootSector == NULL)
1899 {
1900 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1901 return STATUS_INSUFFICIENT_RESOURCES;
1902 }
1903
1904 /* Read new bootsector from SrcPath */
1905 RtlInitUnicodeString(&Name, SrcPath);
1906
1907 InitializeObjectAttributes(&ObjectAttributes,
1908 &Name,
1909 OBJ_CASE_INSENSITIVE,
1910 NULL,
1911 NULL);
1912
1913 Status = NtOpenFile(&FileHandle,
1914 GENERIC_READ | SYNCHRONIZE,
1915 &ObjectAttributes,
1916 &IoStatusBlock,
1917 0,
1918 FILE_SYNCHRONOUS_IO_NONALERT);
1919 if (!NT_SUCCESS(Status))
1920 {
1921 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1922 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1923 return Status;
1924 }
1925
1926 Status = NtReadFile(FileHandle,
1927 NULL,
1928 NULL,
1929 NULL,
1930 &IoStatusBlock,
1931 NewBootSector,
1932 sizeof(EXT2_BOOTSECTOR),
1933 NULL,
1934 NULL);
1935 NtClose(FileHandle);
1936 if (!NT_SUCCESS(Status))
1937 {
1938 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1939 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1940 return Status;
1941 }
1942
1943 #if 0
1944 /* Adjust bootsector (copy a part of the FAT32 BPB) */
1945 memcpy(&NewBootSector->OemName,
1946 &OrigBootSector->OemName,
1947 FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
1948 FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
1949
1950 NewBootSector->HiddenSectors = PartitionList->CurrentDisk->SectorsPerTrack;
1951
1952 /* Get the location of the backup boot sector */
1953 BackupBootSector = OrigBootSector->BackupBootSector;
1954
1955 /* Free the original boot sector */
1956 // RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1957 #endif
1958
1959 /* Write new bootsector to RootPath */
1960 RtlInitUnicodeString(&Name, RootPath);
1961
1962 InitializeObjectAttributes(&ObjectAttributes,
1963 &Name,
1964 0,
1965 NULL,
1966 NULL);
1967
1968 Status = NtOpenFile(&FileHandle,
1969 GENERIC_WRITE | SYNCHRONIZE,
1970 &ObjectAttributes,
1971 &IoStatusBlock,
1972 0,
1973 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
1974 if (!NT_SUCCESS(Status))
1975 {
1976 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1977 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1978 return Status;
1979 }
1980
1981 /* Write sector 0 */
1982 FileOffset.QuadPart = 0ULL;
1983 Status = NtWriteFile(FileHandle,
1984 NULL,
1985 NULL,
1986 NULL,
1987 &IoStatusBlock,
1988 NewBootSector,
1989 sizeof(EXT2_BOOTSECTOR),
1990 &FileOffset,
1991 NULL);
1992 #if 0
1993 if (!NT_SUCCESS(Status))
1994 {
1995 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1996 NtClose(FileHandle);
1997 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1998 return Status;
1999 }
2000
2001 /* Write backup boot sector */
2002 if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
2003 {
2004 FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
2005 Status = NtWriteFile(FileHandle,
2006 NULL,
2007 NULL,
2008 NULL,
2009 &IoStatusBlock,
2010 NewBootSector,
2011 SECTORSIZE,
2012 &FileOffset,
2013 NULL);
2014 if (!NT_SUCCESS(Status))
2015 {
2016 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
2017 NtClose(FileHandle);
2018 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
2019 return Status;
2020 }
2021 }
2022
2023 /* Write sector 14 */
2024 FileOffset.QuadPart = 14 * SECTORSIZE;
2025 Status = NtWriteFile(FileHandle,
2026 NULL,
2027 NULL,
2028 NULL,
2029 &IoStatusBlock,
2030 ((PUCHAR)NewBootSector + SECTORSIZE),
2031 SECTORSIZE,
2032 &FileOffset,
2033 NULL);
2034 if (!NT_SUCCESS(Status))
2035 {
2036 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
2037 }
2038 #endif
2039 NtClose(FileHandle);
2040
2041 /* Free the new boot sector */
2042 RtlFreeHeap(ProcessHeap, 0, NewBootSector);
2043
2044 return Status;
2045 }
2046
2047 static
2048 NTSTATUS
2049 UnprotectBootIni(
2050 PWSTR FileName,
2051 PULONG Attributes)
2052 {
2053 NTSTATUS Status;
2054 UNICODE_STRING Name;
2055 OBJECT_ATTRIBUTES ObjectAttributes;
2056 IO_STATUS_BLOCK IoStatusBlock;
2057 FILE_BASIC_INFORMATION FileInfo;
2058 HANDLE FileHandle;
2059
2060 RtlInitUnicodeString(&Name, FileName);
2061
2062 InitializeObjectAttributes(&ObjectAttributes,
2063 &Name,
2064 OBJ_CASE_INSENSITIVE,
2065 NULL,
2066 NULL);
2067
2068 Status = NtOpenFile(&FileHandle,
2069 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2070 &ObjectAttributes,
2071 &IoStatusBlock,
2072 0,
2073 FILE_SYNCHRONOUS_IO_NONALERT);
2074 if (Status == STATUS_NO_SUCH_FILE)
2075 {
2076 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2077 *Attributes = 0;
2078 return STATUS_SUCCESS;
2079 }
2080 if (!NT_SUCCESS(Status))
2081 {
2082 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2083 return Status;
2084 }
2085
2086 Status = NtQueryInformationFile(FileHandle,
2087 &IoStatusBlock,
2088 &FileInfo,
2089 sizeof(FILE_BASIC_INFORMATION),
2090 FileBasicInformation);
2091 if (!NT_SUCCESS(Status))
2092 {
2093 DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
2094 NtClose(FileHandle);
2095 return Status;
2096 }
2097
2098 *Attributes = FileInfo.FileAttributes;
2099
2100 /* Delete attributes SYSTEM, HIDDEN and READONLY */
2101 FileInfo.FileAttributes = FileInfo.FileAttributes &
2102 ~(FILE_ATTRIBUTE_SYSTEM |
2103 FILE_ATTRIBUTE_HIDDEN |
2104 FILE_ATTRIBUTE_READONLY);
2105
2106 Status = NtSetInformationFile(FileHandle,
2107 &IoStatusBlock,
2108 &FileInfo,
2109 sizeof(FILE_BASIC_INFORMATION),
2110 FileBasicInformation);
2111 if (!NT_SUCCESS(Status))
2112 {
2113 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
2114 }
2115
2116 NtClose(FileHandle);
2117 return Status;
2118 }
2119
2120 static
2121 NTSTATUS
2122 ProtectBootIni(
2123 PWSTR FileName,
2124 ULONG Attributes)
2125 {
2126 NTSTATUS Status;
2127 UNICODE_STRING Name;
2128 OBJECT_ATTRIBUTES ObjectAttributes;
2129 IO_STATUS_BLOCK IoStatusBlock;
2130 FILE_BASIC_INFORMATION FileInfo;
2131 HANDLE FileHandle;
2132
2133 RtlInitUnicodeString(&Name, FileName);
2134
2135 InitializeObjectAttributes(&ObjectAttributes,
2136 &Name,
2137 OBJ_CASE_INSENSITIVE,
2138 NULL,
2139 NULL);
2140
2141 Status = NtOpenFile(&FileHandle,
2142 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2143 &ObjectAttributes,
2144 &IoStatusBlock,
2145 0,
2146 FILE_SYNCHRONOUS_IO_NONALERT);
2147 if (!NT_SUCCESS(Status))
2148 {
2149 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2150 return Status;
2151 }
2152
2153 Status = NtQueryInformationFile(FileHandle,
2154 &IoStatusBlock,
2155 &FileInfo,
2156 sizeof(FILE_BASIC_INFORMATION),
2157 FileBasicInformation);
2158 if (!NT_SUCCESS(Status))
2159 {
2160 DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
2161 NtClose(FileHandle);
2162 return Status;
2163 }
2164
2165 FileInfo.FileAttributes = FileInfo.FileAttributes | Attributes;
2166
2167 Status = NtSetInformationFile(FileHandle,
2168 &IoStatusBlock,
2169 &FileInfo,
2170 sizeof(FILE_BASIC_INFORMATION),
2171 FileBasicInformation);
2172 if (!NT_SUCCESS(Status))
2173 {
2174 DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
2175 }
2176
2177 NtClose(FileHandle);
2178 return Status;
2179 }
2180
2181 static
2182 NTSTATUS
2183 UpdateBootIni(
2184 PWSTR BootIniPath,
2185 PWSTR EntryName,
2186 PWSTR EntryValue)
2187 {
2188 NTSTATUS Status;
2189 PINICACHE Cache = NULL;
2190 PINICACHESECTION Section = NULL;
2191 ULONG FileAttribute;
2192 PWCHAR OldValue = NULL;
2193
2194 Status = IniCacheLoad(&Cache, BootIniPath, FALSE);
2195 if (!NT_SUCCESS(Status))
2196 {
2197 return Status;
2198 }
2199
2200 Section = IniCacheGetSection(Cache,
2201 L"operating systems");
2202 if (Section == NULL)
2203 {
2204 IniCacheDestroy(Cache);
2205 return STATUS_UNSUCCESSFUL;
2206 }
2207
2208 /* Check - maybe record already exists */
2209 Status = IniCacheGetKey(Section, EntryName, &OldValue);
2210
2211 /* If either key was not found, or contains something else - add new one */
2212 if (!NT_SUCCESS(Status) || wcscmp(OldValue, EntryValue))
2213 {
2214 IniCacheInsertKey(Section,
2215 NULL,
2216 INSERT_LAST,
2217 EntryName,
2218 EntryValue);
2219 }
2220
2221 Status = UnprotectBootIni(BootIniPath,
2222 &FileAttribute);
2223 if (!NT_SUCCESS(Status))
2224 {
2225 IniCacheDestroy(Cache);
2226 return Status;
2227 }
2228
2229 Status = IniCacheSave(Cache, BootIniPath);
2230 if (!NT_SUCCESS(Status))
2231 {
2232 IniCacheDestroy(Cache);
2233 return Status;
2234 }
2235
2236 FileAttribute |= (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
2237 Status = ProtectBootIni(BootIniPath, FileAttribute);
2238
2239 IniCacheDestroy(Cache);
2240
2241 return Status;
2242 }
2243
2244 static
2245 NTSTATUS
2246 InstallFatBootcodeToPartition(
2247 PUNICODE_STRING SystemRootPath,
2248 PUNICODE_STRING SourceRootPath,
2249 PUNICODE_STRING DestinationArcPath,
2250 UCHAR PartitionType)
2251 {
2252 NTSTATUS Status;
2253 BOOLEAN DoesFreeLdrExist;
2254 WCHAR SrcPath[MAX_PATH];
2255 WCHAR DstPath[MAX_PATH];
2256
2257 /* FAT or FAT32 partition */
2258 DPRINT("System path: '%wZ'\n", SystemRootPath);
2259
2260 /* Copy FreeLoader to the system partition */
2261 wcscpy(SrcPath, SourceRootPath->Buffer);
2262 wcscat(SrcPath, L"\\loader\\freeldr.sys");
2263 wcscpy(DstPath, SystemRootPath->Buffer);
2264 wcscat(DstPath, L"\\freeldr.sys");
2265
2266 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2267 Status = SetupCopyFile(SrcPath, DstPath);
2268 if (!NT_SUCCESS(Status))
2269 {
2270 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2271 return Status;
2272 }
2273
2274 /* Prepare for possibly copying 'freeldr.ini' */
2275 wcscpy(DstPath, SystemRootPath->Buffer);
2276 wcscat(DstPath, L"\\freeldr.ini");
2277
2278 DoesFreeLdrExist = DoesFileExist(NULL, SystemRootPath->Buffer, L"freeldr.ini");
2279 if (DoesFreeLdrExist)
2280 {
2281 /* Update existing 'freeldr.ini' */
2282 DPRINT1("Update existing 'freeldr.ini'\n");
2283
2284 Status = UpdateFreeLoaderIni(DstPath, DestinationArcPath->Buffer);
2285 if (!NT_SUCCESS(Status))
2286 {
2287 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2288 return Status;
2289 }
2290 }
2291
2292 /* Check for NT and other bootloaders */
2293
2294 // FIXME: Check for Vista+ bootloader!
2295 if (DoesFileExist(NULL, SystemRootPath->Buffer, L"ntldr") == TRUE ||
2296 DoesFileExist(NULL, SystemRootPath->Buffer, L"boot.ini") == TRUE)
2297 {
2298 /* Search root directory for 'ntldr' and 'boot.ini' */
2299 DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
2300
2301 /* Create or update 'freeldr.ini' */
2302 if (DoesFreeLdrExist == FALSE)
2303 {
2304 /* Create new 'freeldr.ini' */
2305 DPRINT1("Create new 'freeldr.ini'\n");
2306 // wcscpy(DstPath, SystemRootPath->Buffer);
2307 // wcscat(DstPath, L"\\freeldr.ini");
2308
2309 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2310 if (!NT_SUCCESS(Status))
2311 {
2312 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2313 return Status;
2314 }
2315
2316 /* Install new bootcode into a file */
2317 wcscpy(DstPath, SystemRootPath->Buffer);
2318 wcscat(DstPath, L"\\bootsect.ros");
2319
2320 if (PartitionType == PARTITION_FAT32 ||
2321 PartitionType == PARTITION_FAT32_XINT13)
2322 {
2323 /* Install FAT32 bootcode */
2324 wcscpy(SrcPath, SourceRootPath->Buffer);
2325 wcscat(SrcPath, L"\\loader\\fat32.bin");
2326
2327 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
2328 Status = InstallFat32BootCodeToFile(SrcPath, DstPath,
2329 SystemRootPath->Buffer);
2330 if (!NT_SUCCESS(Status))
2331 {
2332 DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
2333 return Status;
2334 }
2335 }
2336 else
2337 {
2338 /* Install FAT16 bootcode */
2339 wcscpy(SrcPath, SourceRootPath->Buffer);
2340 wcscat(SrcPath, L"\\loader\\fat.bin");
2341
2342 DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2343 Status = InstallFat16BootCodeToFile(SrcPath, DstPath,
2344 SystemRootPath->Buffer);
2345 if (!NT_SUCCESS(Status))
2346 {
2347 DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
2348 return Status;
2349 }
2350 }
2351 }
2352
2353 /* Update 'boot.ini' */
2354 wcscpy(DstPath, SystemRootPath->Buffer);
2355 wcscat(DstPath, L"\\boot.ini");
2356
2357 DPRINT1("Update 'boot.ini': %S\n", DstPath);
2358 Status = UpdateBootIni(DstPath,
2359 L"C:\\bootsect.ros",
2360 L"\"ReactOS\"");
2361 if (!NT_SUCCESS(Status))
2362 {
2363 DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
2364 return Status;
2365 }
2366 }
2367 else
2368 {
2369 /* Non-NT bootloaders: install our own bootloader */
2370
2371 PWCHAR Section;
2372 PWCHAR Description;
2373 PWCHAR BootDrive;
2374 PWCHAR BootPartition;
2375 PWCHAR BootSector;
2376 PWCHAR BootSectorFileName;
2377
2378 if (DoesFileExist(NULL, SystemRootPath->Buffer, L"io.sys") == TRUE ||
2379 DoesFileExist(NULL, SystemRootPath->Buffer, L"msdos.sys") == TRUE)
2380 {
2381 /* Search for root directory for 'io.sys' and 'msdos.sys' */
2382 DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
2383
2384 Section = L"DOS";
2385 Description = L"\"DOS/Windows\"";
2386 BootDrive = L"hd0";
2387 BootPartition = L"1";
2388 BootSector = L"BOOTSECT.DOS";
2389
2390 BootSectorFileName = L"\\bootsect.dos";
2391 }
2392 else
2393 if (DoesFileExist(NULL, SystemRootPath->Buffer, L"kernel.sys") == TRUE)
2394 {
2395 /* Search for root directory for 'kernel.sys' */
2396 DPRINT1("Found FreeDOS boot loader\n");
2397
2398 Section = L"DOS";
2399 Description = L"\"FreeDOS\"";
2400 BootDrive = L"hd0";
2401 BootPartition = L"1";
2402 BootSector = L"BOOTSECT.DOS";
2403
2404 BootSectorFileName = L"\\bootsect.dos";
2405 }
2406 else
2407 {
2408 /* No or unknown boot loader */
2409 DPRINT1("No or unknown boot loader found\n");
2410
2411 Section = L"Unknown";
2412 Description = L"\"Unknown Operating System\"";
2413 BootDrive = L"hd0";
2414 BootPartition = L"1";
2415 BootSector = L"BOOTSECT.OLD";
2416
2417 BootSectorFileName = L"\\bootsect.old";
2418 }
2419
2420 /* Create or update 'freeldr.ini' */
2421 if (DoesFreeLdrExist == FALSE)
2422 {
2423 /* Create new 'freeldr.ini' */
2424 DPRINT1("Create new 'freeldr.ini'\n");
2425 // wcscpy(DstPath, SystemRootPath->Buffer);
2426 // wcscat(DstPath, L"\\freeldr.ini");
2427
2428 if (IsThereAValidBootSector(SystemRootPath->Buffer))
2429 {
2430 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2431 DstPath, DestinationArcPath->Buffer,
2432 Section, Description,
2433 BootDrive, BootPartition, BootSector);
2434 if (!NT_SUCCESS(Status))
2435 {
2436 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2437 return Status;
2438 }
2439
2440 /* Save current bootsector */
2441 wcscpy(DstPath, SystemRootPath->Buffer);
2442 wcscat(DstPath, BootSectorFileName);
2443
2444 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2445 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE);
2446 if (!NT_SUCCESS(Status))
2447 {
2448 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
2449 return Status;
2450 }
2451 }
2452 else
2453 {
2454 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2455 if (!NT_SUCCESS(Status))
2456 {
2457 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2458 return Status;
2459 }
2460 }
2461
2462 /* Install new bootsector on the disk */
2463 if (PartitionType == PARTITION_FAT32 ||
2464 PartitionType == PARTITION_FAT32_XINT13)
2465 {
2466 /* Install FAT32 bootcode */
2467 wcscpy(SrcPath, SourceRootPath->Buffer);
2468 wcscat(SrcPath, L"\\loader\\fat32.bin");
2469
2470 DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2471 Status = InstallFat32BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2472 if (!NT_SUCCESS(Status))
2473 {
2474 DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
2475 return Status;
2476 }
2477 }
2478 else
2479 {
2480 /* Install FAT16 bootcode */
2481 wcscpy(SrcPath, SourceRootPath->Buffer);
2482 wcscat(SrcPath, L"\\loader\\fat.bin");
2483
2484 DPRINT1("Install FAT16 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2485 Status = InstallFat16BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2486 if (!NT_SUCCESS(Status))
2487 {
2488 DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2489 return Status;
2490 }
2491 }
2492 }
2493 }
2494
2495 return STATUS_SUCCESS;
2496 }
2497
2498 static
2499 NTSTATUS
2500 InstallExt2BootcodeToPartition(
2501 PUNICODE_STRING SystemRootPath,
2502 PUNICODE_STRING SourceRootPath,
2503 PUNICODE_STRING DestinationArcPath,
2504 UCHAR PartitionType)
2505 {
2506 NTSTATUS Status;
2507 BOOLEAN DoesFreeLdrExist;
2508 WCHAR SrcPath[MAX_PATH];
2509 WCHAR DstPath[MAX_PATH];
2510
2511 /* EXT2 partition */
2512 DPRINT("System path: '%wZ'\n", SystemRootPath);
2513
2514 /* Copy FreeLoader to the system partition */
2515 wcscpy(SrcPath, SourceRootPath->Buffer);
2516 wcscat(SrcPath, L"\\loader\\freeldr.sys");
2517 wcscpy(DstPath, SystemRootPath->Buffer);
2518 wcscat(DstPath, L"\\freeldr.sys");
2519
2520 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2521 Status = SetupCopyFile(SrcPath, DstPath);
2522 if (!NT_SUCCESS(Status))
2523 {
2524 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2525 return Status;
2526 }
2527
2528 /* Prepare for possibly copying 'freeldr.ini' */
2529 wcscpy(DstPath, SystemRootPath->Buffer);
2530 wcscat(DstPath, L"\\freeldr.ini");
2531
2532 DoesFreeLdrExist = DoesFileExist(NULL, SystemRootPath->Buffer, L"freeldr.ini");
2533 if (DoesFreeLdrExist)
2534 {
2535 /* Update existing 'freeldr.ini' */
2536 DPRINT1("Update existing 'freeldr.ini'\n");
2537
2538 Status = UpdateFreeLoaderIni(DstPath, DestinationArcPath->Buffer);
2539 if (!NT_SUCCESS(Status))
2540 {
2541 DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2542 return Status;
2543 }
2544 }
2545
2546 /* Check for *nix bootloaders */
2547
2548 /* Create or update 'freeldr.ini' */
2549 if (DoesFreeLdrExist == FALSE)
2550 {
2551 /* Create new 'freeldr.ini' */
2552 DPRINT1("Create new 'freeldr.ini'\n");
2553 wcscpy(DstPath, SystemRootPath->Buffer);
2554 wcscat(DstPath, L"\\freeldr.ini");
2555
2556 /* Certainly SysLinux, GRUB, LILO... or an unknown boot loader */
2557 DPRINT1("*nix or unknown boot loader found\n");
2558
2559 if (IsThereAValidBootSector(SystemRootPath->Buffer))
2560 {
2561 Status = CreateFreeLoaderIniForReactOSAndBootSector(
2562 DstPath, DestinationArcPath->Buffer,
2563 L"Linux", L"\"Linux\"",
2564 L"hd0", L"1", L"BOOTSECT.OLD");
2565 if (!NT_SUCCESS(Status))
2566 {
2567 DPRINT1("CreateFreeLoaderIniForReactOSAndBootSector() failed (Status %lx)\n", Status);
2568 return Status;
2569 }
2570
2571 /* Save current bootsector */
2572 wcscpy(DstPath, SystemRootPath->Buffer);
2573 wcscat(DstPath, L"\\bootsect.old");
2574
2575 DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath);
2576 Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(EXT2_BOOTSECTOR));
2577 if (!NT_SUCCESS(Status))
2578 {
2579 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
2580 return Status;
2581 }
2582 }
2583 else
2584 {
2585 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2586 if (!NT_SUCCESS(Status))
2587 {
2588 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2589 return Status;
2590 }
2591 }
2592
2593 /* Install new bootsector on the disk */
2594 // if (PartitionType == PARTITION_EXT2)
2595 {
2596 /* Install EXT2 bootcode */
2597 wcscpy(SrcPath, SourceRootPath->Buffer);
2598 wcscat(SrcPath, L"\\loader\\ext2.bin");
2599
2600 DPRINT1("Install EXT2 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer);
2601 Status = InstallExt2BootCodeToDisk(SrcPath, SystemRootPath->Buffer);
2602 if (!NT_SUCCESS(Status))
2603 {
2604 DPRINT1("InstallExt2BootCodeToDisk() failed (Status %lx)\n", Status);
2605 return Status;
2606 }
2607 }
2608 }
2609
2610 return STATUS_SUCCESS;
2611 }
2612
2613
2614 NTSTATUS
2615 InstallVBRToPartition(
2616 PUNICODE_STRING SystemRootPath,
2617 PUNICODE_STRING SourceRootPath,
2618 PUNICODE_STRING DestinationArcPath,
2619 UCHAR PartitionType)
2620 {
2621 switch (PartitionType)
2622 {
2623 case PARTITION_FAT_12:
2624 case PARTITION_FAT_16:
2625 case PARTITION_HUGE:
2626 case PARTITION_XINT13:
2627 case PARTITION_FAT32:
2628 case PARTITION_FAT32_XINT13:
2629 {
2630 return InstallFatBootcodeToPartition(SystemRootPath,
2631 SourceRootPath,
2632 DestinationArcPath,
2633 PartitionType);
2634 }
2635
2636 case PARTITION_EXT2:
2637 {
2638 return InstallExt2BootcodeToPartition(SystemRootPath,
2639 SourceRootPath,
2640 DestinationArcPath,
2641 PartitionType);
2642 }
2643
2644 case PARTITION_IFS:
2645 break;
2646
2647 default:
2648 DPRINT1("PartitionType 0x%02X unknown!\n", PartitionType);
2649 break;
2650 }
2651
2652 return STATUS_UNSUCCESSFUL;
2653 }
2654
2655
2656 NTSTATUS
2657 InstallFatBootcodeToFloppy(
2658 PUNICODE_STRING SourceRootPath,
2659 PUNICODE_STRING DestinationArcPath)
2660 {
2661 NTSTATUS Status;
2662 PFILE_SYSTEM FatFS;
2663 UNICODE_STRING FloppyDevice = RTL_CONSTANT_STRING(L"\\Device\\Floppy0");
2664 WCHAR SrcPath[MAX_PATH];
2665 WCHAR DstPath[MAX_PATH];
2666
2667 /* Format the floppy first */
2668 FatFS = GetFileSystemByName(L"FAT");
2669 if (!FatFS)
2670 {
2671 DPRINT1("FAT FS non existent on this system?!\n");
2672 return STATUS_NOT_SUPPORTED;
2673 }
2674 Status = FatFS->FormatFunc(&FloppyDevice,
2675 FMIFS_FLOPPY,
2676 NULL,
2677 TRUE,
2678 0,
2679 NULL);
2680 if (!NT_SUCCESS(Status))
2681 {
2682 DPRINT1("VfatFormat() failed (Status %lx)\n", Status);
2683 return Status;
2684 }
2685
2686 /* Copy FreeLoader to the boot partition */
2687 wcscpy(SrcPath, SourceRootPath->Buffer);
2688 wcscat(SrcPath, L"\\loader\\freeldr.sys");
2689
2690 wcscpy(DstPath, L"\\Device\\Floppy0\\freeldr.sys");
2691
2692 DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2693 Status = SetupCopyFile(SrcPath, DstPath);
2694 if (!NT_SUCCESS(Status))
2695 {
2696 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2697 return Status;
2698 }
2699
2700 /* Create new 'freeldr.ini' */
2701 wcscpy(DstPath, L"\\Device\\Floppy0\\freeldr.ini");
2702
2703 DPRINT("Create new 'freeldr.ini'\n");
2704 Status = CreateFreeLoaderIniForReactOS(DstPath, DestinationArcPath->Buffer);
2705 if (!NT_SUCCESS(Status))
2706 {
2707 DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status);
2708 return Status;
2709 }
2710
2711 /* Install FAT12/16 boosector */
2712 wcscpy(SrcPath, SourceRootPath->Buffer);
2713 wcscat(SrcPath, L"\\loader\\fat.bin");
2714
2715 wcscpy(DstPath, L"\\Device\\Floppy0");
2716
2717 DPRINT("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2718 Status = InstallFat12BootCodeToFloppy(SrcPath, DstPath);
2719 if (!NT_SUCCESS(Status))
2720 {
2721 DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2722 return Status;
2723 }
2724
2725 return STATUS_SUCCESS;
2726 }
2727
2728 /* EOF */