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