a792f3b7b9df330d4325c0eda6a5d3820b0a9bfd
[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] = 0x00;
832   NewBootSector[0x33] = 0x00;
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 InstallMbrBootCodeToDisk (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   /* Copy partition table from old MBR to new */
1033   RtlCopyMemory ((NewBootSector + 446),
1034                  (OrigBootSector + 446),
1035                  4*16 /* Length of partition table */);
1036
1037   /* Free the original boot sector */
1038   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1039
1040   /* Write new bootsector to RootPath */
1041   RtlInitUnicodeString(&Name,
1042                        RootPath);
1043
1044   InitializeObjectAttributes(&ObjectAttributes,
1045                              &Name,
1046                              0,
1047                              NULL,
1048                              NULL);
1049
1050   Status = NtCreateFile(&FileHandle,
1051                         FILE_WRITE_ACCESS,
1052                         &ObjectAttributes,
1053                         &IoStatusBlock,
1054                         NULL,
1055                         FILE_ATTRIBUTE_NORMAL,
1056                         0,
1057                         FILE_OVERWRITE_IF,
1058                         FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
1059                         NULL,
1060                         0);
1061   if (!NT_SUCCESS(Status))
1062   {
1063     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1064     return(Status);
1065   }
1066
1067   Status = NtWriteFile(FileHandle,
1068                        NULL,
1069                        NULL,
1070                        NULL,
1071                        &IoStatusBlock,
1072                        NewBootSector,
1073                        SECTORSIZE,
1074                        NULL,
1075                        NULL);
1076   NtClose(FileHandle);
1077
1078   /* Free the new boot sector */
1079   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1080
1081   return(Status);
1082 }
1083
1084
1085 NTSTATUS
1086 InstallFat16BootCodeToDisk(PWSTR SrcPath,
1087                            PWSTR RootPath)
1088 {
1089   OBJECT_ATTRIBUTES ObjectAttributes;
1090   IO_STATUS_BLOCK IoStatusBlock;
1091   UNICODE_STRING Name;
1092   HANDLE FileHandle;
1093   NTSTATUS Status;
1094   PUCHAR OrigBootSector;
1095   PUCHAR NewBootSector;
1096
1097   /* Allocate buffer for original bootsector */
1098   OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
1099                                            0,
1100                                            SECTORSIZE);
1101   if (OrigBootSector == NULL)
1102     return(STATUS_INSUFFICIENT_RESOURCES);
1103
1104   /* Read current boot sector into buffer */
1105   RtlInitUnicodeString(&Name,
1106                        RootPath);
1107
1108   InitializeObjectAttributes(&ObjectAttributes,
1109                              &Name,
1110                              OBJ_CASE_INSENSITIVE,
1111                              NULL,
1112                              NULL);
1113
1114   Status = NtOpenFile(&FileHandle,
1115                       FILE_READ_ACCESS,
1116                       &ObjectAttributes,
1117                       &IoStatusBlock,
1118                       0,
1119                       FILE_SYNCHRONOUS_IO_ALERT);
1120   if (!NT_SUCCESS(Status))
1121   {
1122     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1123     return(Status);
1124   }
1125
1126   Status = NtReadFile(FileHandle,
1127                       NULL,
1128                       NULL,
1129                       NULL,
1130                       &IoStatusBlock,
1131                       OrigBootSector,
1132                       SECTORSIZE,
1133                       NULL,
1134                       NULL);
1135   NtClose(FileHandle);
1136   if (!NT_SUCCESS(Status))
1137   {
1138     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1139     return(Status);
1140   }
1141
1142
1143   /* Allocate buffer for new bootsector */
1144   NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
1145                                           0,
1146                                           SECTORSIZE);
1147   if (NewBootSector == NULL)
1148   {
1149     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1150     return(STATUS_INSUFFICIENT_RESOURCES);
1151   }
1152
1153   /* Read new bootsector from SrcPath */
1154   RtlInitUnicodeString(&Name,
1155                        SrcPath);
1156
1157   InitializeObjectAttributes(&ObjectAttributes,
1158                              &Name,
1159                              OBJ_CASE_INSENSITIVE,
1160                              NULL,
1161                              NULL);
1162
1163   Status = NtOpenFile(&FileHandle,
1164                       FILE_READ_ACCESS,
1165                       &ObjectAttributes,
1166                       &IoStatusBlock,
1167                       0,
1168                       FILE_SYNCHRONOUS_IO_ALERT);
1169   if (!NT_SUCCESS(Status))
1170   {
1171     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1172     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1173     return(Status);
1174   }
1175
1176   Status = NtReadFile(FileHandle,
1177                       NULL,
1178                       NULL,
1179                       NULL,
1180                       &IoStatusBlock,
1181                       NewBootSector,
1182                       SECTORSIZE,
1183                       NULL,
1184                       NULL);
1185   NtClose(FileHandle);
1186   if (!NT_SUCCESS(Status))
1187   {
1188     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1189     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1190     return(Status);
1191   }
1192
1193   /* Adjust bootsector (copy a part of the FAT16 BPB) */
1194   memcpy((NewBootSector + 3),
1195          (OrigBootSector + 3),
1196          59);  /* FAT16 BPB length*/
1197
1198   /* Free the original boot sector */
1199   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1200
1201   /* Write new bootsector to RootPath */
1202   RtlInitUnicodeString(&Name,
1203                        RootPath);
1204
1205   InitializeObjectAttributes(&ObjectAttributes,
1206                              &Name,
1207                              0,
1208                              NULL,
1209                              NULL);
1210
1211   Status = NtCreateFile(&FileHandle,
1212                         FILE_WRITE_ACCESS,
1213                         &ObjectAttributes,
1214                         &IoStatusBlock,
1215                         NULL,
1216                         FILE_ATTRIBUTE_NORMAL,
1217                         0,
1218                         FILE_OVERWRITE_IF,
1219                         FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
1220                         NULL,
1221                         0);
1222   if (!NT_SUCCESS(Status))
1223   {
1224     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1225     return(Status);
1226   }
1227
1228 #if 0
1229   FilePosition.QuadPart = 0;
1230 #endif
1231   Status = NtWriteFile(FileHandle,
1232                        NULL,
1233                        NULL,
1234                        NULL,
1235                        &IoStatusBlock,
1236                        NewBootSector,
1237                        SECTORSIZE,
1238                        NULL,
1239                        NULL);
1240   NtClose(FileHandle);
1241
1242   /* Free the new boot sector */
1243   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1244
1245   return(Status);
1246 }
1247
1248
1249 NTSTATUS
1250 InstallFat32BootCodeToDisk(PWSTR SrcPath,
1251                            PWSTR RootPath)
1252 {
1253   OBJECT_ATTRIBUTES ObjectAttributes;
1254   IO_STATUS_BLOCK IoStatusBlock;
1255   UNICODE_STRING Name;
1256   HANDLE FileHandle;
1257   NTSTATUS Status;
1258   PUCHAR OrigBootSector;
1259   PUCHAR NewBootSector;
1260   LARGE_INTEGER FileOffset;
1261   USHORT BackupBootSector;
1262
1263   /* Allocate buffer for original bootsector */
1264   OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
1265                                            0,
1266                                            SECTORSIZE);
1267   if (OrigBootSector == NULL)
1268     return(STATUS_INSUFFICIENT_RESOURCES);
1269
1270   /* Read current boot sector into buffer */
1271   RtlInitUnicodeString(&Name,
1272                        RootPath);
1273
1274   InitializeObjectAttributes(&ObjectAttributes,
1275                              &Name,
1276                              OBJ_CASE_INSENSITIVE,
1277                              NULL,
1278                              NULL);
1279
1280   Status = NtOpenFile(&FileHandle,
1281                       FILE_READ_ACCESS,
1282                       &ObjectAttributes,
1283                       &IoStatusBlock,
1284                       0,
1285                       FILE_SYNCHRONOUS_IO_ALERT);
1286   if (!NT_SUCCESS(Status))
1287   {
1288     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1289     return(Status);
1290   }
1291
1292   Status = NtReadFile(FileHandle,
1293                       NULL,
1294                       NULL,
1295                       NULL,
1296                       &IoStatusBlock,
1297                       OrigBootSector,
1298                       SECTORSIZE,
1299                       NULL,
1300                       NULL);
1301   NtClose(FileHandle);
1302   if (!NT_SUCCESS(Status))
1303   {
1304     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1305     return(Status);
1306   }
1307
1308
1309   /* Allocate buffer for new bootsector (2 sectors) */
1310   NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap,
1311                                           0,
1312                                           2 * SECTORSIZE);
1313   if (NewBootSector == NULL)
1314   {
1315     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1316     return(STATUS_INSUFFICIENT_RESOURCES);
1317   }
1318
1319   /* Read new bootsector from SrcPath */
1320   RtlInitUnicodeString(&Name,
1321                        SrcPath);
1322
1323   InitializeObjectAttributes(&ObjectAttributes,
1324                              &Name,
1325                              OBJ_CASE_INSENSITIVE,
1326                              NULL,
1327                              NULL);
1328
1329   Status = NtOpenFile(&FileHandle,
1330                       FILE_READ_ACCESS,
1331                       &ObjectAttributes,
1332                       &IoStatusBlock,
1333                       0,
1334                       FILE_SYNCHRONOUS_IO_ALERT);
1335   if (!NT_SUCCESS(Status))
1336   {
1337     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1338     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1339     return(Status);
1340   }
1341
1342   Status = NtReadFile(FileHandle,
1343                       NULL,
1344                       NULL,
1345                       NULL,
1346                       &IoStatusBlock,
1347                       NewBootSector,
1348                       2 * SECTORSIZE,
1349                       NULL,
1350                       NULL);
1351   NtClose(FileHandle);
1352   if (!NT_SUCCESS(Status))
1353   {
1354     RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1355     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1356     return(Status);
1357   }
1358
1359   /* Adjust bootsector (copy a part of the FAT32 BPB) */
1360   memcpy((NewBootSector + 3),
1361          (OrigBootSector + 3),
1362          87); /* FAT32 BPB length */
1363
1364   /* Get the location of the backup boot sector */
1365   BackupBootSector = (OrigBootSector[0x33] << 8) + OrigBootSector[0x32];
1366
1367   /* Free the original boot sector */
1368   RtlFreeHeap(ProcessHeap, 0, OrigBootSector);
1369
1370   /* Write the first sector of the new bootcode to DstPath */
1371   RtlInitUnicodeString(&Name,
1372                        RootPath);
1373
1374   InitializeObjectAttributes(&ObjectAttributes,
1375                              &Name,
1376                              0,
1377                              NULL,
1378                              NULL);
1379
1380   Status = NtOpenFile(&FileHandle,
1381                       FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES,
1382                       &ObjectAttributes,
1383                       &IoStatusBlock,
1384                       0,
1385                       FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY);
1386   if (!NT_SUCCESS(Status))
1387   {
1388     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1389     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1390     return(Status);
1391   }
1392
1393   /* Write sector 0 */
1394   FileOffset.QuadPart = 0ULL;
1395   Status = NtWriteFile(FileHandle,
1396                        NULL,
1397                        NULL,
1398                        NULL,
1399                        &IoStatusBlock,
1400                        NewBootSector,
1401                        SECTORSIZE,
1402                        &FileOffset,
1403                        NULL);
1404   if (!NT_SUCCESS(Status))
1405   {
1406     DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1407     NtClose(FileHandle);
1408     RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1409     return(Status);
1410   }
1411
1412   /* Write backup boot sector */
1413   if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
1414   {
1415     FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE);
1416     Status = NtWriteFile(FileHandle,
1417                          NULL,
1418                          NULL,
1419                          NULL,
1420                          &IoStatusBlock,
1421                          NewBootSector,
1422                          SECTORSIZE,
1423                          &FileOffset,
1424                          NULL);
1425     if (!NT_SUCCESS(Status))
1426     {
1427       DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1428       NtClose(FileHandle);
1429       RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1430       return(Status);
1431     }
1432   }
1433
1434   /* Write sector 14 */
1435   FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE);
1436   Status = NtWriteFile(FileHandle,
1437                        NULL,
1438                        NULL,
1439                        NULL,
1440                        &IoStatusBlock,
1441                        (NewBootSector + SECTORSIZE),
1442                        SECTORSIZE,
1443                        &FileOffset,
1444                        NULL);
1445   if (!NT_SUCCESS(Status))
1446   {
1447     DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1448   }
1449   NtClose(FileHandle);
1450
1451   /* Free the new boot sector */
1452   RtlFreeHeap(ProcessHeap, 0, NewBootSector);
1453
1454   return(Status);
1455 }
1456
1457
1458 static NTSTATUS
1459 UnprotectBootIni(PWSTR FileName,
1460                  PULONG Attributes)
1461 {
1462   UNICODE_STRING Name;
1463   OBJECT_ATTRIBUTES ObjectAttributes;
1464   IO_STATUS_BLOCK IoStatusBlock;
1465   FILE_BASIC_INFORMATION FileInfo;
1466   HANDLE FileHandle;
1467   NTSTATUS Status;
1468
1469   RtlInitUnicodeString(&Name,
1470                        FileName);
1471
1472   InitializeObjectAttributes(&ObjectAttributes,
1473                              &Name,
1474                              OBJ_CASE_INSENSITIVE,
1475                              NULL,
1476                              NULL);
1477
1478   Status = NtOpenFile(&FileHandle,
1479                       FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
1480                       &ObjectAttributes,
1481                       &IoStatusBlock,
1482                       0,
1483                       FILE_SYNCHRONOUS_IO_ALERT);
1484   if (Status == STATUS_NO_SUCH_FILE)
1485   {
1486     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1487     *Attributes = 0;
1488     return(STATUS_SUCCESS);
1489   }
1490   if (!NT_SUCCESS(Status))
1491   {
1492     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1493     return(Status);
1494   }
1495
1496   Status = NtQueryInformationFile(FileHandle,
1497                                   &IoStatusBlock,
1498                                   &FileInfo,
1499                                   sizeof(FILE_BASIC_INFORMATION),
1500                                   FileBasicInformation);
1501   if (!NT_SUCCESS(Status))
1502   {
1503     DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
1504     NtClose(FileHandle);
1505     return(Status);
1506   }
1507
1508   *Attributes = FileInfo.FileAttributes;
1509
1510   /* Delete attributes SYSTEM, HIDDEN and READONLY */
1511   FileInfo.FileAttributes = FileInfo.FileAttributes &
1512     ~(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
1513
1514   Status = NtSetInformationFile(FileHandle,
1515                                 &IoStatusBlock,
1516                                 &FileInfo,
1517                                 sizeof(FILE_BASIC_INFORMATION),
1518                                 FileBasicInformation);
1519   if (!NT_SUCCESS(Status))
1520   {
1521     DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
1522   }
1523
1524   NtClose(FileHandle);
1525   return(Status);
1526 }
1527
1528
1529 static NTSTATUS
1530 ProtectBootIni(PWSTR FileName,
1531                ULONG Attributes)
1532 {
1533   UNICODE_STRING Name;
1534   OBJECT_ATTRIBUTES ObjectAttributes;
1535   IO_STATUS_BLOCK IoStatusBlock;
1536   FILE_BASIC_INFORMATION FileInfo;
1537   HANDLE FileHandle;
1538   NTSTATUS Status;
1539
1540   RtlInitUnicodeString(&Name,
1541                        FileName);
1542
1543   InitializeObjectAttributes(&ObjectAttributes,
1544                              &Name,
1545                              OBJ_CASE_INSENSITIVE,
1546                              NULL,
1547                              NULL);
1548
1549   Status = NtOpenFile(&FileHandle,
1550                       FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
1551                       &ObjectAttributes,
1552                       &IoStatusBlock,
1553                       0,
1554                       FILE_SYNCHRONOUS_IO_ALERT);
1555   if (!NT_SUCCESS(Status))
1556   {
1557     DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
1558     return(Status);
1559   }
1560
1561   Status = NtQueryInformationFile(FileHandle,
1562                                   &IoStatusBlock,
1563                                   &FileInfo,
1564                                   sizeof(FILE_BASIC_INFORMATION),
1565                                   FileBasicInformation);
1566   if (!NT_SUCCESS(Status))
1567   {
1568     DPRINT1("NtQueryInformationFile() failed (Status %lx)\n", Status);
1569     NtClose(FileHandle);
1570     return(Status);
1571   }
1572
1573   FileInfo.FileAttributes = FileInfo.FileAttributes | Attributes;
1574
1575   Status = NtSetInformationFile(FileHandle,
1576                                 &IoStatusBlock,
1577                                 &FileInfo,
1578                                 sizeof(FILE_BASIC_INFORMATION),
1579                                 FileBasicInformation);
1580   if (!NT_SUCCESS(Status))
1581   {
1582     DPRINT1("NtSetInformationFile() failed (Status %lx)\n", Status);
1583   }
1584
1585   NtClose(FileHandle);
1586   return(Status);
1587 }
1588
1589
1590 NTSTATUS
1591 UpdateBootIni(PWSTR BootIniPath,
1592               PWSTR EntryName,
1593               PWSTR EntryValue)
1594 {
1595   UNICODE_STRING Name;
1596   PINICACHE Cache = NULL;
1597   PINICACHESECTION Section = NULL;
1598   NTSTATUS Status;
1599   ULONG FileAttribute;
1600
1601   RtlInitUnicodeString(&Name,
1602                        BootIniPath);
1603
1604   Status = IniCacheLoad(&Cache,
1605                         &Name,
1606                         FALSE);
1607   if (!NT_SUCCESS(Status))
1608   {
1609 CHECKPOINT1;
1610     return(Status);
1611   }
1612
1613   Section = IniCacheGetSection(Cache,
1614                                L"operating systems");
1615   if (Section == NULL)
1616   {
1617 CHECKPOINT1;
1618     IniCacheDestroy(Cache);
1619     return(STATUS_UNSUCCESSFUL);
1620   }
1621
1622   IniCacheInsertKey(Section,
1623                     NULL,
1624                     INSERT_LAST,
1625                     EntryName,
1626                     EntryValue);
1627
1628   Status = UnprotectBootIni(BootIniPath,
1629                             &FileAttribute);
1630   if (!NT_SUCCESS(Status))
1631   {
1632 CHECKPOINT1;
1633     IniCacheDestroy(Cache);
1634     return(Status);
1635   }
1636
1637   Status = IniCacheSave(Cache,
1638                         BootIniPath);
1639   if (!NT_SUCCESS(Status))
1640   {
1641 CHECKPOINT1;
1642     IniCacheDestroy(Cache);
1643     return(Status);
1644   }
1645
1646   FileAttribute |= (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
1647   Status = ProtectBootIni(BootIniPath,
1648                           FileAttribute);
1649
1650   IniCacheDestroy(Cache);
1651
1652   return(Status);
1653 }
1654
1655 /* EOF */