1 /*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Boot Stores Management functionality, with support for
5 * NT 5.x family (MS Windows <= 2003, and ReactOS) bootloaders.
6 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
7 */
8
9 // TODO: Add support for NT 6.x family! (detection + BCD manipulation).
10
11 /* INCLUDES *****************************************************************/
12
13 #include "precomp.h"
14
15 #include "bldrsup.h"
16 #include "filesup.h"
17 #include "inicache.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 /* GLOBALS ******************************************************************/
24
25 typedef NTSTATUS
26 (*POPEN_BOOT_STORE)(
27 _Out_ PVOID* Handle,
28 _In_ HANDLE PartitionDirectoryHandle, // _In_opt_
29 _In_ BOOT_STORE_TYPE Type,
30 _In_ BOOT_STORE_OPENMODE OpenMode,
31 _In_ BOOT_STORE_ACCESS Access);
32
33 typedef NTSTATUS
34 (*PCLOSE_BOOT_STORE)(
35 _In_ PVOID Handle);
36
37 typedef NTSTATUS
38 (*PENUM_BOOT_STORE_ENTRIES)(
39 IN PVOID Handle,
40 // IN ULONG Flags, // Determine which data to retrieve
41 IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
42 IN PVOID Parameter OPTIONAL);
43
44 typedef struct _NTOS_BOOT_LOADER_FILES
45 {
46 BOOT_STORE_TYPE Type;
47 PCZZWSTR LoaderExecutables;
48 PCWSTR LoaderConfigurationFile;
49 POPEN_BOOT_STORE OpenBootStore;
50 PCLOSE_BOOT_STORE CloseBootStore;
51 PENUM_BOOT_STORE_ENTRIES EnumBootStoreEntries;
52 } NTOS_BOOT_LOADER_FILES, *PNTOS_BOOT_LOADER_FILES;
53
54
55 /*
56 * Header for particular store contexts
57 */
58 typedef struct _BOOT_STORE_CONTEXT
59 {
60 BOOT_STORE_TYPE Type;
61 BOOLEAN ReadOnly;
62 // PNTOS_BOOT_LOADER_FILES ??
63 /*
64 PVOID PrivateData;
65 */
66 } BOOT_STORE_CONTEXT, *PBOOT_STORE_CONTEXT;
67
68 typedef struct _BOOT_STORE_INI_CONTEXT
69 {
70 BOOT_STORE_CONTEXT Header;
71
72 /*
73 * If all these members are NULL, we know that the store is freshly created
74 * and is cached in memory only. At file closure we will therefore need to
75 * create the file proper and save its contents.
76 */
77 HANDLE FileHandle;
78 HANDLE SectionHandle;
79 // SIZE_T ViewSize;
80 ULONG FileSize;
81 PVOID ViewBase;
82
83 PINICACHE IniCache;
84 PINI_SECTION OptionsIniSection;
85 PINI_SECTION OsIniSection;
86 } BOOT_STORE_INI_CONTEXT, *PBOOT_STORE_INI_CONTEXT;
87
88 // TODO!
89 typedef struct _BOOT_STORE_BCDREG_CONTEXT
90 {
91 BOOT_STORE_CONTEXT Header;
92 ULONG PlaceHolder;
93 } BOOT_STORE_BCDREG_CONTEXT, *PBOOT_STORE_BCDREG_CONTEXT;
94
95
96 static NTSTATUS
97 OpenIniBootLoaderStore(
98 _Out_ PVOID* Handle,
99 _In_ HANDLE PartitionDirectoryHandle, // _In_opt_
100 _In_ BOOT_STORE_TYPE Type,
101 _In_ BOOT_STORE_OPENMODE OpenMode,
102 _In_ BOOT_STORE_ACCESS Access);
103
104 static NTSTATUS
105 CloseIniBootLoaderStore(
106 _In_ PVOID Handle);
107
108 static NTSTATUS
109 FreeLdrEnumerateBootEntries(
110 IN PBOOT_STORE_INI_CONTEXT BootStore,
111 // IN ULONG Flags, // Determine which data to retrieve
112 IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
113 IN PVOID Parameter OPTIONAL);
114
115 static NTSTATUS
116 NtLdrEnumerateBootEntries(
117 IN PBOOT_STORE_INI_CONTEXT BootStore,
118 // IN ULONG Flags, // Determine which data to retrieve
119 IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
120 IN PVOID Parameter OPTIONAL);
121
122
123 // Question 1: What if config file is optional?
124 // Question 2: What if many config files are possible?
125 NTOS_BOOT_LOADER_FILES NtosBootLoaders[] =
126 {
127 {FreeLdr, L"freeldr.sys\0", L"freeldr.ini",
128 OpenIniBootLoaderStore, CloseIniBootLoaderStore, (PENUM_BOOT_STORE_ENTRIES)FreeLdrEnumerateBootEntries},
129 {NtLdr , L"ntldr\0" L"osloader.exe\0", L"boot.ini",
130 OpenIniBootLoaderStore, CloseIniBootLoaderStore, (PENUM_BOOT_STORE_ENTRIES)NtLdrEnumerateBootEntries },
131 // {SetupLdr, L"setupldr\0" L"setupldr.bin\0" L"setupldr.exe\0", L"txtsetup.sif", UNIMPLEMENTED, UNIMPLEMENTED, UNIMPLEMENTED}
132 // {BootMgr , L"bootmgr", L"BCD", UNIMPLEMENTED, UNIMPLEMENTED, UNIMPLEMENTED}
133 };
134 C_ASSERT(_countof(NtosBootLoaders) == BldrTypeMax);
135
136 enum BOOT_OPTION
137 {
138 BO_TimeOut,
139 BO_DefaultOS,
140 };
141 static const PCWSTR BootOptionNames[][2] =
142 {
143 {L"TimeOut", L"DefaultOS"}, // FreeLdr
144 {L"timeout", L"default" } // NtLdr
145 };
146
147
148 /* FUNCTIONS ****************************************************************/
149
150 NTSTATUS
FindBootStore(IN HANDLE PartitionDirectoryHandle,IN BOOT_STORE_TYPE Type,OUT PULONG VersionNumber OPTIONAL)151 FindBootStore( // By handle
152 IN HANDLE PartitionDirectoryHandle, // OPTIONAL
153 IN BOOT_STORE_TYPE Type,
154 OUT PULONG VersionNumber OPTIONAL)
155 // OUT PHANDLE ConfigFileHande OPTIONAL ????
156 {
157 PCWSTR LoaderExecutable;
158 // UINT i;
159
160 if (Type >= BldrTypeMax)
161 return STATUS_INVALID_PARAMETER;
162
163 if (VersionNumber)
164 *VersionNumber = 0;
165
166 /* Check whether any of the loader executables exist */
167 LoaderExecutable = NtosBootLoaders[Type].LoaderExecutables;
168 while (*LoaderExecutable)
169 {
170 if (DoesFileExist(PartitionDirectoryHandle, LoaderExecutable))
171 {
172 /* A loader was found, stop there */
173 DPRINT("Found loader executable '%S'\n", LoaderExecutable);
174 break;
175 }
176
177 /* The loader does not exist, continue with another one */
178 DPRINT("Loader executable '%S' does not exist, continue with another one...\n", LoaderExecutable);
179 LoaderExecutable += wcslen(LoaderExecutable) + 1;
180 }
181 if (!*LoaderExecutable)
182 {
183 /* No loader was found */
184 DPRINT("No loader executable was found\n");
185 return STATUS_NOT_FOUND;
186 }
187
188 /* Check for loader version if needed */
189 if (VersionNumber)
190 {
191 *VersionNumber = 0;
192 // TODO: Check for BLDR version!
193 }
194
195 /* Check whether the loader configuration file exists */
196 #if 0
197 Status = OpenAndMapFile(PartitionDirectoryHandle, NtosBootLoaders[Type].LoaderConfigurationFile,
198 &FileHandle, &FileSize, &SectionHandle, &ViewBase, FALSE);
199 if (!NT_SUCCESS(Status))
200 #else
201 if (!DoesFileExist(PartitionDirectoryHandle, NtosBootLoaders[Type].LoaderConfigurationFile))
202 #endif
203 {
204 /* The loader does not exist, continue with another one */
205 // FIXME: Consider it might be optional??
206 DPRINT1("Loader configuration file '%S' does not exist\n", NtosBootLoaders[Type].LoaderConfigurationFile);
207 return STATUS_NOT_FOUND;
208 }
209
210 return STATUS_SUCCESS;
211 }
212
213
214 //
215 // TEMPORARY functions to migrate the DEPRECATED BootDrive and BootPartition
216 // values of BootSector boot entries in FREELDR.INI to the newer BootPath value.
217 //
218 // REMOVE THEM once they won't be necessary anymore,
219 // after the removal of their support in FreeLoader!
220 //
221 static VOID
FreeLdrMigrateBootDrivePartWorker(_In_ PINI_SECTION OsIniSection)222 FreeLdrMigrateBootDrivePartWorker(
223 _In_ PINI_SECTION OsIniSection)
224 {
225 PCWSTR KeyData;
226 PINI_KEYWORD OldKey;
227
228 /*
229 * Check whether we have a "BootPath" value (takes precedence
230 * over both "BootDrive" and "BootPartition").
231 */
232 if (IniGetKey(OsIniSection, L"BootPath", &KeyData) && KeyData && *KeyData)
233 {
234 /* We already have a BootPath value, do nothing more */
235 return;
236 }
237
238 /* We don't have one: retrieve the BIOS drive and
239 * partition and convert them to a valid ARC path */
240
241 /* Retrieve the boot drive */
242 OldKey = IniGetKey(OsIniSection, L"BootDrive", &KeyData);
243 if (OldKey)
244 {
245 PCWSTR OldDrive = KeyData;
246 ULONG DriveNumber = 0;
247 ULONG PartitionNumber = 0;
248 UCHAR DriveType = 0;
249 WCHAR BufferBootPath[80]; // 80 chars is enough for "multi(0)disk(0)rdisk(x)partition(y)", with (x,y) == MAXULONG
250
251 /* If a number string is given, then just
252 * convert it to decimal (BIOS HW only) */
253 PCWCH p = KeyData;
254 if (p[0] >= L'0' && p[0] <= L'9')
255 {
256 DriveNumber = wcstoul(p, (PWCHAR*)&p, 0);
257 if (DriveNumber >= 0x80)
258 {
259 /* It's quite probably a hard disk */
260 DriveNumber -= 0x80;
261 DriveType = L'h';
262 }
263 else
264 {
265 /* It's quite probably a floppy */
266 DriveType = L'f';
267 }
268 }
269 else if (p[0] && towlower(p[1]) == L'd')
270 {
271 /* Convert the drive number string into a number: 'hd1' = 1 */
272 DriveType = tolower(p[0]);
273 DriveNumber = _wtoi(&p[2]);
274 }
275
276 /* Retrieve the boot partition (optional, fall back to zero otherwise) */
277 if (IniGetKey(OsIniSection, L"BootPartition", &KeyData))
278 PartitionNumber = _wtoi(KeyData);
279
280 if (DriveType == L'f')
281 {
282 /* Floppy disk path: multi(0)disk(0)fdisk(x) */
283 RtlStringCchPrintfW(BufferBootPath, _countof(BufferBootPath),
284 L"multi(0)disk(0)fdisk(%lu)", DriveNumber);
285 }
286 else if (DriveType == L'h')
287 {
288 /* Hard disk path: multi(0)disk(0)rdisk(x)partition(y) */
289 RtlStringCchPrintfW(BufferBootPath, _countof(BufferBootPath),
290 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
291 DriveNumber, PartitionNumber);
292 }
293 else if (DriveType == L'c')
294 {
295 /* CD-ROM disk path: multi(0)disk(0)cdrom(x) */
296 RtlStringCchPrintfW(BufferBootPath, _countof(BufferBootPath),
297 L"multi(0)disk(0)cdrom(%lu)", DriveNumber);
298 }
299 else
300 {
301 /* This case should rarely happen, if ever */
302 DPRINT1("Unrecognized BootDrive type '%C'\n", DriveType ? DriveType : L'?');
303
304 /* Build the boot path in the form: hdX,Y */
305 RtlStringCchCopyW(BufferBootPath, _countof(BufferBootPath), OldDrive);
306 if (KeyData && *KeyData)
307 {
308 RtlStringCchCatW(BufferBootPath, _countof(BufferBootPath), L",");
309 RtlStringCchCatW(BufferBootPath, _countof(BufferBootPath), KeyData);
310 }
311 }
312
313 /* Add the new BootPath value */
314 IniInsertKey(OsIniSection, OldKey, INSERT_BEFORE, L"BootPath", BufferBootPath);
315 }
316
317 /* Delete the deprecated BootDrive and BootPartition values */
318 IniRemoveKeyByName(OsIniSection, L"BootDrive");
319 IniRemoveKeyByName(OsIniSection, L"BootPartition");
320 }
321
322 static VOID
FreeLdrMigrateBootDrivePart(_In_ PBOOT_STORE_INI_CONTEXT BootStore)323 FreeLdrMigrateBootDrivePart(
324 _In_ PBOOT_STORE_INI_CONTEXT BootStore)
325 {
326 PINICACHEITERATOR Iterator;
327 PINI_SECTION OsIniSection;
328 PCWSTR SectionName, KeyData;
329
330 /* Enumerate all the valid entries in the "Operating Systems" section */
331 Iterator = IniFindFirstValue(BootStore->OsIniSection, &SectionName, &KeyData);
332 if (!Iterator) return;
333 do
334 {
335 /* Search for an existing boot entry section */
336 OsIniSection = IniGetSection(BootStore->IniCache, SectionName);
337 if (!OsIniSection)
338 continue;
339
340 /* Check for boot type to migrate */
341 if (!IniGetKey(OsIniSection, L"BootType", &KeyData) || !KeyData)
342 {
343 /* Certainly not a ReactOS installation */
344 DPRINT1("No BootType value present\n");
345 continue;
346 }
347 if ((_wcsicmp(KeyData, L"Drive") == 0) ||
348 (_wcsicmp(KeyData, L"\"Drive\"") == 0) ||
349 (_wcsicmp(KeyData, L"Partition") == 0) ||
350 (_wcsicmp(KeyData, L"\"Partition\"") == 0))
351 {
352 /* Modify the BootPath value */
353 IniAddKey(OsIniSection, L"BootType", L"BootSector");
354 goto migrate_drivepart;
355 }
356 if ((_wcsicmp(KeyData, L"BootSector") == 0) ||
357 (_wcsicmp(KeyData, L"\"BootSector\"") == 0))
358 {
359 migrate_drivepart:
360 DPRINT("This is a '%S' boot entry\n", KeyData);
361 FreeLdrMigrateBootDrivePartWorker(OsIniSection);
362 }
363 }
364 while (IniFindNextValue(Iterator, &SectionName, &KeyData));
365
366 IniFindClose(Iterator);
367 }
368 //////////////
369
370
371 static VOID
CreateCommonFreeLdrSections(IN OUT PBOOT_STORE_INI_CONTEXT BootStore)372 CreateCommonFreeLdrSections(
373 IN OUT PBOOT_STORE_INI_CONTEXT BootStore)
374 {
375 PINI_SECTION IniSection;
376
377 /*
378 * Cache the "FREELOADER" section for our future usage.
379 */
380
381 /* Create the "FREELOADER" section */
382 IniSection = IniAddSection(BootStore->IniCache, L"FREELOADER");
383 if (!IniSection)
384 DPRINT1("CreateCommonFreeLdrSections: Failed to create 'FREELOADER' section!\n");
385
386 BootStore->OptionsIniSection = IniSection;
387
388 /* TimeOut */
389 IniAddKey(BootStore->OptionsIniSection, L"TimeOut", L"0");
390
391 /* Create "Display" section */
392 IniSection = IniAddSection(BootStore->IniCache, L"Display");
393
394 /* TitleText and MinimalUI */
395 IniAddKey(IniSection, L"TitleText", L"ReactOS Boot Manager");
396 IniAddKey(IniSection, L"MinimalUI", L"Yes");
397
398 /*
399 * Cache the "Operating Systems" section for our future usage.
400 */
401
402 /* Create the "Operating Systems" section */
403 IniSection = IniAddSection(BootStore->IniCache, L"Operating Systems");
404 if (!IniSection)
405 DPRINT1("CreateCommonFreeLdrSections: Failed to create 'Operating Systems' section!\n");
406
407 BootStore->OsIniSection = IniSection;
408 }
409
410 static NTSTATUS
OpenIniBootLoaderStore(_Out_ PVOID * Handle,_In_ HANDLE PartitionDirectoryHandle,_In_ BOOT_STORE_TYPE Type,_In_ BOOT_STORE_OPENMODE OpenMode,_In_ BOOT_STORE_ACCESS Access)411 OpenIniBootLoaderStore(
412 _Out_ PVOID* Handle,
413 _In_ HANDLE PartitionDirectoryHandle, // _In_opt_
414 _In_ BOOT_STORE_TYPE Type,
415 _In_ BOOT_STORE_OPENMODE OpenMode,
416 _In_ BOOT_STORE_ACCESS Access)
417 {
418 NTSTATUS Status;
419 PBOOT_STORE_INI_CONTEXT BootStore;
420 UNICODE_STRING Name;
421 OBJECT_ATTRIBUTES ObjectAttributes;
422 IO_STATUS_BLOCK IoStatusBlock;
423 ACCESS_MASK DesiredAccess;
424 ULONG CreateDisposition;
425
426 //
427 // WARNING! We support the INI creation *ONLY* for FreeLdr, and not for NTLDR
428 //
429 if ((Type == NtLdr) && (OpenMode == BS_CreateNew || OpenMode == BS_CreateAlways || OpenMode == BS_RecreateExisting))
430 {
431 DPRINT1("OpenIniBootLoaderStore() unsupported for NTLDR\n");
432 return STATUS_NOT_SUPPORTED;
433 }
434
435 /* Create a boot store structure */
436 BootStore = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*BootStore));
437 if (!BootStore)
438 return STATUS_INSUFFICIENT_RESOURCES;
439
440 BootStore->Header.Type = Type;
441
442 /*
443 * So far, we only use the INI cache. The file itself is not created or
444 * opened yet, therefore FileHandle, SectionHandle, ViewBase and FileSize
445 * are all NULL. We will use this fact to know that the INI file was indeed
446 * created, and not just opened as an existing file.
447 */
448 // BootStore->FileHandle = NULL;
449 BootStore->SectionHandle = NULL;
450 BootStore->ViewBase = NULL;
451 BootStore->FileSize = 0;
452
453 /*
454 * Create or open the loader configuration INI file as necessary.
455 */
456 RtlInitUnicodeString(&Name, NtosBootLoaders[Type].LoaderConfigurationFile);
457 InitializeObjectAttributes(&ObjectAttributes,
458 &Name,
459 OBJ_CASE_INSENSITIVE,
460 PartitionDirectoryHandle,
461 NULL);
462
463 DesiredAccess =
464 ((Access & BS_ReadAccess ) ? FILE_GENERIC_READ : 0) |
465 ((Access & BS_WriteAccess) ? FILE_GENERIC_WRITE : 0);
466
467 CreateDisposition = FILE_OPEN;
468 switch (OpenMode)
469 {
470 case BS_CreateNew:
471 CreateDisposition = FILE_CREATE;
472 break;
473 case BS_CheckExisting:
474 case BS_OpenExisting:
475 CreateDisposition = FILE_OPEN;
476 break;
477 case BS_OpenAlways:
478 CreateDisposition = FILE_OPEN_IF;
479 break;
480 case BS_RecreateExisting:
481 CreateDisposition = FILE_OVERWRITE;
482 break;
483 case BS_CreateAlways:
484 CreateDisposition = FILE_OVERWRITE_IF;
485 break;
486 default:
487 ASSERT(FALSE);
488 }
489
490 IoStatusBlock.Information = 0;
491 Status = NtCreateFile(&BootStore->FileHandle,
492 DesiredAccess | SYNCHRONIZE,
493 &ObjectAttributes,
494 &IoStatusBlock,
495 NULL,
496 FILE_ATTRIBUTE_NORMAL,
497 FILE_SHARE_READ,
498 CreateDisposition,
499 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE,
500 NULL,
501 0);
502
503 if (OpenMode == BS_CheckExisting)
504 {
505 /* We just want to check for file existence. If we either succeeded
506 * opening the file, or we failed because it exists but we do not
507 * currently have access to it, return success in either case. */
508 BOOLEAN Success = (NT_SUCCESS(Status) || (Status == STATUS_ACCESS_DENIED));
509 if (!Success)
510 {
511 DPRINT1("Couldn't find Loader configuration file '%S'\n",
512 NtosBootLoaders[Type].LoaderConfigurationFile);
513 }
514 if (BootStore->FileHandle)
515 NtClose(BootStore->FileHandle);
516 RtlFreeHeap(ProcessHeap, 0, BootStore);
517 return (Success ? STATUS_SUCCESS : Status);
518 }
519
520 /*
521 * If create/open failed because the file is in read-only mode,
522 * change its attributes and re-attempt opening it.
523 */
524 if (Status == STATUS_ACCESS_DENIED) do
525 {
526 FILE_BASIC_INFORMATION FileInfo = {0};
527
528 /* Reattempt to open it with limited access */
529 Status = NtCreateFile(&BootStore->FileHandle,
530 FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
531 &ObjectAttributes,
532 &IoStatusBlock,
533 NULL,
534 FILE_ATTRIBUTE_NORMAL,
535 FILE_SHARE_READ,
536 FILE_OPEN,
537 FILE_NO_INTERMEDIATE_BUFFERING |
538 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE,
539 NULL,
540 0);
541 /* Fail for real if we cannot open it that way */
542 if (!NT_SUCCESS(Status))
543 break;
544
545 /* Reset attributes to normal, no read-only */
546 FileInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
547 /*
548 * We basically don't care about whether it succeeds:
549 * if it didn't, later open will fail.
550 */
551 NtSetInformationFile(BootStore->FileHandle, &IoStatusBlock,
552 &FileInfo, sizeof(FileInfo),
553 FileBasicInformation);
554
555 /* Close file */
556 NtClose(BootStore->FileHandle);
557
558 /* And re-attempt create/open */
559 Status = NtCreateFile(&BootStore->FileHandle,
560 DesiredAccess | SYNCHRONIZE,
561 &ObjectAttributes,
562 &IoStatusBlock,
563 NULL,
564 FILE_ATTRIBUTE_NORMAL,
565 FILE_SHARE_READ,
566 CreateDisposition,
567 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE,
568 NULL,
569 0);
570 } while (0);
571 if (!NT_SUCCESS(Status))
572 {
573 DPRINT1("Couldn't open Loader configuration file '%S' (Status 0x%08lx)\n",
574 NtosBootLoaders[Type].LoaderConfigurationFile, Status);
575 RtlFreeHeap(ProcessHeap, 0, BootStore);
576 return Status;
577 }
578
579 BootStore->Header.ReadOnly = !(Access & BS_WriteAccess);
580
581 if (IoStatusBlock.Information == FILE_CREATED || // with: FILE_CREATE, FILE_OVERWRITE_IF, FILE_OPEN_IF, FILE_SUPERSEDE
582 IoStatusBlock.Information == FILE_OVERWRITTEN || // with: FILE_OVERWRITE, FILE_OVERWRITE_IF
583 IoStatusBlock.Information == FILE_SUPERSEDED) // with: FILE_SUPERSEDE
584 {
585 /*
586 * The loader configuration INI file is (re)created
587 * fresh new, initialize its cache and its contents.
588 */
589 BootStore->IniCache = IniCacheCreate();
590 if (!BootStore->IniCache)
591 {
592 DPRINT1("IniCacheCreate() failed\n");
593 NtClose(BootStore->FileHandle);
594 RtlFreeHeap(ProcessHeap, 0, BootStore);
595 return STATUS_INSUFFICIENT_RESOURCES;
596 }
597
598 if (Type == FreeLdr)
599 CreateCommonFreeLdrSections(BootStore);
600 }
601 else // if (IoStatusBlock.Information == FILE_OPENED) // with: FILE_OPEN, FILE_OPEN_IF
602 {
603 PINI_SECTION IniSection;
604
605 /*
606 * The loader configuration INI file exists and is opened,
607 * map its file contents into memory.
608 */
609 #if 0
610 // FIXME: &BootStore->FileSize
611 Status = MapFile(BootStore->FileHandle,
612 &BootStore->SectionHandle,
613 &BootStore->ViewBase,
614 (Access & BS_WriteAccess));
615 if (!NT_SUCCESS(Status))
616 {
617 DPRINT1("Failed to map Loader configuration file '%S' (Status 0x%08lx)\n",
618 NtosBootLoaders[Type].LoaderConfigurationFile, Status);
619 NtClose(BootStore->FileHandle);
620 RtlFreeHeap(ProcessHeap, 0, BootStore);
621 return Status;
622 }
623 #else
624 BootStore->SectionHandle = UlongToPtr(1); // Workaround for CloseIniBootLoaderStore
625 #endif
626
627 /* Open an *existing* INI configuration file */
628 #if 0
629 Status = IniCacheLoadFromMemory(&BootStore->IniCache,
630 BootStore->ViewBase,
631 BootStore->FileSize,
632 FALSE);
633 #else
634 Status = IniCacheLoadByHandle(&BootStore->IniCache, BootStore->FileHandle, FALSE);
635 #endif
636 if (!NT_SUCCESS(Status))
637 {
638 DPRINT1("IniCacheLoadFromMemory() failed (Status 0x%08lx)\n", Status);
639 #if 0
640 /* Finally, unmap and close the file */
641 UnMapAndCloseFile(BootStore->FileHandle,
642 BootStore->SectionHandle,
643 BootStore->ViewBase);
644 #else
645 NtClose(BootStore->FileHandle);
646 #endif
647 RtlFreeHeap(ProcessHeap, 0, BootStore);
648 return Status;
649 }
650
651 if (Type == FreeLdr)
652 {
653 /*
654 * Cache the "FREELOADER" section for our future usage.
655 */
656
657 /* Get or create the "FREELOADER" section */
658 IniSection = IniAddSection(BootStore->IniCache, L"FREELOADER");
659 if (!IniSection)
660 DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'FREELOADER' section!\n");
661
662 BootStore->OptionsIniSection = IniSection;
663
664 /*
665 * Cache the "Operating Systems" section for our future usage.
666 */
667
668 /* Get or create the "Operating Systems" section */
669 IniSection = IniAddSection(BootStore->IniCache, L"Operating Systems");
670 if (!IniSection)
671 DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'Operating Systems' section!\n");
672
673 BootStore->OsIniSection = IniSection;
674
675 //
676 // TEMPORARY: Migrate the DEPRECATED BootDrive and BootPartition
677 // values of BootSector boot entries to the newer BootPath value.
678 //
679 FreeLdrMigrateBootDrivePart(BootStore);
680 }
681 else
682 if (Type == NtLdr)
683 {
684 /*
685 * Cache the "boot loader" section for our future usage.
686 */
687 /*
688 * HISTORICAL NOTE:
689 *
690 * While the "operating systems" section acquired its definitive
691 * name already when Windows NT was at its very early beta stage
692 * (NT 3.1 October 1991 Beta, 10-16-1991), this was not the case
693 * for its general settings section "boot loader".
694 *
695 * The following section names were successively introduced:
696 *
697 * - In NT 3.1 October 1991 Beta, 10-16-1991, using OS Loader V1.5,
698 * the section was named "multiboot".
699 *
700 * - In the next public beta version NT 3.10.340 Beta, 10-12-1992,
701 * using OS Loader V2.10, a new name was introduced: "flexboot".
702 * This is around this time that the NT OS Loader was also
703 * introduced as the "Windows NT FlexBoot" loader, as shown by
704 * the Windows NT FAQs that circulated around this time:
705 * http://cd.textfiles.com/cica9308/CIS_LIBS/WINNT/1/NTFAQ.TXT
706 * http://cd.textfiles.com/cica/cica9308/UNZIPPED/NT/NTFAQ/FTP/NEWS/NTFAQ1.TXT
707 * I can only hypothesize that the "FlexBoot" name was chosen
708 * as a marketing coup, possibly to emphasise its "flexibility"
709 * as a simple multiboot-aware boot manager.
710 *
711 * - A bit later, with NT 3.10.404 Beta, 3-7-1993, using an updated
712 * version of OS Loader V2.10, the final section name "boot loader"
713 * was introduced, and was kept since then.
714 *
715 * Due to the necessity to be able to boot and / or upgrade any
716 * Windows NT version at any time, including its NT Loader and the
717 * associated boot.ini file, all versions of NTLDR and the NT installer
718 * understand and parse these three section names, the default one
719 * being "boot loader", and if not present, they successively fall
720 * back to "flexboot" and then to "multiboot".
721 */
722
723 /* Get the "boot loader" section */
724 IniSection = IniGetSection(BootStore->IniCache, L"boot loader");
725 if (!IniSection)
726 {
727 /* Fall back to "flexboot" */
728 IniSection = IniGetSection(BootStore->IniCache, L"flexboot");
729 if (!IniSection)
730 {
731 /* Fall back to "multiboot" */
732 IniSection = IniGetSection(BootStore->IniCache, L"multiboot");
733 }
734 }
735 #if 0
736 if (!IniSection)
737 {
738 /* It does not exist yet, so create it */
739 IniSection = IniAddSection(BootStore->IniCache, L"boot loader");
740 }
741 #endif
742 if (!IniSection)
743 DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'boot loader' section!\n");
744
745 BootStore->OptionsIniSection = IniSection;
746
747 /*
748 * Cache the "Operating Systems" section for our future usage.
749 */
750
751 /* Get or create the "Operating Systems" section */
752 IniSection = IniAddSection(BootStore->IniCache, L"operating systems");
753 if (!IniSection)
754 DPRINT1("OpenIniBootLoaderStore: Failed to retrieve 'operating systems' section!\n");
755
756 BootStore->OsIniSection = IniSection;
757 }
758 }
759
760 *Handle = BootStore;
761 return STATUS_SUCCESS;
762 }
763
764 /**
765 * @brief
766 * Selectively changes the attributes of a file.
767 *
768 * @param[in] FileHandle
769 * Handle to an opened file for which to change its attributes.
770 *
771 * @param[in] MaskAttributes
772 * A mask specifying which attributes to change; any other attributes
773 * will be maintained as they are. If this parameter is zero, all of
774 * the attributes in *Attributes will be changed.
775 *
776 * @param[in,out] Attributes
777 * In input, specifies the new attributes to set. Attributes that
778 * are not set, but are specified in MaskAttributes, are removed.
779 * In output, receives the original attributes of the file.
780 *
781 * @return
782 * STATUS_SUCCESS if the attributes were successfully changed,
783 * or a failure code if an error happened.
784 **/
785 static NTSTATUS
ProtectFile(_In_ HANDLE FileHandle,_In_ ULONG MaskAttributes,_Inout_ PULONG Attributes)786 ProtectFile(
787 _In_ HANDLE FileHandle,
788 _In_ ULONG MaskAttributes,
789 _Inout_ PULONG Attributes)
790 {
791 NTSTATUS Status;
792 IO_STATUS_BLOCK IoStatusBlock;
793 FILE_BASIC_INFORMATION FileInfo;
794 ULONG OldAttributes;
795
796 /* Retrieve the original file attributes */
797 Status = NtQueryInformationFile(FileHandle,
798 &IoStatusBlock,
799 &FileInfo,
800 sizeof(FileInfo),
801 FileBasicInformation);
802 if (!NT_SUCCESS(Status))
803 {
804 DPRINT1("NtQueryInformationFile() failed (Status 0x%08lx)\n", Status);
805 return Status;
806 }
807 OldAttributes = FileInfo.FileAttributes;
808
809 /* Modify the attributes and return the old ones */
810 if (MaskAttributes)
811 FileInfo.FileAttributes = (OldAttributes & ~MaskAttributes) | (*Attributes & MaskAttributes);
812 else
813 FileInfo.FileAttributes = *Attributes;
814
815 *Attributes = OldAttributes;
816
817 /* Set the new file attributes */
818 Status = NtSetInformationFile(FileHandle,
819 &IoStatusBlock,
820 &FileInfo,
821 sizeof(FileInfo),
822 FileBasicInformation);
823 if (!NT_SUCCESS(Status))
824 DPRINT1("NtSetInformationFile() failed (Status 0x%08lx)\n", Status);
825
826 return Status;
827 }
828
829 static NTSTATUS
CloseIniBootLoaderStore(_In_ PVOID Handle)830 CloseIniBootLoaderStore(
831 _In_ PVOID Handle)
832 {
833 /* Set or remove SYSTEM, HIDDEN and READONLY attributes */
834 static const ULONG ProtectAttribs =
835 (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
836
837 PBOOT_STORE_INI_CONTEXT BootStore = (PBOOT_STORE_INI_CONTEXT)Handle;
838 NTSTATUS Status = STATUS_SUCCESS;
839 ULONG FileAttribs;
840
841 ASSERT(BootStore);
842
843 /* If the INI file was opened in read-only mode, skip saving */
844 if (BootStore->Header.ReadOnly)
845 goto Quit;
846
847 /* If the INI file was already opened because it already existed, unprotect it */
848 if (BootStore->SectionHandle)
849 {
850 FileAttribs = 0;
851 Status = ProtectFile(BootStore->FileHandle, ProtectAttribs, &FileAttribs);
852 if (!NT_SUCCESS(Status))
853 {
854 DPRINT1("Could not unprotect INI boot store (Status 0x%08lx)\n", Status);
855 goto Quit;
856 }
857 }
858
859 IniCacheSaveByHandle(BootStore->IniCache, BootStore->FileHandle);
860
861 /* Re-protect the INI file */
862 FileAttribs = ProtectAttribs;
863 if (BootStore->Header.Type == FreeLdr)
864 {
865 // NOTE: CORE-19575: For the time being, don't add READONLY for ease
866 // of testing and modifying files, but it won't always stay this way.
867 FileAttribs &= ~FILE_ATTRIBUTE_READONLY;
868 }
869 /*Status =*/ ProtectFile(BootStore->FileHandle, FileAttribs, &FileAttribs);
870 Status = STATUS_SUCCESS; // Ignore the status and just succeed.
871
872 Quit:
873 IniCacheDestroy(BootStore->IniCache);
874
875 #if 0
876 if (BootStore->SectionHandle)
877 {
878 /* Finally, unmap and close the file */
879 UnMapAndCloseFile(BootStore->FileHandle,
880 BootStore->SectionHandle,
881 BootStore->ViewBase);
882 }
883 else // if (BootStore->FileHandle)
884 #endif
885 {
886 /* Just close the file we have opened for creation */
887 NtClose(BootStore->FileHandle);
888 }
889
890 /* Finally, free the boot store structure */
891 RtlFreeHeap(ProcessHeap, 0, BootStore);
892 return Status;
893 }
894
895
896 NTSTATUS
OpenBootStoreByHandle(_Out_ PVOID * Handle,_In_ HANDLE PartitionDirectoryHandle,_In_ BOOT_STORE_TYPE Type,_In_ BOOT_STORE_OPENMODE OpenMode,_In_ BOOT_STORE_ACCESS Access)897 OpenBootStoreByHandle(
898 _Out_ PVOID* Handle,
899 _In_ HANDLE PartitionDirectoryHandle, // _In_opt_
900 _In_ BOOT_STORE_TYPE Type,
901 _In_ BOOT_STORE_OPENMODE OpenMode,
902 _In_ BOOT_STORE_ACCESS Access)
903 {
904 /*
905 * NOTE: Currently we open & map the loader configuration file without
906 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
907 * and NTLDR's boot.ini files. But as soon as we'll implement support for
908 * BOOTMGR detection, the "configuration file" will be the BCD registry
909 * hive and then, we'll have instead to mount the hive & open it.
910 */
911
912 if (Type >= BldrTypeMax || NtosBootLoaders[Type].Type >= BldrTypeMax)
913 {
914 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[Type].Type);
915 return STATUS_NOT_SUPPORTED;
916 }
917
918 /*
919 * Verify the access modes to perform the open actions.
920 * The operating system may allow e.g. file creation even with
921 * read-only access, but we do not allow this because we want
922 * to protect any existing boot store file in case the caller
923 * specified such an open mode.
924 */
925 // if ((OpenMode == BS_CheckExisting) && !(Access & BS_ReadAccess))
926 // return STATUS_ACCESS_DENIED;
927 if ((OpenMode == BS_CreateNew || OpenMode == BS_CreateAlways || OpenMode == BS_RecreateExisting) && !(Access & BS_WriteAccess))
928 return STATUS_ACCESS_DENIED;
929 if ((OpenMode == BS_OpenExisting || OpenMode == BS_OpenAlways) && !(Access & BS_ReadWriteAccess))
930 return STATUS_ACCESS_DENIED;
931
932 return NtosBootLoaders[Type].OpenBootStore(Handle,
933 PartitionDirectoryHandle,
934 Type,
935 OpenMode,
936 Access);
937 }
938
939 NTSTATUS
OpenBootStore_UStr(_Out_ PVOID * Handle,_In_ PUNICODE_STRING SystemPartitionPath,_In_ BOOT_STORE_TYPE Type,_In_ BOOT_STORE_OPENMODE OpenMode,_In_ BOOT_STORE_ACCESS Access)940 OpenBootStore_UStr(
941 _Out_ PVOID* Handle,
942 _In_ PUNICODE_STRING SystemPartitionPath,
943 _In_ BOOT_STORE_TYPE Type,
944 _In_ BOOT_STORE_OPENMODE OpenMode,
945 _In_ BOOT_STORE_ACCESS Access)
946 {
947 NTSTATUS Status;
948 OBJECT_ATTRIBUTES ObjectAttributes;
949 IO_STATUS_BLOCK IoStatusBlock;
950 HANDLE PartitionDirectoryHandle;
951
952 /*
953 * NOTE: Currently we open & map the loader configuration file without
954 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
955 * and NTLDR's boot.ini files. But as soon as we'll implement support for
956 * BOOTMGR detection, the "configuration file" will be the BCD registry
957 * hive and then, we'll have instead to mount the hive & open it.
958 */
959
960 if (Type >= BldrTypeMax || NtosBootLoaders[Type].Type >= BldrTypeMax)
961 {
962 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[Type].Type);
963 return STATUS_NOT_SUPPORTED;
964 }
965
966 /* Open SystemPartition */
967 InitializeObjectAttributes(&ObjectAttributes,
968 SystemPartitionPath,
969 OBJ_CASE_INSENSITIVE,
970 NULL,
971 NULL);
972 Status = NtOpenFile(&PartitionDirectoryHandle,
973 FILE_LIST_DIRECTORY | FILE_ADD_FILE /* | FILE_ADD_SUBDIRECTORY | FILE_TRAVERSE*/ | SYNCHRONIZE,
974 &ObjectAttributes,
975 &IoStatusBlock,
976 FILE_SHARE_READ | FILE_SHARE_WRITE,
977 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE /* | FILE_OPEN_FOR_BACKUP_INTENT */);
978 if (!NT_SUCCESS(Status))
979 {
980 DPRINT1("Failed to open SystemPartition '%wZ' (Status 0x%08lx)\n",
981 SystemPartitionPath, Status);
982 return Status;
983 }
984
985 Status = OpenBootStoreByHandle(Handle,
986 PartitionDirectoryHandle,
987 Type,
988 OpenMode,
989 Access);
990
991 /* Done! */
992 NtClose(PartitionDirectoryHandle);
993 return Status;
994 }
995
996 NTSTATUS
OpenBootStore(_Out_ PVOID * Handle,_In_ PCWSTR SystemPartition,_In_ BOOT_STORE_TYPE Type,_In_ BOOT_STORE_OPENMODE OpenMode,_In_ BOOT_STORE_ACCESS Access)997 OpenBootStore(
998 _Out_ PVOID* Handle,
999 _In_ PCWSTR SystemPartition,
1000 _In_ BOOT_STORE_TYPE Type,
1001 _In_ BOOT_STORE_OPENMODE OpenMode,
1002 _In_ BOOT_STORE_ACCESS Access)
1003 {
1004 UNICODE_STRING SystemPartitionPath;
1005 RtlInitUnicodeString(&SystemPartitionPath, SystemPartition);
1006 return OpenBootStore_UStr(Handle,
1007 &SystemPartitionPath,
1008 Type,
1009 OpenMode,
1010 Access);
1011 }
1012
1013 NTSTATUS
CloseBootStore(_In_ PVOID Handle)1014 CloseBootStore(
1015 _In_ PVOID Handle)
1016 {
1017 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1018
1019 if (!BootStore)
1020 return STATUS_INVALID_PARAMETER;
1021
1022 /*
1023 * NOTE: Currently we open & map the loader configuration file without
1024 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1025 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1026 * BOOTMGR detection, the "configuration file" will be the BCD registry
1027 * hive and then, we'll have instead to mount the hive & open it.
1028 */
1029
1030 if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1031 {
1032 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
1033 return STATUS_NOT_SUPPORTED;
1034 }
1035
1036 return NtosBootLoaders[BootStore->Type].CloseBootStore(Handle /* BootStore */);
1037 }
1038
1039
1040 static
1041 NTSTATUS
CreateNTOSEntry(IN PBOOT_STORE_INI_CONTEXT BootStore,IN ULONG_PTR BootEntryKey,IN PBOOT_STORE_ENTRY BootEntry)1042 CreateNTOSEntry(
1043 IN PBOOT_STORE_INI_CONTEXT BootStore,
1044 IN ULONG_PTR BootEntryKey,
1045 IN PBOOT_STORE_ENTRY BootEntry)
1046 {
1047 PINI_SECTION IniSection;
1048 PCWSTR Section = (PCWSTR)BootEntryKey;
1049
1050 /* Insert the entry into the "Operating Systems" section */
1051 IniAddKey(BootStore->OsIniSection, Section, BootEntry->FriendlyName);
1052
1053 /* Create a new section */
1054 IniSection = IniAddSection(BootStore->IniCache, Section);
1055
1056 if (BootEntry->OsOptionsLength >= sizeof(NTOS_OPTIONS) &&
1057 RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
1058 NTOS_OPTIONS_SIGNATURE,
1059 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) ==
1060 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature))
1061 {
1062 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
1063
1064 /* BootType, SystemPath and Options */
1065 IniAddKey(IniSection, L"BootType", L"Windows2003");
1066 IniAddKey(IniSection, L"SystemPath", Options->OsLoadPath);
1067 IniAddKey(IniSection, L"Options", Options->OsLoadOptions);
1068 }
1069 else
1070 if (BootEntry->OsOptionsLength >= sizeof(BOOTSECTOR_OPTIONS) &&
1071 RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
1072 BOOTSECTOR_OPTIONS_SIGNATURE,
1073 RTL_FIELD_SIZE(BOOTSECTOR_OPTIONS, Signature)) ==
1074 RTL_FIELD_SIZE(BOOTSECTOR_OPTIONS, Signature))
1075 {
1076 PBOOTSECTOR_OPTIONS Options = (PBOOTSECTOR_OPTIONS)&BootEntry->OsOptions;
1077
1078 /* BootType, BootPath and BootSector */
1079 IniAddKey(IniSection, L"BootType", L"BootSector");
1080 IniAddKey(IniSection, L"BootPath", Options->BootPath);
1081 IniAddKey(IniSection, L"BootSectorFile", Options->FileName);
1082 }
1083 else
1084 {
1085 // DPRINT1("Unsupported BootType %lu/'%*.s'\n",
1086 // BootEntry->OsOptionsLength, 8, &BootEntry->OsOptions);
1087 DPRINT1("Unsupported BootType %lu\n", BootEntry->OsOptionsLength);
1088 }
1089
1090 return STATUS_SUCCESS;
1091 }
1092
1093 NTSTATUS
AddBootStoreEntry(IN PVOID Handle,IN PBOOT_STORE_ENTRY BootEntry,IN ULONG_PTR BootEntryKey)1094 AddBootStoreEntry(
1095 IN PVOID Handle,
1096 IN PBOOT_STORE_ENTRY BootEntry,
1097 IN ULONG_PTR BootEntryKey)
1098 {
1099 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1100
1101 if (!BootStore || !BootEntry)
1102 return STATUS_INVALID_PARAMETER;
1103
1104 /*
1105 * NOTE: Currently we open & map the loader configuration file without
1106 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1107 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1108 * BOOTMGR detection, the "configuration file" will be the BCD registry
1109 * hive and then, we'll have instead to mount the hive & open it.
1110 */
1111
1112 //
1113 // FIXME!!
1114 //
1115
1116 // if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1117
1118 if (BootStore->Type == FreeLdr)
1119 {
1120 if (BootEntry->Version != FreeLdr)
1121 return STATUS_INVALID_PARAMETER;
1122
1123 return CreateNTOSEntry((PBOOT_STORE_INI_CONTEXT)BootStore,
1124 BootEntryKey, BootEntry);
1125 }
1126 else
1127 if (BootStore->Type == NtLdr)
1128 {
1129 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
1130 PWCHAR Buffer;
1131 ULONG BufferLength;
1132 PCWSTR InstallName, OsOptions;
1133 // ULONG InstallNameLength, OsOptionsLength;
1134 BOOLEAN IsNameNotQuoted;
1135
1136 if (BootEntry->Version != NtLdr)
1137 return STATUS_INVALID_PARAMETER;
1138
1139 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) ||
1140 RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
1141 NTOS_OPTIONS_SIGNATURE,
1142 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature)) !=
1143 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature))
1144 {
1145 // DPRINT1("Unsupported BootType '%S'\n", BootEntry->Version);
1146 DPRINT1("Unsupported BootType %lu\n", BootEntry->OsOptionsLength);
1147 return STATUS_SUCCESS; // STATUS_NOT_SUPPORTED;
1148 }
1149
1150 InstallName = BootEntry->FriendlyName;
1151 OsOptions = Options->OsLoadOptions;
1152
1153 // if (InstallNameLength == 0) InstallName = NULL;
1154 // if (OsOptionsLength == 0) OsOptions = NULL;
1155
1156 IsNameNotQuoted = (InstallName[0] != L'\"' || InstallName[wcslen(InstallName)-1] != L'\"');
1157
1158 BufferLength = (IsNameNotQuoted ? 2 /* Quotes for FriendlyName*/ : 0) + wcslen(InstallName);
1159 if (OsOptions)
1160 BufferLength += 1 /* Space between FriendlyName and options */ + wcslen(OsOptions);
1161 BufferLength++; /* NULL-termination */
1162
1163 Buffer = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, BufferLength * sizeof(WCHAR));
1164 if (!Buffer)
1165 return STATUS_INSUFFICIENT_RESOURCES;
1166
1167 *Buffer = UNICODE_NULL;
1168 if (IsNameNotQuoted) RtlStringCchCatW(Buffer, BufferLength, L"\"");
1169 RtlStringCchCatW(Buffer, BufferLength, InstallName);
1170 if (IsNameNotQuoted) RtlStringCchCatW(Buffer, BufferLength, L"\"");
1171 if (OsOptions)
1172 {
1173 RtlStringCchCatW(Buffer, BufferLength, L" ");
1174 RtlStringCchCatW(Buffer, BufferLength, OsOptions);
1175 }
1176
1177 /* Insert the entry into the "Operating Systems" section */
1178 IniAddKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OsIniSection,
1179 Options->OsLoadPath, Buffer);
1180
1181 RtlFreeHeap(ProcessHeap, 0, Buffer);
1182 return STATUS_SUCCESS;
1183 }
1184 else
1185 {
1186 DPRINT1("Loader type %d is currently unsupported!\n", BootStore->Type);
1187 return STATUS_NOT_SUPPORTED;
1188 }
1189 }
1190
1191 NTSTATUS
DeleteBootStoreEntry(IN PVOID Handle,IN ULONG_PTR BootEntryKey)1192 DeleteBootStoreEntry(
1193 IN PVOID Handle,
1194 IN ULONG_PTR BootEntryKey)
1195 {
1196 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1197
1198 if (!BootStore)
1199 return STATUS_INVALID_PARAMETER;
1200
1201 /*
1202 * NOTE: Currently we open & map the loader configuration file without
1203 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1204 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1205 * BOOTMGR detection, the "configuration file" will be the BCD registry
1206 * hive and then, we'll have instead to mount the hive & open it.
1207 */
1208
1209 //
1210 // FIXME!!
1211 //
1212
1213 // if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1214 if (BootStore->Type != FreeLdr)
1215 {
1216 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
1217 return STATUS_NOT_SUPPORTED;
1218 }
1219
1220 // FIXME! This function needs my INI library rewrite to be implemented!!
1221 UNIMPLEMENTED;
1222 return STATUS_NOT_IMPLEMENTED;
1223 }
1224
1225 NTSTATUS
ModifyBootStoreEntry(IN PVOID Handle,IN PBOOT_STORE_ENTRY BootEntry)1226 ModifyBootStoreEntry(
1227 IN PVOID Handle,
1228 IN PBOOT_STORE_ENTRY BootEntry)
1229 {
1230 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1231
1232 if (!BootStore || !BootEntry)
1233 return STATUS_INVALID_PARAMETER;
1234
1235 /*
1236 * NOTE: Currently we open & map the loader configuration file without
1237 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1238 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1239 * BOOTMGR detection, the "configuration file" will be the BCD registry
1240 * hive and then, we'll have instead to mount the hive & open it.
1241 */
1242
1243 //
1244 // FIXME!!
1245 //
1246
1247 // if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1248 if (BootStore->Type != FreeLdr)
1249 {
1250 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
1251 return STATUS_NOT_SUPPORTED;
1252 }
1253
1254 // FIXME! This function needs my INI library rewrite to operate properly!!
1255 UNIMPLEMENTED;
1256 return STATUS_NOT_IMPLEMENTED;
1257 }
1258
1259 NTSTATUS
QueryBootStoreEntry(IN PVOID Handle,IN ULONG_PTR BootEntryKey,OUT PBOOT_STORE_ENTRY BootEntry)1260 QueryBootStoreEntry(
1261 IN PVOID Handle,
1262 IN ULONG_PTR BootEntryKey,
1263 OUT PBOOT_STORE_ENTRY BootEntry) // Technically this should be PBOOT_STORE_ENTRY*
1264 {
1265 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1266
1267 if (!BootStore)
1268 return STATUS_INVALID_PARAMETER;
1269
1270 /*
1271 * NOTE: Currently we open & map the loader configuration file without
1272 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1273 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1274 * BOOTMGR detection, the "configuration file" will be the BCD registry
1275 * hive and then, we'll have instead to mount the hive & open it.
1276 */
1277
1278 //
1279 // FIXME!!
1280 //
1281
1282 // if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1283 if (BootStore->Type != FreeLdr)
1284 {
1285 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
1286 return STATUS_NOT_SUPPORTED;
1287 }
1288
1289 // FIXME! This function needs my INI library rewrite to be implemented!!
1290 UNIMPLEMENTED;
1291 return STATUS_NOT_IMPLEMENTED;
1292 }
1293
1294 NTSTATUS
QueryBootStoreOptions(IN PVOID Handle,IN OUT PBOOT_STORE_OPTIONS BootOptions)1295 QueryBootStoreOptions(
1296 IN PVOID Handle,
1297 IN OUT PBOOT_STORE_OPTIONS BootOptions
1298 /* , IN PULONG BootOptionsLength */ )
1299 {
1300 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1301 PCWSTR TimeoutStr;
1302
1303 if (!BootStore || !BootOptions)
1304 return STATUS_INVALID_PARAMETER;
1305
1306 /*
1307 * NOTE: Currently we open & map the loader configuration file without
1308 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1309 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1310 * BOOTMGR detection, the "configuration file" will be the BCD registry
1311 * hive and then, we'll have instead to mount the hive & open it.
1312 */
1313
1314 //
1315 // FIXME!!
1316 //
1317
1318 // if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1319 if (BootStore->Type != FreeLdr && BootStore->Type != NtLdr)
1320 {
1321 DPRINT1("Loader type %d is currently unsupported!\n", BootStore->Type);
1322 return STATUS_NOT_SUPPORTED;
1323 }
1324
1325 BootOptions->Timeout = 0;
1326 BootOptions->CurrentBootEntryKey = 0;
1327 BootOptions->NextBootEntryKey = 0;
1328
1329 if (IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
1330 BootOptionNames[BootStore->Type][BO_TimeOut],
1331 &TimeoutStr) && TimeoutStr)
1332 {
1333 BootOptions->Timeout = _wtoi(TimeoutStr);
1334 }
1335
1336 IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
1337 BootOptionNames[BootStore->Type][BO_DefaultOS],
1338 (PCWSTR*)&BootOptions->NextBootEntryKey);
1339
1340 /*
1341 * NOTE: BootOptions->CurrentBootEntryKey is an informative field only.
1342 * It indicates which boot entry has been selected for starting the
1343 * current OS instance. Such information is NOT stored in the INI file,
1344 * but has to be determined via other means. On UEFI the 'BootCurrent'
1345 * environment variable does that. Otherwise, one could heuristically
1346 * determine it by comparing the boot path and options of each entry
1347 * with those used by the current OS instance.
1348 * Since we currently do not need this information (and it can be costly
1349 * to determine), BootOptions->CurrentBootEntryKey is not evaluated.
1350 */
1351
1352 return STATUS_SUCCESS;
1353 }
1354
1355 NTSTATUS
SetBootStoreOptions(IN PVOID Handle,IN PBOOT_STORE_OPTIONS BootOptions,IN ULONG FieldsToChange)1356 SetBootStoreOptions(
1357 IN PVOID Handle,
1358 IN PBOOT_STORE_OPTIONS BootOptions,
1359 IN ULONG FieldsToChange)
1360 {
1361 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1362
1363 if (!BootStore || !BootOptions)
1364 return STATUS_INVALID_PARAMETER;
1365
1366 /*
1367 * NOTE: Currently we open & map the loader configuration file without
1368 * further tests. It's OK as long as we only deal with FreeLdr's freeldr.ini
1369 * and NTLDR's boot.ini files. But as soon as we'll implement support for
1370 * BOOTMGR detection, the "configuration file" will be the BCD registry
1371 * hive and then, we'll have instead to mount the hive & open it.
1372 */
1373
1374 //
1375 // FIXME!!
1376 //
1377
1378 // if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1379 if (BootStore->Type != FreeLdr && BootStore->Type != NtLdr)
1380 {
1381 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
1382 return STATUS_NOT_SUPPORTED;
1383 }
1384
1385 // if (BootOptions->Length < sizeof(*BootOptions))
1386 // return STATUS_INVALID_PARAMETER;
1387
1388 if (FieldsToChange & BOOT_OPTIONS_TIMEOUT)
1389 {
1390 WCHAR TimeoutStr[15];
1391 RtlStringCchPrintfW(TimeoutStr, ARRAYSIZE(TimeoutStr), L"%d", BootOptions->Timeout);
1392 IniAddKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
1393 BootOptionNames[BootStore->Type][BO_TimeOut],
1394 TimeoutStr);
1395 }
1396 if (FieldsToChange & BOOT_OPTIONS_NEXT_BOOTENTRY_KEY)
1397 {
1398 IniAddKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
1399 BootOptionNames[BootStore->Type][BO_DefaultOS],
1400 (PCWSTR)BootOptions->NextBootEntryKey);
1401 }
1402
1403 return STATUS_SUCCESS;
1404 }
1405
1406
1407 static NTSTATUS
FreeLdrEnumerateBootEntries(IN PBOOT_STORE_INI_CONTEXT BootStore,IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,IN PVOID Parameter OPTIONAL)1408 FreeLdrEnumerateBootEntries(
1409 IN PBOOT_STORE_INI_CONTEXT BootStore,
1410 // IN ULONG Flags, // Determine which data to retrieve
1411 IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
1412 IN PVOID Parameter OPTIONAL)
1413 {
1414 NTSTATUS Status = STATUS_SUCCESS;
1415 PINICACHEITERATOR Iterator;
1416 PINI_SECTION OsIniSection;
1417 PCWSTR SectionName, KeyData;
1418 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) +
1419 max(sizeof(NTOS_OPTIONS), sizeof(BOOTSECTOR_OPTIONS))];
1420 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
1421 PWCHAR Buffer;
1422
1423 /* Enumerate all the valid installations listed in the "Operating Systems" section */
1424 Iterator = IniFindFirstValue(BootStore->OsIniSection, &SectionName, &KeyData);
1425 if (!Iterator) return STATUS_SUCCESS;
1426 do
1427 {
1428 PCWSTR InstallName;
1429 ULONG InstallNameLength;
1430
1431 /* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */
1432 if (*KeyData == L'"')
1433 {
1434 /* Quoted name, copy up to the closing quote */
1435 PWCHAR End = wcschr(KeyData + 1, L'"');
1436
1437 if (End)
1438 {
1439 /* Skip the first quote */
1440 InstallName = KeyData + 1;
1441 InstallNameLength = End - InstallName;
1442 }
1443 else // if (!End)
1444 {
1445 /* No corresponding closing quote, so we include the first one in the InstallName */
1446 InstallName = KeyData;
1447 InstallNameLength = wcslen(InstallName);
1448 }
1449 if (InstallNameLength == 0) InstallName = NULL;
1450 }
1451 else
1452 {
1453 /* Non-quoted name, copy everything */
1454 InstallName = KeyData;
1455 InstallNameLength = wcslen(InstallName);
1456 if (InstallNameLength == 0) InstallName = NULL;
1457 }
1458
1459 /* Allocate the temporary buffer */
1460 Buffer = NULL;
1461 if (InstallNameLength)
1462 Buffer = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, (InstallNameLength + 1) * sizeof(WCHAR));
1463 if (Buffer)
1464 {
1465 RtlCopyMemory(Buffer, InstallName, InstallNameLength * sizeof(WCHAR));
1466 Buffer[InstallNameLength] = UNICODE_NULL;
1467 InstallName = Buffer;
1468 }
1469
1470 DPRINT("Boot entry '%S' in OS section '%S'\n", InstallName, SectionName);
1471
1472 BootEntry->Version = FreeLdr;
1473 BootEntry->BootEntryKey = MAKESTRKEY(SectionName);
1474 BootEntry->FriendlyName = InstallName;
1475 BootEntry->BootFilePath = NULL;
1476 BootEntry->OsOptionsLength = 0;
1477
1478 /* Search for an existing boot entry section */
1479 OsIniSection = IniGetSection(BootStore->IniCache, SectionName);
1480 if (!OsIniSection)
1481 goto DoEnum;
1482
1483 /* Check for supported boot type */
1484 if (!IniGetKey(OsIniSection, L"BootType", &KeyData) || !KeyData)
1485 {
1486 /* Certainly not a ReactOS installation */
1487 DPRINT1("No BootType value present\n");
1488 goto DoEnum;
1489 }
1490
1491 // TODO: What to do with "Windows" ; "WindowsNT40" ; "ReactOSSetup" ?
1492 if ((_wcsicmp(KeyData, L"Windows2003") == 0) ||
1493 (_wcsicmp(KeyData, L"\"Windows2003\"") == 0))
1494 {
1495 /* BootType is Windows2003 */
1496 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
1497
1498 DPRINT("This is a '%S' boot entry\n", KeyData);
1499
1500 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
1501 RtlCopyMemory(Options->Signature,
1502 NTOS_OPTIONS_SIGNATURE,
1503 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
1504
1505 // BootEntry->BootFilePath = NULL;
1506
1507 /* Check its SystemPath */
1508 Options->OsLoadPath = NULL;
1509 if (IniGetKey(OsIniSection, L"SystemPath", &KeyData))
1510 Options->OsLoadPath = KeyData;
1511 // KeyData == SystemRoot;
1512
1513 /* Check the optional Options */
1514 Options->OsLoadOptions = NULL;
1515 if (IniGetKey(OsIniSection, L"Options", &KeyData))
1516 Options->OsLoadOptions = KeyData;
1517 }
1518 else
1519 if ((_wcsicmp(KeyData, L"BootSector") == 0) ||
1520 (_wcsicmp(KeyData, L"\"BootSector\"") == 0))
1521 {
1522 /* BootType is BootSector */
1523 PBOOTSECTOR_OPTIONS Options = (PBOOTSECTOR_OPTIONS)&BootEntry->OsOptions;
1524
1525 DPRINT("This is a '%S' boot entry\n", KeyData);
1526
1527 BootEntry->OsOptionsLength = sizeof(BOOTSECTOR_OPTIONS);
1528 RtlCopyMemory(Options->Signature,
1529 BOOTSECTOR_OPTIONS_SIGNATURE,
1530 RTL_FIELD_SIZE(BOOTSECTOR_OPTIONS, Signature));
1531
1532 // BootEntry->BootFilePath = NULL;
1533
1534 /* Check its BootPath */
1535 Options->BootPath = NULL;
1536 if (IniGetKey(OsIniSection, L"BootPath", &KeyData))
1537 Options->BootPath = KeyData;
1538
1539 /* Check its BootSector */
1540 Options->FileName = NULL;
1541 if (IniGetKey(OsIniSection, L"BootSectorFile", &KeyData))
1542 Options->FileName = KeyData;
1543 }
1544 else
1545 {
1546 DPRINT1("Unrecognized BootType value '%S'\n", KeyData);
1547 // goto DoEnum;
1548 }
1549
1550 DoEnum:
1551 /* Call the user enumeration routine callback */
1552 Status = EnumBootEntriesRoutine(FreeLdr, BootEntry, Parameter);
1553
1554 /* Free temporary buffers */
1555 if (Buffer)
1556 RtlFreeHeap(ProcessHeap, 0, Buffer);
1557
1558 /* Stop the enumeration if needed */
1559 if (!NT_SUCCESS(Status))
1560 break;
1561 }
1562 while (IniFindNextValue(Iterator, &SectionName, &KeyData));
1563
1564 IniFindClose(Iterator);
1565 return Status;
1566 }
1567
1568 static NTSTATUS
NtLdrEnumerateBootEntries(IN PBOOT_STORE_INI_CONTEXT BootStore,IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,IN PVOID Parameter OPTIONAL)1569 NtLdrEnumerateBootEntries(
1570 IN PBOOT_STORE_INI_CONTEXT BootStore,
1571 // IN ULONG Flags, // Determine which data to retrieve
1572 IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
1573 IN PVOID Parameter OPTIONAL)
1574 {
1575 NTSTATUS Status = STATUS_SUCCESS;
1576 PINICACHEITERATOR Iterator;
1577 PCWSTR SectionName, KeyData;
1578 UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
1579 PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
1580 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
1581 PWCHAR Buffer;
1582 ULONG BufferLength;
1583
1584 /* Enumerate all the valid installations */
1585 Iterator = IniFindFirstValue(BootStore->OsIniSection, &SectionName, &KeyData);
1586 if (!Iterator) return STATUS_SUCCESS;
1587 do
1588 {
1589 PCWSTR InstallName, OsOptions;
1590 ULONG InstallNameLength, OsOptionsLength;
1591
1592 /* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */
1593 if (*KeyData == L'"')
1594 {
1595 /* Quoted name, copy up to the closing quote */
1596 OsOptions = wcschr(KeyData + 1, L'"');
1597
1598 /* Retrieve the starting point of the installation name and the OS options */
1599 if (OsOptions)
1600 {
1601 /* Skip the first quote */
1602 InstallName = KeyData + 1;
1603 InstallNameLength = OsOptions - InstallName;
1604 if (InstallNameLength == 0) InstallName = NULL;
1605
1606 /* Skip the ending quote (if found) */
1607 ++OsOptions;
1608
1609 /* Skip any whitespace */
1610 while (iswspace(*OsOptions)) ++OsOptions;
1611 /* Get its final length */
1612 OsOptionsLength = wcslen(OsOptions);
1613 if (OsOptionsLength == 0) OsOptions = NULL;
1614 }
1615 else
1616 {
1617 /* No corresponding closing quote, so we include the first one in the InstallName */
1618 InstallName = KeyData;
1619 InstallNameLength = wcslen(InstallName);
1620 if (InstallNameLength == 0) InstallName = NULL;
1621
1622 /* There are no OS options */
1623 // OsOptions = NULL;
1624 OsOptionsLength = 0;
1625 }
1626 }
1627 else
1628 {
1629 /* Non-quoted name, copy everything */
1630
1631 /* Retrieve the starting point of the installation name */
1632 InstallName = KeyData;
1633 InstallNameLength = wcslen(InstallName);
1634 if (InstallNameLength == 0) InstallName = NULL;
1635
1636 /* There are no OS options */
1637 OsOptions = NULL;
1638 OsOptionsLength = 0;
1639 }
1640
1641 /* Allocate the temporary buffer */
1642 Buffer = NULL;
1643 BufferLength = (InstallNameLength + OsOptionsLength) * sizeof(WCHAR);
1644 if (BufferLength)
1645 Buffer = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, BufferLength + 2*sizeof(UNICODE_NULL));
1646 if (Buffer)
1647 {
1648 PWCHAR ptr;
1649
1650 /* Copy the installation name, and make InstallName point into the buffer */
1651 if (InstallName && InstallNameLength)
1652 {
1653 ptr = Buffer;
1654 RtlCopyMemory(ptr, InstallName, InstallNameLength * sizeof(WCHAR));
1655 ptr[InstallNameLength] = UNICODE_NULL;
1656 InstallName = ptr;
1657 }
1658
1659 /* Copy the OS options, and make OsOptions point into the buffer */
1660 if (OsOptions && OsOptionsLength)
1661 {
1662 ptr = Buffer + InstallNameLength + 1;
1663 RtlCopyMemory(ptr, OsOptions, OsOptionsLength * sizeof(WCHAR));
1664 ptr[OsOptionsLength] = UNICODE_NULL;
1665 OsOptions = ptr;
1666 }
1667 }
1668
1669 DPRINT1("Boot entry '%S' in OS section (path) '%S'\n", InstallName, SectionName);
1670 // SectionName == SystemRoot;
1671
1672 BootEntry->Version = NtLdr;
1673 BootEntry->BootEntryKey = 0; // FIXME??
1674 BootEntry->FriendlyName = InstallName;
1675 BootEntry->BootFilePath = NULL;
1676
1677 BootEntry->OsOptionsLength = sizeof(NTOS_OPTIONS);
1678 RtlCopyMemory(Options->Signature,
1679 NTOS_OPTIONS_SIGNATURE,
1680 RTL_FIELD_SIZE(NTOS_OPTIONS, Signature));
1681
1682 Options->OsLoadPath = SectionName;
1683 Options->OsLoadOptions = OsOptions;
1684
1685 /* Call the user enumeration routine callback */
1686 Status = EnumBootEntriesRoutine(NtLdr, BootEntry, Parameter);
1687
1688 /* Free temporary buffers */
1689 if (Buffer)
1690 RtlFreeHeap(ProcessHeap, 0, Buffer);
1691
1692 /* Stop the enumeration if needed */
1693 if (!NT_SUCCESS(Status))
1694 break;
1695 }
1696 while (IniFindNextValue(Iterator, &SectionName, &KeyData));
1697
1698 IniFindClose(Iterator);
1699 return Status;
1700 }
1701
1702 NTSTATUS
EnumerateBootStoreEntries(IN PVOID Handle,IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,IN PVOID Parameter OPTIONAL)1703 EnumerateBootStoreEntries(
1704 IN PVOID Handle,
1705 // IN ULONG Flags, // Determine which data to retrieve
1706 IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine,
1707 IN PVOID Parameter OPTIONAL)
1708 {
1709 PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
1710
1711 if (!BootStore)
1712 return STATUS_INVALID_PARAMETER;
1713
1714 if (BootStore->Type >= BldrTypeMax || NtosBootLoaders[BootStore->Type].Type >= BldrTypeMax)
1715 {
1716 DPRINT1("Loader type %d is currently unsupported!\n", NtosBootLoaders[BootStore->Type].Type);
1717 /**/return STATUS_SUCCESS;/**/
1718 // return STATUS_INVALID_PARAMETER;
1719 }
1720
1721 return NtosBootLoaders[BootStore->Type].EnumBootStoreEntries(
1722 (PBOOT_STORE_INI_CONTEXT)BootStore, // Flags,
1723 EnumBootEntriesRoutine, Parameter);
1724 }
1725
1726 /* EOF */
1727