update for HEAD-2003021201
[reactos.git] / subsys / system / usetup / bootsup.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2002 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * COPYRIGHT:       See COPYING in the top level directory
21  * PROJECT:         ReactOS text-mode setup
22  * FILE:            subsys/system/usetup/bootsup.c
23  * PURPOSE:         Bootloader support functions
24  * PROGRAMMER:      Eric Kohl
25  */
26
27 #include <ddk/ntddk.h>
28 #include <ntdll/rtl.h>
29
30 #include "usetup.h"
31 #include "inicache.h"
32 #include "bootsup.h"
33
34
35 #define SECTORSIZE 512
36
37 /* FUNCTIONS ****************************************************************/
38
39
40 static VOID
41 CreateCommonFreeLoaderSections(PINICACHE IniCache)
42 {
43   PINICACHESECTION IniSection;
44
45   /* Create "FREELOADER" section */
46   IniSection = IniCacheAppendSection(IniCache,
47                                      L"FREELOADER");
48
49   /* DefaultOS=ReactOS */
50   IniCacheInsertKey(IniSection,
51                     NULL,
52                     INSERT_LAST,
53                     L"DefaultOS",
54                     L"ReactOS");
55
56 #if 0
57   /* Timeout=10 */
58   IniCacheInsertKey(IniSection,
59                     NULL,
60                     INSERT_LAST,
61                     L"TimeOut",
62                     L"10");
63 #endif
64
65   /* Create "Display" section */
66   IniSection = IniCacheAppendSection(IniCache,
67                                      L"Display");
68
69   /* TitleText=ReactOS Boot Manager */
70   IniCacheInsertKey(IniSection,
71                     NULL,
72                     INSERT_LAST,
73                     L"TitleText",
74                     L"ReactOS Boot Manager");
75
76   /* StatusBarColor=Cyan */
77   IniCacheInsertKey(IniSection,
78                     NULL,
79                     INSERT_LAST,
80                     L"StatusBarColor",
81                     L"Cyan");
82
83   /* StatusBarTextColor=Black */
84   IniCacheInsertKey(IniSection,
85                     NULL,
86                     INSERT_LAST,
87                     L"StatusBarTextColor",
88                     L"Black");
89
90   /* BackdropTextColor=White */
91   IniCacheInsertKey(IniSection,
92                     NULL,
93                     INSERT_LAST,
94                     L"BackdropTextColor",
95                     L"White");
96
97   /* BackdropColor=Blue */
98   IniCacheInsertKey(IniSection,
99                     NULL,
100                     INSERT_LAST,
101                     L"BackdropColor",
102                     L"Blue");
103
104   /* BackdropFillStyle=Medium */
105   IniCacheInsertKey(IniSection,
106                     NULL,
107                     INSERT_LAST,
108                     L"BackdropFillStyle",
109                     L"Medium");
110
111   /* TitleBoxTextColor=White */
112   IniCacheInsertKey(IniSection,
113                     NULL,
114                     INSERT_LAST,
115                     L"TitleBoxTextColor",
116                     L"White");
117
118   /* TitleBoxColor=Red */
119   IniCacheInsertKey(IniSection,
120                     NULL,
121                     INSERT_LAST,
122                     L"TitleBoxColor",
123                     L"Red");
124
125   /* MessageBoxTextColor=White */
126   IniCacheInsertKey(IniSection,
127                     NULL,
128                     INSERT_LAST,
129                     L"MessageBoxTextColor",
130                     L"White");
131
132   /* MessageBoxColor=Blue */
133   IniCacheInsertKey(IniSection,
134                     NULL,
135                     INSERT_LAST,
136                     L"MessageBoxColor",
137                     L"Blue");
138
139   /* MenuTextColor=White */
140   IniCacheInsertKey(IniSection,
141                     NULL,
142                     INSERT_LAST,
143                     L"MenuTextColor",
144                     L"White");
145
146   /* MenuColor=Blue */
147   IniCacheInsertKey(IniSection,
148                     NULL,
149                     INSERT_LAST,
150                     L"MenuColor",
151                     L"Blue");
152
153   /* TextColor=Yellow */
154   IniCacheInsertKey(IniSection,
155                     NULL,
156                     INSERT_LAST,
157                     L"TextColor",
158                     L"Yellow");
159
160   /* SelectedTextColor=Black */
161   IniCacheInsertKey(IniSection,
162                     NULL,
163                     INSERT_LAST,
164                     L"SelectedTextColor",
165                     L"Black");
166
167   /* SelectedColor=Gray */
168   IniCacheInsertKey(IniSection,
169                     NULL,
170                     INSERT_LAST,
171                     L"SelectedColor",
172                     L"Gray");
173 }
174
175
176 NTSTATUS
177 CreateFreeLoaderIniForDos(PWCHAR IniPath,
178                           PWCHAR ArcPath)
179 {
180   PINICACHE IniCache;
181   PINICACHESECTION IniSection;
182
183   IniCache = IniCacheCreate();
184
185   CreateCommonFreeLoaderSections(IniCache);
186
187   /* Create "Operating Systems" section */
188   IniSection = IniCacheAppendSection(IniCache,
189                                      L"Operating Systems");
190
191   /* REACTOS=ReactOS */
192   IniCacheInsertKey(IniSection,
193                     NULL,
194                     INSERT_LAST,
195                     L"ReactOS",
196                     L"\"ReactOS\"");
197
198   /* ReactOS_Debug="ReactOS (Debug)" */
199   IniCacheInsertKey(IniSection,
200                     NULL,
201                     INSERT_LAST,
202                     L"ReactOS_Debug",
203                     L"\"ReactOS (Debug)\"");
204
205   /* DOS=Dos/Windows */
206   IniCacheInsertKey(IniSection,
207                     NULL,
208                     INSERT_LAST,
209                     L"DOS",
210                     L"\"DOS/Windows\"");
211
212   /* Create "ReactOS" section */
213   IniSection = IniCacheAppendSection(IniCache,
214                                      L"ReactOS");
215
216   /* BootType=ReactOS */
217   IniCacheInsertKey(IniSection,
218                     NULL,
219                     INSERT_LAST,
220                     L"BootType",
221                     L"ReactOS");
222
223   /* SystemPath=<ArcPath> */
224   IniCacheInsertKey(IniSection,
225                     NULL,
226                     INSERT_LAST,
227                     L"SystemPath",
228                     ArcPath);
229
230   /* Create "ReactOS_Debug" section */
231   IniSection = IniCacheAppendSection(IniCache,
232                                      L"ReactOS_Debug");
233
234   /* BootType=ReactOS */
235   IniCacheInsertKey(IniSection,
236                     NULL,
237                     INSERT_LAST,
238                     L"BootType",
239                     L"ReactOS");
240
241   /* SystemPath=<ArcPath> */
242   IniCacheInsertKey(IniSection,
243                     NULL,
244                     INSERT_LAST,
245                     L"SystemPath",
246                     ArcPath);
247
248   /* Options=/DEBUGPORT=SCREEN */
249   IniCacheInsertKey(IniSection,
250                     NULL,
251                     INSERT_LAST,
252                     L"Options",
253                     L"/DEBUGPORT=SCREEN");
254
255   /* Create "DOS" section */
256   IniSection = IniCacheAppendSection(IniCache,
257                                      L"DOS");
258
259   /* BootType=BootSector */
260   IniCacheInsertKey(IniSection,
261                     NULL,
262                     INSERT_LAST,
263                     L"BootType",
264                     L"BootSector");
265
266   /* BootDrive=hd0 */
267   IniCacheInsertKey(IniSection,
268                     NULL,
269                     INSERT_LAST,
270                     L"BootDrive",
271                     L"hd0");
272
273   /* BootPartition=1 */
274   IniCacheInsertKey(IniSection,
275                     NULL,
276                     INSERT_LAST,
277                     L"BootPartition",
278                     L"1");
279
280   /* BootSector=BOOTSECT.DOS */
281   IniCacheInsertKey(IniSection,
282                     NULL,
283                     INSERT_LAST,
284                     L"BootSectorFile",
285                     L"BOOTSECT.DOS");
286
287   IniCacheSave(IniCache, IniPath);
288   IniCacheDestroy(IniCache);
289
290   return(STATUS_SUCCESS);
291 }
292
293
294 NTSTATUS
295 CreateFreeLoaderIniForReactos(PWCHAR IniPath,
296                               PWCHAR ArcPath)
297 {
298   PINICACHE IniCache;
299   PINICACHESECTION IniSection;
300
301   IniCache = IniCacheCreate();
302
303   CreateCommonFreeLoaderSections(IniCache);
304
305   /* Create "Operating Systems" section */
306   IniSection = IniCacheAppendSection(IniCache,
307                                      L"Operating Systems");
308
309   /* ReactOS="ReactOS" */
310   IniCacheInsertKey(IniSection,
311                     NULL,
312                     INSERT_LAST,
313                     L"ReactOS",
314                     L"\"ReactOS\"");
315
316   /* ReactOS_Debug="ReactOS (Debug)" */
317   IniCacheInsertKey(IniSection,
318                     NULL,
319                     INSERT_LAST,
320                     L"ReactOS_Debug",
321                     L"\"ReactOS (Debug)\"");
322
323   /* Create "ReactOS" section */
324   IniSection = IniCacheAppendSection(IniCache,
325                                      L"ReactOS");
326
327   /* BootType=ReactOS */
328   IniCacheInsertKey(IniSection,
329                     NULL,
330                     INSERT_LAST,
331                     L"BootType",
332                     L"ReactOS");
333
334   /* SystemPath=<ArcPath> */
335   IniCacheInsertKey(IniSection,
336                     NULL,
337                     INSERT_LAST,
338                     L"SystemPath",
339                     ArcPath);
340
341   /* Create "ReactOS_Debug" section */
342   IniSection = IniCacheAppendSection(IniCache,
343                                      L"ReactOS_Debug");
344
345   /* BootType=ReactOS */
346   IniCacheInsertKey(IniSection,
347                     NULL,
348                     INSERT_LAST,
349                     L"BootType",
350                     L"ReactOS");
351
352   /* SystemPath=<ArcPath> */
353   IniCacheInsertKey(IniSection,
354                     NULL,
355                     INSERT_LAST,
356                     L"SystemPath",
357                     ArcPath);
358
359   /* Options=/DEBUGPORT=SCREEN */
360   IniCacheInsertKey(IniSection,
361                     NULL,
362                     INSERT_LAST,
363                     L"Options",
364                     L"/DEBUGPORT=SCREEN");
365
366   /* Save the ini file */
367   IniCacheSave(IniCache, IniPath);
368   IniCacheDestroy(IniCache);
369
370   return(STATUS_SUCCESS);
371 }
372
373
374 NTSTATUS
375 UpdateFreeLoaderIni(PWCHAR IniPath,
376                     PWCHAR ArcPath)
377 {
378   UNICODE_STRING Name;
379   PINICACHE IniCache;
380   PINICACHESECTION IniSection;
381   WCHAR SectionName[80];
382   WCHAR OsName[80];
383   PWCHAR KeyData;
384   ULONG i;
385   NTSTATUS Status;
386
387   RtlInitUnicodeString(&Name,
388                        IniPath);
389
390   Status = IniCacheLoad(&IniCache,
391                         &Name,
392                         FALSE);
393   if (!NT_SUCCESS(Status))
394     return(Status);
395
396   /* Get "Operating Systems" section */
397   IniSection = IniCacheGetSection(IniCache,
398                                   L"Operating Systems");
399   if (IniSection == NULL)
400     return(STATUS_UNSUCCESSFUL);
401
402   /* Find an unused section name */
403   i = 1;
404   wcscpy(SectionName, L"ReactOS");
405   wcscpy(OsName, L"\"ReactOS\"");
406   while(TRUE)
407   {
408     Status = IniCacheGetKey(IniSection,
409                             SectionName,
410                             &KeyData);
411     if (!NT_SUCCESS(Status))
412       break;
413
414     swprintf(SectionName, L"ReactOS_%lu", i);
415     swprintf(OsName, L"\"ReactOS %lu\"", i);
416     i++;
417   }
418
419   /* <SectionName>=<OsName> */
420   IniCacheInsertKey(IniSection,
421                     NULL,
422                     INSERT_LAST,
423                     SectionName,
424                     OsName);
425
426   /* Create <SectionName> section */
427   IniSection = IniCacheAppendSection(IniCache,
428                                      SectionName);
429
430   /* BootType=ReactOS */
431   IniCacheInsertKey(IniSection,
432                     NULL,
433                     INSERT_LAST,
434                     L"BootType",
435                     L"ReactOS");
436
437   /* SystemPath=<ArcPath> */
438   IniCacheInsertKey(IniSection,
439                     NULL,
440                     INSERT_LAST,
441                     L"SystemPath",
442                     ArcPath);
443
444   IniCacheSave(IniCache, IniPath);
445   IniCacheDestroy(IniCache);
446
447   return(STATUS_SUCCESS);
448 }
449
450
451 NTSTATUS
452 SaveCurrentBootSector(PWSTR RootPath,
453                       PWSTR DstPath)
454 {
455   OBJECT_ATTRIBUTES ObjectAttributes;
456   IO_STATUS_BLOCK IoStatusBlock;
457   UNICODE_STRING Name;
458   HANDLE FileHandle;
459   NTSTATUS Status;
460   PUCHAR BootSector;
461
462   /* Allocate buffer for bootsector */
463   BootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
464                                        0,
465                                        SECTORSIZE);
466   if (BootSector == NULL)
467     return(STATUS_INSUFFICIENT_RESOURCES);
468
469   /* Read current boot sector into buffer */
470   RtlInitUnicodeString(&Name,
471                        RootPath);
472
473   InitializeObjectAttributes(&ObjectAttributes,
474                              &Name,
475                              OBJ_CASE_INSENSITIVE,
476                              NULL,
477                              NULL);
478
479   Status = NtOpenFile(&FileHandle,
480                       FILE_READ_ACCESS,
481                       &ObjectAttributes,
482                       &IoStatusBlock,
483                       0,
484                       FILE_SYNCHRONOUS_IO_ALERT);
485   if (!NT_SUCCESS(Status))
486   {
487     RtlFreeHeap(ProcessHeap, 0, BootSector);
488     return(Status);
489   }
490
491   Status = NtReadFile(FileHandle,
492                       NULL,
493                       NULL,
494                       NULL,
495                       &IoStatusBlock,
496                       BootSector,
497                       SECTORSIZE,
498                       NULL,
499                       NULL);
500   NtClose(FileHandle);
501   if (!NT_SUCCESS(Status))
502   {
503     RtlFreeHeap(ProcessHeap, 0, BootSector);
504     return(Status);
505   }
506
507   /* Write bootsector to DstPath */
508   RtlInitUnicodeString(&Name,
509                        DstPath);
510
511   InitializeObjectAttributes(&ObjectAttributes,
512                              &Name,
513                              0,
514                              NULL,
515                              NULL);
516
517   Status = NtCreateFile(&FileHandle,
518                         FILE_WRITE_ACCESS,
519                         &ObjectAttributes,
520                         &IoStatusBlock,
521                         NULL,
522                         FILE_ATTRIBUTE_NORMAL,
523                         0,
524                         FILE_SUPERSEDE,
525                         FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
526                         NULL,
527                         0);
528   if (!NT_SUCCESS(Status))
529   {
530     RtlFreeHeap(ProcessHeap, 0, BootSector);
531     return(Status);
532   }
533
534   Status = NtWriteFile(FileHandle,
535                        NULL,
536                        NULL,
537                        NULL,
538                        &IoStatusBlock,
539                        BootSector,
540                        SECTORSIZE,
541                        NULL,
542                        NULL);
543   NtClose(FileHandle);
544
545   /* Free the new boot sector */
546   RtlFreeHeap(ProcessHeap, 0, BootSector);
547
548   return(Status);
549 }
550
551
552 NTSTATUS
553 InstallFat16BootCodeToFile(PWSTR SrcPath,
554                            PWSTR DstPath,
555                            PWSTR RootPath)
556 {
557   OBJECT_ATTRIBUTES ObjectAttributes;
558   IO_STATUS_BLOCK IoStatusBlock;
559   UNICODE_STRING Name;
560   HANDLE FileHandle;
561   NTSTATUS Status;
562   PUCHAR OrigBootSector;
563   PUCHAR NewBootSector;
564
565   /* Allocate buffer for original bootsector */
566   OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
567                                            0,
568                                            SECTORSIZE);
569   if (OrigBootSector == NULL)
570     return(STATUS_INSUFFICIENT_RESOURCES);
571
572   /* Read current boot sector into buffer */
573   RtlInitUnicodeString(&Name,
574                        RootPath);
575
576   InitializeObjectAttributes(&ObjectAttributes,
577                              &Name,
578                              OBJ_CASE_INSENSITIVE,
579                              NULL,
580                              NULL);
581
582   Status = NtOpenFile(&FileHandle,
583                       FILE_READ_ACCESS,
584                       &ObjectAttributes,
585                       &IoStatusBlock,
586                       0,
587                       FILE_SYNCHRONOUS_IO_ALERT);
588   if (!NT_SUCCESS(Status))
589   {
590     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
591     return(Status);
592   }
593
594   Status = NtReadFile(FileHandle,
595                       NULL,
596                       NULL,
597                       NULL,
598                       &IoStatusBlock,
599                       OrigBootSector,
600                       SECTORSIZE,
601                       NULL,
602                       NULL);
603   NtClose(FileHandle);
604   if (!NT_SUCCESS(Status))
605   {
606     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
607     return(Status);
608   }
609
610
611   /* Allocate buffer for new bootsector */
612   NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
613                                           0,
614                                           SECTORSIZE);
615   if (NewBootSector == NULL)
616   {
617     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
618     return(STATUS_INSUFFICIENT_RESOURCES);
619   }
620
621   /* Read new bootsector from SrcPath */
622   RtlInitUnicodeString(&Name,
623                        SrcPath);
624
625   InitializeObjectAttributes(&ObjectAttributes,
626                              &Name,
627                              OBJ_CASE_INSENSITIVE,
628                              NULL,
629                              NULL);
630
631   Status = NtOpenFile(&FileHandle,
632                       FILE_READ_ACCESS,
633                       &ObjectAttributes,
634                       &IoStatusBlock,
635                       0,
636                       FILE_SYNCHRONOUS_IO_ALERT);
637   if (!NT_SUCCESS(Status))
638   {
639     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
640     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
641     return(Status);
642   }
643
644   Status = NtReadFile(FileHandle,
645                       NULL,
646                       NULL,
647                       NULL,
648                       &IoStatusBlock,
649                       NewBootSector,
650                       SECTORSIZE,
651                       NULL,
652                       NULL);
653   NtClose(FileHandle);
654   if (!NT_SUCCESS(Status))
655   {
656     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
657     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
658     return(Status);
659   }
660
661   /* Adjust bootsector (copy a part of the FAT BPB) */
662   memcpy((NewBootSector + 11), (OrigBootSector + 11), 51 /*fat BPB length*/);
663
664   /* Free the original boot sector */
665   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
666
667   /* Write new bootsector to DstPath */
668   RtlInitUnicodeString(&Name,
669                        DstPath);
670
671   InitializeObjectAttributes(&ObjectAttributes,
672                              &Name,
673                              0,
674                              NULL,
675                              NULL);
676
677   Status = NtCreateFile(&FileHandle,
678                         FILE_WRITE_ACCESS,
679                         &ObjectAttributes,
680                         &IoStatusBlock,
681                         NULL,
682                         FILE_ATTRIBUTE_NORMAL,
683                         0,
684                         FILE_OVERWRITE_IF,
685                         FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
686                         NULL,
687                         0);
688   if (!NT_SUCCESS(Status))
689   {
690     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
691     return(Status);
692   }
693
694 #if 0
695   FilePosition.QuadPart = 0;
696 #endif
697   Status = NtWriteFile(FileHandle,
698                        NULL,
699                        NULL,
700                        NULL,
701                        &IoStatusBlock,
702                        NewBootSector,
703                        SECTORSIZE,
704                        NULL,
705                        NULL);
706   NtClose(FileHandle);
707
708   /* Free the new boot sector */
709   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
710
711   return(Status);
712 }
713
714
715 NTSTATUS
716 InstallFat32BootCodeToFile(PWSTR SrcPath,
717                            PWSTR DstPath,
718                            PWSTR RootPath)
719 {
720   OBJECT_ATTRIBUTES ObjectAttributes;
721   IO_STATUS_BLOCK IoStatusBlock;
722   UNICODE_STRING Name;
723   HANDLE FileHandle;
724   NTSTATUS Status;
725   PUCHAR OrigBootSector;
726   PUCHAR NewBootSector;
727   LARGE_INTEGER FileOffset;
728
729   /* Allocate buffer for original bootsector */
730   OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
731                                            0,
732                                            SECTORSIZE);
733   if (OrigBootSector == NULL)
734     return(STATUS_INSUFFICIENT_RESOURCES);
735
736   /* Read current boot sector into buffer */
737   RtlInitUnicodeString(&Name,
738                        RootPath);
739
740   InitializeObjectAttributes(&ObjectAttributes,
741                              &Name,
742                              OBJ_CASE_INSENSITIVE,
743                              NULL,
744                              NULL);
745
746   Status = NtOpenFile(&FileHandle,
747                       FILE_READ_ACCESS,
748                       &ObjectAttributes,
749                       &IoStatusBlock,
750                       0,
751                       FILE_SYNCHRONOUS_IO_ALERT);
752   if (!NT_SUCCESS(Status))
753   {
754     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
755     return(Status);
756   }
757
758   Status = NtReadFile(FileHandle,
759                       NULL,
760                       NULL,
761                       NULL,
762                       &IoStatusBlock,
763                       OrigBootSector,
764                       SECTORSIZE,
765                       NULL,
766                       NULL);
767   NtClose(FileHandle);
768   if (!NT_SUCCESS(Status))
769   {
770 CHECKPOINT1;
771     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
772     return(Status);
773   }
774
775   /* Allocate buffer for new bootsector (2 sectors) */
776   NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
777                                           0,
778                                           2 * SECTORSIZE);
779   if (NewBootSector == NULL)
780   {
781     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
782     return(STATUS_INSUFFICIENT_RESOURCES);
783   }
784
785   /* Read new bootsector from SrcPath */
786   RtlInitUnicodeString(&Name,
787                        SrcPath);
788
789   InitializeObjectAttributes(&ObjectAttributes,
790                              &Name,
791                              OBJ_CASE_INSENSITIVE,
792                              NULL,
793                              NULL);
794
795   Status = NtOpenFile(&FileHandle,
796                       FILE_READ_ACCESS,
797                       &ObjectAttributes,
798                       &IoStatusBlock,
799                       0,
800                       FILE_SYNCHRONOUS_IO_ALERT);
801   if (!NT_SUCCESS(Status))
802   {
803     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
804     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
805     return(Status);
806   }
807
808   Status = NtReadFile(FileHandle,
809                       NULL,
810                       NULL,
811                       NULL,
812                       &IoStatusBlock,
813                       NewBootSector,
814                       2 * SECTORSIZE,
815                       NULL,
816                       NULL);
817   NtClose(FileHandle);
818   if (!NT_SUCCESS(Status))
819   {
820     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
821     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
822     return(Status);
823   }
824
825   /* Adjust bootsector (copy a part of the FAT32 BPB) */
826   memcpy((NewBootSector + 3),
827          (OrigBootSector + 3),
828          87); /* FAT32 BPB length */
829
830   /* Disable the backup boot sector */
831   NewBootSector[0x32] = 0xFF;
832   NewBootSector[0x33] = 0xFF;
833
834   /* Free the original boot sector */
835   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
836
837   /* Write the first sector of the new bootcode to DstPath */
838   RtlInitUnicodeString(&Name,
839                        DstPath);
840
841   InitializeObjectAttributes(&ObjectAttributes,
842                              &Name,
843                              0,
844                              NULL,
845                              NULL);
846
847   Status = NtCreateFile(&FileHandle,
848                         FILE_WRITE_ACCESS,
849                         &ObjectAttributes,
850                         &IoStatusBlock,
851                         NULL,
852                         FILE_ATTRIBUTE_NORMAL,
853                         0,
854                         FILE_SUPERSEDE,
855                         FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
856                         NULL,
857                         0);
858   if (!NT_SUCCESS(Status))
859   {
860     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
861     return(Status);
862   }
863
864   Status = NtWriteFile(FileHandle,
865                        NULL,
866                        NULL,
867                        NULL,
868                        &IoStatusBlock,
869                        NewBootSector,
870                        SECTORSIZE,
871                        NULL,
872                        NULL);
873   NtClose(FileHandle);
874   if (!NT_SUCCESS(Status))
875   {
876     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
877     return(Status);
878   }
879
880   /* Write the second sector of the new bootcode to boot disk sector 14 */
881   RtlInitUnicodeString(&Name,
882                        RootPath);
883
884   InitializeObjectAttributes(&ObjectAttributes,
885                              &Name,
886                              0,
887                              NULL,
888                              NULL);
889
890   Status = NtOpenFile(&FileHandle,
891                       FILE_WRITE_ACCESS,
892                       &ObjectAttributes,
893                       &IoStatusBlock,
894                       0,
895                       FILE_SYNCHRONOUS_IO_ALERT);
896   if (!NT_SUCCESS(Status))
897   {
898     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
899     return(Status);
900   }
901
902   FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE);
903   Status = NtWriteFile(FileHandle,
904                        NULL,
905                        NULL,
906                        NULL,
907                        &IoStatusBlock,
908                        (NewBootSector + SECTORSIZE),
909                        SECTORSIZE,
910                        &FileOffset,
911                        NULL);
912   if (!NT_SUCCESS(Status))
913   {
914   }
915   NtClose(FileHandle);
916
917   /* Free the new boot sector */
918   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
919
920   return(Status);
921 }
922
923
924 NTSTATUS
925 InstallFat16BootCodeToDisk(PWSTR SrcPath,
926                            PWSTR RootPath)
927 {
928   OBJECT_ATTRIBUTES ObjectAttributes;
929   IO_STATUS_BLOCK IoStatusBlock;
930   UNICODE_STRING Name;
931   HANDLE FileHandle;
932   NTSTATUS Status;
933   PUCHAR OrigBootSector;
934   PUCHAR NewBootSector;
935
936   /* Allocate buffer for original bootsector */
937   OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
938                                            0,
939                                            SECTORSIZE);
940   if (OrigBootSector == NULL)
941     return(STATUS_INSUFFICIENT_RESOURCES);
942
943   /* Read current boot sector into buffer */
944   RtlInitUnicodeString(&Name,
945                        RootPath);
946
947   InitializeObjectAttributes(&ObjectAttributes,
948                              &Name,
949                              OBJ_CASE_INSENSITIVE,
950                              NULL,
951                              NULL);
952
953   Status = NtOpenFile(&FileHandle,
954                       FILE_READ_ACCESS,
955                       &ObjectAttributes,
956                       &IoStatusBlock,
957                       0,
958                       FILE_SYNCHRONOUS_IO_ALERT);
959   if (!NT_SUCCESS(Status))
960   {
961     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
962     return(Status);
963   }
964
965   Status = NtReadFile(FileHandle,
966                       NULL,
967                       NULL,
968                       NULL,
969                       &IoStatusBlock,
970                       OrigBootSector,
971                       SECTORSIZE,
972                       NULL,
973                       NULL);
974   NtClose(FileHandle);
975   if (!NT_SUCCESS(Status))
976   {
977     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
978     return(Status);
979   }
980
981
982   /* Allocate buffer for new bootsector */
983   NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
984                                           0,
985                                           SECTORSIZE);
986   if (NewBootSector == NULL)
987   {
988     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
989     return(STATUS_INSUFFICIENT_RESOURCES);
990   }
991
992   /* Read new bootsector from SrcPath */
993   RtlInitUnicodeString(&Name,
994                        SrcPath);
995
996   InitializeObjectAttributes(&ObjectAttributes,
997                              &Name,
998                              OBJ_CASE_INSENSITIVE,
999                              NULL,
1000                              NULL);
1001
1002   Status = NtOpenFile(&FileHandle,
1003                       FILE_READ_ACCESS,
1004                       &ObjectAttributes,
1005                       &IoStatusBlock,
1006                       0,
1007                       FILE_SYNCHRONOUS_IO_ALERT);
1008   if (!NT_SUCCESS(Status))
1009   {
1010     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1011     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1012     return(Status);
1013   }
1014
1015   Status = NtReadFile(FileHandle,
1016                       NULL,
1017                       NULL,
1018                       NULL,
1019                       &IoStatusBlock,
1020                       NewBootSector,
1021                       SECTORSIZE,
1022                       NULL,
1023                       NULL);
1024   NtClose(FileHandle);
1025   if (!NT_SUCCESS(Status))
1026   {
1027     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1028     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1029     return(Status);
1030   }
1031
1032   /* Adjust bootsector (copy a part of the FAT BPB) */
1033   memcpy((NewBootSector + 11), (OrigBootSector + 11), 51 /*fat BPB length*/);
1034
1035   /* Free the original boot sector */
1036   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1037
1038   /* Write new bootsector to RootPath */
1039   RtlInitUnicodeString(&Name,
1040                        RootPath);
1041
1042   InitializeObjectAttributes(&ObjectAttributes,
1043                              &Name,
1044                              0,
1045                              NULL,
1046                              NULL);
1047
1048   Status = NtCreateFile(&FileHandle,
1049                         FILE_WRITE_ACCESS,
1050                         &ObjectAttributes,
1051                         &IoStatusBlock,
1052                         NULL,
1053                         FILE_ATTRIBUTE_NORMAL,
1054                         0,
1055                         FILE_OVERWRITE_IF,
1056                         FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
1057                         NULL,
1058                         0);
1059   if (!NT_SUCCESS(Status))
1060   {
1061     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1062     return(Status);
1063   }
1064
1065 #if 0
1066   FilePosition.QuadPart = 0;
1067 #endif
1068   Status = NtWriteFile(FileHandle,
1069                        NULL,
1070                        NULL,
1071                        NULL,
1072                        &IoStatusBlock,
1073                        NewBootSector,
1074                        SECTORSIZE,
1075                        NULL,
1076                        NULL);
1077   NtClose(FileHandle);
1078
1079   /* Free the new boot sector */
1080   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1081
1082   return(Status);
1083 }
1084
1085
1086 NTSTATUS
1087 InstallFat32BootCodeToDisk(PWSTR SrcPath,
1088                            PWSTR RootPath)
1089 {
1090   OBJECT_ATTRIBUTES ObjectAttributes;
1091   IO_STATUS_BLOCK IoStatusBlock;
1092   UNICODE_STRING Name;
1093   HANDLE FileHandle;
1094   NTSTATUS Status;
1095   PUCHAR OrigBootSector;
1096   PUCHAR NewBootSector;
1097   LARGE_INTEGER FileOffset;
1098   USHORT BackupBootSector;
1099
1100   /* Allocate buffer for original bootsector */
1101   OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
1102                                            0,
1103                                            SECTORSIZE);
1104   if (OrigBootSector == NULL)
1105     return(STATUS_INSUFFICIENT_RESOURCES);
1106
1107   /* Read current boot sector into buffer */
1108   RtlInitUnicodeString(&Name,
1109                        RootPath);
1110
1111   InitializeObjectAttributes(&ObjectAttributes,
1112                              &Name,
1113                              OBJ_CASE_INSENSITIVE,
1114                              NULL,
1115                              NULL);
1116
1117   Status = NtOpenFile(&FileHandle,
1118                       FILE_READ_ACCESS,
1119                       &ObjectAttributes,
1120                       &IoStatusBlock,
1121                       0,
1122                       FILE_SYNCHRONOUS_IO_ALERT);
1123   if (!NT_SUCCESS(Status))
1124   {
1125     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1126     return(Status);
1127   }
1128
1129   Status = NtReadFile(FileHandle,
1130                       NULL,
1131                       NULL,
1132                       NULL,
1133                       &IoStatusBlock,
1134                       OrigBootSector,
1135                       SECTORSIZE,
1136                       NULL,
1137                       NULL);
1138   NtClose(FileHandle);
1139   if (!NT_SUCCESS(Status))
1140   {
1141     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1142     return(Status);
1143   }
1144
1145
1146   /* Allocate buffer for new bootsector (2 sectors) */
1147   NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
1148                                           0,
1149                                           2 * SECTORSIZE);
1150   if (NewBootSector == NULL)
1151   {
1152     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1153     return(STATUS_INSUFFICIENT_RESOURCES);
1154   }
1155
1156   /* Read new bootsector from SrcPath */
1157   RtlInitUnicodeString(&Name,
1158                        SrcPath);
1159
1160   InitializeObjectAttributes(&ObjectAttributes,
1161                              &Name,
1162                              OBJ_CASE_INSENSITIVE,
1163                              NULL,
1164                              NULL);
1165
1166   Status = NtOpenFile(&FileHandle,
1167                       FILE_READ_ACCESS,
1168                       &ObjectAttributes,
1169                       &IoStatusBlock,
1170                       0,
1171                       FILE_SYNCHRONOUS_IO_ALERT);
1172   if (!NT_SUCCESS(Status))
1173   {
1174     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1175     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1176     return(Status);
1177   }
1178
1179   Status = NtReadFile(FileHandle,
1180                       NULL,
1181                       NULL,
1182                       NULL,
1183                       &IoStatusBlock,
1184                       NewBootSector,
1185                       2 * SECTORSIZE,
1186                       NULL,
1187                       NULL);
1188   NtClose(FileHandle);
1189   if (!NT_SUCCESS(Status))
1190   {
1191     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1192     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1193     return(Status);
1194   }
1195
1196   /* Adjust bootsector (copy a part of the FAT32 BPB) */
1197   memcpy((NewBootSector + 3),
1198          (OrigBootSector + 3),
1199          87); /* FAT32 BPB length */
1200
1201   /* Get the location of the backup boot sector */
1202   BackupBootSector = (OrigBootSector[0x33] << 8) + OrigBootSector[0x33];
1203
1204   /* Free the original boot sector */
1205   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1206
1207   /* Write the first sector of the new bootcode to DstPath */
1208   RtlInitUnicodeString(&Name,
1209                        RootPath);
1210
1211   InitializeObjectAttributes(&ObjectAttributes,
1212                              &Name,
1213                              0,
1214                              NULL,
1215                              NULL);
1216
1217   Status = NtOpenFile(&FileHandle,
1218                       FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES,
1219                       &ObjectAttributes,
1220                       &IoStatusBlock,
1221                       0,
1222                       FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY);
1223   if (!NT_SUCCESS(Status))
1224   {
1225     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1226     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1227     return(Status);
1228   }
1229
1230   /* Write sector 0 */
1231   FileOffset.QuadPart = 0ULL;
1232   Status = NtWriteFile(FileHandle,
1233                        NULL,
1234                        NULL,
1235                        NULL,
1236                        &IoStatusBlock,
1237                        NewBootSector,
1238                        SECTORSIZE,
1239                        &FileOffset,
1240                        NULL);
1241   if (!NT_SUCCESS(Status))
1242   {
1243     DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1244     NtClose(FileHandle);
1245     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1246     return(Status);
1247   }
1248
1249   /* Write backup boot sector */
1250   if (BackupBootSector != 0xFFFF)
1251   {
1252     FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1253     Status = NtWriteFile(FileHandle,
1254                          NULL,
1255                          NULL,
1256                          NULL,
1257                          &IoStatusBlock,
1258                          NewBootSector,
1259                          SECTORSIZE,
1260                          &FileOffset,
1261                          NULL);
1262     if (!NT_SUCCESS(Status))
1263     {
1264       DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1265       NtClose(FileHandle);
1266       RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1267       return(Status);
1268     }
1269   }
1270
1271   /* Write sector 14 */
1272   FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE);
1273   Status = NtWriteFile(FileHandle,
1274                        NULL,
1275                        NULL,
1276                        NULL,
1277                        &IoStatusBlock,
1278                        (NewBootSector + SECTORSIZE),
1279                        SECTORSIZE,
1280                        &FileOffset,
1281                        NULL);
1282   if (!NT_SUCCESS(Status))
1283   {
1284     DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1285   }
1286   NtClose(FileHandle);
1287
1288   /* Free the new boot sector */
1289   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1290
1291   return(Status);
1292 }
1293
1294
1295 static NTSTATUS
1296 UnprotectBootIni(PWSTR FileName,
1297                  PULONG Attributes)
1298 {
1299   UNICODE_STRING Name;
1300   OBJECT_ATTRIBUTES ObjectAttributes;
1301   IO_STATUS_BLOCK IoStatusBlock;
1302   FILE_BASIC_INFORMATION FileInfo;
1303   HANDLE FileHandle;
1304   NTSTATUS Status;
1305
1306   RtlInitUnicodeString(&Name,
1307                        FileName);
1308
1309   InitializeObjectAttributes(&ObjectAttributes,
1310                              &Name,
1311                              OBJ_CASE_INSENSITIVE,
1312                              NULL,
1313                              NULL);
1314
1315   Status = NtOpenFile(&FileHandle,
1316                       FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
1317                       &ObjectAttributes,
1318                       &IoStatusBlock,
1319                       0,
1320                       FILE_SYNCHRONOUS_IO_ALERT);
1321   if (Status == STATUS_NO_SUCH_FILE)
1322   {
1323     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1324     *Attributes = 0;
1325     return(STATUS_SUCCESS);
1326   }
1327   if (!NT_SUCCESS(Status))
1328   {
1329     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1330     return(Status);
1331   }
1332
1333   Status = NtQueryInformationFile(FileHandle,
1334                                   &IoStatusBlock,
1335                                   &FileInfo,
1336                                   sizeof(FILE_BASIC_INFORMATION),
1337                                   FileBasicInformation);
1338   if (!NT_SUCCESS(Status))
1339   {
1340     DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
1341     NtClose(FileHandle);
1342     return(Status);
1343   }
1344
1345   *Attributes = FileInfo.FileAttributes;
1346
1347   /* Delete attributes SYSTEM, HIDDEN and READONLY */
1348   FileInfo.FileAttributes = FileInfo.FileAttributes &
1349     ~(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
1350
1351   Status = NtSetInformationFile(FileHandle,
1352                                 &IoStatusBlock,
1353                                 &FileInfo,
1354                                 sizeof(FILE_BASIC_INFORMATION),
1355                                 FileBasicInformation);
1356   if (!NT_SUCCESS(Status))
1357   {
1358     DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
1359   }
1360
1361   NtClose(FileHandle);
1362   return(Status);
1363 }
1364
1365
1366 static NTSTATUS
1367 ProtectBootIni(PWSTR FileName,
1368                ULONG Attributes)
1369 {
1370   UNICODE_STRING Name;
1371   OBJECT_ATTRIBUTES ObjectAttributes;
1372   IO_STATUS_BLOCK IoStatusBlock;
1373   FILE_BASIC_INFORMATION FileInfo;
1374   HANDLE FileHandle;
1375   NTSTATUS Status;
1376
1377   RtlInitUnicodeString(&Name,
1378                        FileName);
1379
1380   InitializeObjectAttributes(&ObjectAttributes,
1381                              &Name,
1382                              OBJ_CASE_INSENSITIVE,
1383                              NULL,
1384                              NULL);
1385
1386   Status = NtOpenFile(&FileHandle,
1387                       FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
1388                       &ObjectAttributes,
1389                       &IoStatusBlock,
1390                       0,
1391                       FILE_SYNCHRONOUS_IO_ALERT);
1392   if (!NT_SUCCESS(Status))
1393   {
1394     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1395     return(Status);
1396   }
1397
1398   Status = NtQueryInformationFile(FileHandle,
1399                                   &IoStatusBlock,
1400                                   &FileInfo,
1401                                   sizeof(FILE_BASIC_INFORMATION),
1402                                   FileBasicInformation);
1403   if (!NT_SUCCESS(Status))
1404   {
1405     DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
1406     NtClose(FileHandle);
1407     return(Status);
1408   }
1409
1410   FileInfo.FileAttributes = FileInfo.FileAttributes | Attributes;
1411
1412   Status = NtSetInformationFile(FileHandle,
1413                                 &IoStatusBlock,
1414                                 &FileInfo,
1415                                 sizeof(FILE_BASIC_INFORMATION),
1416                                 FileBasicInformation);
1417   if (!NT_SUCCESS(Status))
1418   {
1419     DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
1420   }
1421
1422   NtClose(FileHandle);
1423   return(Status);
1424 }
1425
1426
1427 NTSTATUS
1428 UpdateBootIni(PWSTR BootIniPath,
1429               PWSTR EntryName,
1430               PWSTR EntryValue)
1431 {
1432   UNICODE_STRING Name;
1433   PINICACHE Cache = NULL;
1434   PINICACHESECTION Section = NULL;
1435   NTSTATUS Status;
1436   ULONG FileAttribute;
1437
1438   RtlInitUnicodeString(&Name,
1439                        BootIniPath);
1440
1441   Status = IniCacheLoad(&Cache,
1442                         &Name,
1443                         FALSE);
1444   if (!NT_SUCCESS(Status))
1445   {
1446 CHECKPOINT1;
1447     return(Status);
1448   }
1449
1450   Section = IniCacheGetSection(Cache,
1451                                L"operating systems");
1452   if (Section == NULL)
1453   {
1454 CHECKPOINT1;
1455     IniCacheDestroy(Cache);
1456     return(STATUS_UNSUCCESSFUL);
1457   }
1458
1459   IniCacheInsertKey(Section,
1460                     NULL,
1461                     INSERT_LAST,
1462                     EntryName,
1463                     EntryValue);
1464
1465   Status = UnprotectBootIni(BootIniPath,
1466                             &FileAttribute);
1467   if (!NT_SUCCESS(Status))
1468   {
1469 CHECKPOINT1;
1470     IniCacheDestroy(Cache);
1471     return(Status);
1472   }
1473
1474   Status = IniCacheSave(Cache,
1475                         BootIniPath);
1476   if (!NT_SUCCESS(Status))
1477   {
1478 CHECKPOINT1;
1479     IniCacheDestroy(Cache);
1480     return(Status);
1481   }
1482
1483   FileAttribute |= (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
1484   Status = ProtectBootIni(BootIniPath,
1485                           FileAttribute);
1486
1487   IniCacheDestroy(Cache);
1488
1489   return(Status);
1490 }
1491
1492 /* EOF */