2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: NT 5.x family (MS Windows <= 2003, and ReactOS)
5 * operating systems detection code.
6 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
9 /* INCLUDES *****************************************************************/
13 #include "ntverrsrc.h"
14 // #include "arcname.h"
26 /* GLOBALS ******************************************************************/
28 /* Language-independent Vendor strings */
29 static const PCWSTR KnownVendors
[] = { L
"ReactOS", L
"Microsoft" };
32 /* FUNCTIONS ****************************************************************/
35 IsValidNTOSInstallation_UStr(
36 IN PUNICODE_STRING SystemRootPath
);
39 IsValidNTOSInstallation(
40 IN PCWSTR SystemRoot
);
42 static PNTOS_INSTALLATION
43 FindExistingNTOSInstall(
44 IN PGENERIC_LIST List
,
45 IN PCWSTR SystemRootArcPath OPTIONAL
,
46 IN PUNICODE_STRING SystemRootNtPath OPTIONAL
// or PCWSTR ?
49 static PNTOS_INSTALLATION
51 IN PGENERIC_LIST List
,
52 IN PCWSTR SystemRootArcPath
,
53 IN PUNICODE_STRING SystemRootNtPath
, // or PCWSTR ?
54 IN PCWSTR PathComponent
, // Pointer inside SystemRootNtPath buffer
56 IN ULONG PartitionNumber
,
57 IN PPARTENTRY PartEntry OPTIONAL
,
58 IN PCWSTR InstallationName
);
60 typedef struct _ENUM_INSTALLS_DATA
62 IN OUT PGENERIC_LIST List
;
63 IN PPARTLIST PartList
;
64 // IN PPARTENTRY PartEntry;
65 } ENUM_INSTALLS_DATA
, *PENUM_INSTALLS_DATA
;
67 // PENUM_BOOT_ENTRIES_ROUTINE
70 EnumerateInstallations(
71 IN BOOT_STORE_TYPE Type
,
72 IN PBOOT_STORE_ENTRY BootEntry
,
73 IN PVOID Parameter OPTIONAL
)
75 PENUM_INSTALLS_DATA Data
= (PENUM_INSTALLS_DATA
)Parameter
;
76 PNTOS_OPTIONS Options
= (PNTOS_OPTIONS
)&BootEntry
->OsOptions
;
78 PNTOS_INSTALLATION NtOsInstall
;
79 UNICODE_STRING SystemRootPath
;
80 WCHAR SystemRoot
[MAX_PATH
];
81 WCHAR InstallNameW
[MAX_PATH
];
83 ULONG DiskNumber
= 0, PartitionNumber
= 0;
84 PCWSTR PathComponent
= NULL
;
85 PDISKENTRY DiskEntry
= NULL
;
86 PPARTENTRY PartEntry
= NULL
;
88 /* We have a boot entry */
90 /* Check for supported boot type "Windows2003" */
91 if (BootEntry
->OsOptionsLength
< sizeof(NTOS_OPTIONS
) ||
92 RtlCompareMemory(&BootEntry
->OsOptions
/* Signature */,
93 NTOS_OPTIONS_SIGNATURE
,
94 RTL_FIELD_SIZE(NTOS_OPTIONS
, Signature
)) !=
95 RTL_FIELD_SIZE(NTOS_OPTIONS
, Signature
))
97 /* This is not a ReactOS entry */
98 // DPRINT1(" An installation '%S' of unsupported type '%S'\n",
99 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a");
100 DPRINT1(" An installation '%S' of unsupported type %lu\n",
101 BootEntry
->FriendlyName
, BootEntry
->OsOptionsLength
);
102 /* Continue the enumeration */
103 return STATUS_SUCCESS
;
106 /* BootType is Windows2003, now check OsLoadPath */
107 if (!Options
->OsLoadPath
|| !*Options
->OsLoadPath
)
109 /* Certainly not a ReactOS installation */
110 DPRINT1(" A Win2k3 install '%S' without an ARC path?!\n", BootEntry
->FriendlyName
);
111 /* Continue the enumeration */
112 return STATUS_SUCCESS
;
115 DPRINT1(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n",
116 BootEntry
->FriendlyName
, Options
->OsLoadPath
);
117 // DPRINT1(" Found a Win2k3 install '%S' with ARC path '%S'\n",
118 // BootEntry->FriendlyName, Options->OsLoadPath);
120 // TODO: Normalize the ARC path.
123 * Check whether we already have an installation with this ARC path.
124 * If this is the case, stop there.
126 NtOsInstall
= FindExistingNTOSInstall(Data
->List
, Options
->OsLoadPath
, NULL
);
129 DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
130 NtOsInstall
->InstallationName
, &NtOsInstall
->SystemArcPath
);
131 /* Continue the enumeration */
132 return STATUS_SUCCESS
;
136 * Convert the ARC path into an NT path, from which we will deduce
137 * the real disk drive & partition on which the candidate installation
138 * resides, as well verifying whether it is indeed an NTOS installation.
140 RtlInitEmptyUnicodeString(&SystemRootPath
, SystemRoot
, sizeof(SystemRoot
));
141 if (!ArcPathToNtPath(&SystemRootPath
, Options
->OsLoadPath
, Data
->PartList
))
143 DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", Options
->OsLoadPath
);
144 /* Continue the enumeration */
145 return STATUS_SUCCESS
;
148 DPRINT1("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n",
149 Options
->OsLoadPath
, &SystemRootPath
);
152 * Check whether we already have an installation with this NT path.
153 * If this is the case, stop there.
155 NtOsInstall
= FindExistingNTOSInstall(Data
->List
, NULL
/*Options->OsLoadPath*/, &SystemRootPath
);
158 DPRINT1(" An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
159 NtOsInstall
->InstallationName
, &NtOsInstall
->SystemNtPath
);
160 /* Continue the enumeration */
161 return STATUS_SUCCESS
;
164 DPRINT1("EnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath
);
166 /* Check if this is a valid NTOS installation; stop there if it isn't one */
167 if (!IsValidNTOSInstallation_UStr(&SystemRootPath
))
169 /* Continue the enumeration */
170 return STATUS_SUCCESS
;
173 DPRINT1("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n",
174 Options
->OsLoadPath
, &SystemRootPath
);
176 /* From the NT path, compute the disk, partition and path components */
177 if (NtPathToDiskPartComponents(SystemRootPath
.Buffer
, &DiskNumber
, &PartitionNumber
, &PathComponent
))
179 DPRINT1("SystemRootPath = '%wZ' points to disk #%d, partition #%d, path '%S'\n",
180 &SystemRootPath
, DiskNumber
, PartitionNumber
, PathComponent
);
182 /* Retrieve the corresponding disk and partition */
183 if (!GetDiskOrPartition(Data
->PartList
, DiskNumber
, PartitionNumber
, &DiskEntry
, &PartEntry
))
185 DPRINT1("GetDiskOrPartition(disk #%d, partition #%d) failed\n",
186 DiskNumber
, PartitionNumber
);
191 DPRINT1("NtPathToDiskPartComponents(%wZ) failed\n", &SystemRootPath
);
194 /* Add the discovered NTOS installation into the list */
195 if (PartEntry
&& PartEntry
->DriveLetter
)
197 /* We have retrieved a partition that is mounted */
198 RtlStringCchPrintfW(InstallNameW
, ARRAYSIZE(InstallNameW
),
200 PartEntry
->DriveLetter
,
202 BootEntry
->FriendlyName
);
206 /* We failed somewhere, just show the NT path */
207 RtlStringCchPrintfW(InstallNameW
, ARRAYSIZE(InstallNameW
),
210 BootEntry
->FriendlyName
);
212 AddNTOSInstallation(Data
->List
, Options
->OsLoadPath
,
213 &SystemRootPath
, PathComponent
,
214 DiskNumber
, PartitionNumber
, PartEntry
,
217 /* Continue the enumeration */
218 return STATUS_SUCCESS
;
222 * FindSubStrI(PCWSTR str, PCWSTR strSearch) :
223 * Searches for a sub-string 'strSearch' inside 'str', similarly to what
224 * wcsstr(str, strSearch) does, but ignores the case during the comparisons.
226 PCWSTR
FindSubStrI(PCWSTR str
, PCWSTR strSearch
)
239 while (*s1
&& *s2
&& (towupper(*s1
) == towupper(*s2
)))
252 CheckForValidPEAndVendor(
253 IN HANDLE RootDirectory OPTIONAL
,
254 IN PCWSTR PathNameToFile
,
255 OUT PUNICODE_STRING VendorName
258 BOOLEAN Success
= FALSE
;
260 HANDLE FileHandle
, SectionHandle
;
263 PVOID VersionBuffer
= NULL
; // Read-only
267 if (VendorName
->MaximumLength
< sizeof(UNICODE_NULL
))
270 *VendorName
->Buffer
= UNICODE_NULL
;
271 VendorName
->Length
= 0;
273 Status
= OpenAndMapFile(RootDirectory
, PathNameToFile
,
274 &FileHandle
, &SectionHandle
, &ViewBase
,
276 if (!NT_SUCCESS(Status
))
278 DPRINT1("Failed to open and map file '%S', Status 0x%08lx\n", PathNameToFile
, Status
);
279 return FALSE
; // Status;
282 /* Make sure it's a valid PE file */
283 if (!RtlImageNtHeader(ViewBase
))
285 DPRINT1("File '%S' does not seem to be a valid PE, bail out\n", PathNameToFile
);
286 Status
= STATUS_INVALID_IMAGE_FORMAT
;
291 * Search for a valid executable version and vendor.
292 * NOTE: The module is loaded as a data file, it should be marked as such.
294 Status
= NtGetVersionResource((PVOID
)((ULONG_PTR
)ViewBase
| 1), &VersionBuffer
, NULL
);
295 if (!NT_SUCCESS(Status
))
297 DPRINT1("Failed to get version resource for file '%S', Status 0x%08lx\n", PathNameToFile
, Status
);
301 Status
= NtVerQueryValue(VersionBuffer
, L
"\\VarFileInfo\\Translation", &pvData
, &BufLen
);
302 if (NT_SUCCESS(Status
))
304 USHORT wCodePage
= 0, wLangID
= 0;
305 WCHAR FileInfo
[MAX_PATH
];
307 wCodePage
= LOWORD(*(ULONG
*)pvData
);
308 wLangID
= HIWORD(*(ULONG
*)pvData
);
310 RtlStringCchPrintfW(FileInfo
, ARRAYSIZE(FileInfo
),
311 L
"StringFileInfo\\%04X%04X\\CompanyName",
314 Status
= NtVerQueryValue(VersionBuffer
, FileInfo
, &pvData
, &BufLen
);
316 /* Fixup the Status in case pvData is NULL */
317 if (NT_SUCCESS(Status
) && !pvData
)
318 Status
= STATUS_NOT_FOUND
;
320 if (NT_SUCCESS(Status
) /*&& pvData*/)
322 /* BufLen includes the NULL terminator count */
323 DPRINT1("Found version vendor: \"%S\" for file '%S'\n", pvData
, PathNameToFile
);
325 RtlStringCbCopyNW(VendorName
->Buffer
, VendorName
->MaximumLength
,
326 pvData
, BufLen
* sizeof(WCHAR
));
327 VendorName
->Length
= wcslen(VendorName
->Buffer
) * sizeof(WCHAR
);
333 if (!NT_SUCCESS(Status
))
334 DPRINT1("No version vendor found for file '%S'\n", PathNameToFile
);
337 /* Finally, unmap and close the file */
338 UnMapAndCloseFile(FileHandle
, SectionHandle
, ViewBase
);
344 // TODO: Instead of returning TRUE/FALSE, it would be nice to return
345 // a flag indicating:
346 // - whether the installation is actually valid;
347 // - if it's broken or not (aka. needs for repair, or just upgrading).
350 IsValidNTOSInstallationByHandle(
351 IN HANDLE SystemRootDirectory
)
353 BOOLEAN Success
= FALSE
;
356 UNICODE_STRING VendorName
;
357 WCHAR VendorNameBuffer
[MAX_PATH
];
359 /* Check for the existence of \SystemRoot\System32 */
360 PathName
= L
"System32\\";
361 if (!DoesDirExist(SystemRootDirectory
, PathName
))
363 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
367 /* Check for the existence of \SystemRoot\System32\drivers */
368 PathName
= L
"System32\\drivers\\";
369 if (!DoesDirExist(SystemRootDirectory
, PathName
))
371 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
375 /* Check for the existence of \SystemRoot\System32\config */
376 PathName
= L
"System32\\config\\";
377 if (!DoesDirExist(SystemRootDirectory
, PathName
))
379 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
385 * Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
386 * (but we don't check here whether they are actually valid).
388 PathName
= L
"System32\\config\\SYSTEM";
389 if (!DoesFileExist(SystemRootDirectory
, PathName
))
391 // DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
394 PathName
= L
"System32\\config\\SOFTWARE";
395 if (!DoesFileExist(SystemRootDirectory
, PathName
))
397 // DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
402 RtlInitEmptyUnicodeString(&VendorName
, VendorNameBuffer
, sizeof(VendorNameBuffer
));
404 /* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and retrieves its vendor name */
405 PathName
= L
"System32\\ntoskrnl.exe";
406 Success
= CheckForValidPEAndVendor(SystemRootDirectory
, PathName
, &VendorName
);
408 DPRINT1("Kernel executable '%S' is either not a PE file, or does not have any vendor?\n", PathName
);
410 /* The kernel gives the OS its flavour */
413 for (i
= 0; i
< ARRAYSIZE(KnownVendors
); ++i
)
415 Success
= !!FindSubStrI(VendorName
.Buffer
, KnownVendors
[i
]);
418 /* We have found a correct vendor combination */
419 DPRINT1("IsValidNTOSInstallation: We've got an NTOS installation from %S !\n", KnownVendors
[i
]);
425 /* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
427 /* Check for the existence of \SystemRoot\System32\ntdll.dll and retrieves its vendor name */
428 PathName
= L
"System32\\ntdll.dll";
429 Success
= CheckForValidPEAndVendor(SystemRootDirectory
, PathName
, &VendorName
);
431 DPRINT1("User-mode DLL '%S' is either not a PE file, or does not have any vendor?\n", PathName
);
434 for (i
= 0; i
< ARRAYSIZE(KnownVendors
); ++i
)
436 if (!!FindSubStrI(VendorName
.Buffer
, KnownVendors
[i
]))
438 /* We have found a correct vendor combination */
439 DPRINT1("IsValidNTOSInstallation: The user-mode DLL '%S' is from %S\n", PathName
, KnownVendors
[i
]);
449 IsValidNTOSInstallation_UStr(
450 IN PUNICODE_STRING SystemRootPath
)
453 OBJECT_ATTRIBUTES ObjectAttributes
;
454 IO_STATUS_BLOCK IoStatusBlock
;
455 HANDLE SystemRootDirectory
;
458 /* Open SystemRootPath */
459 InitializeObjectAttributes(&ObjectAttributes
,
461 OBJ_CASE_INSENSITIVE
,
464 Status
= NtOpenFile(&SystemRootDirectory
,
465 FILE_LIST_DIRECTORY
| FILE_TRAVERSE
| SYNCHRONIZE
,
468 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
469 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_DIRECTORY_FILE
);
470 if (!NT_SUCCESS(Status
))
472 DPRINT1("Failed to open SystemRoot '%wZ', Status 0x%08lx\n", SystemRootPath
, Status
);
476 Success
= IsValidNTOSInstallationByHandle(SystemRootDirectory
);
479 NtClose(SystemRootDirectory
);
484 IsValidNTOSInstallation(
485 IN PCWSTR SystemRoot
)
487 UNICODE_STRING SystemRootPath
;
488 RtlInitUnicodeString(&SystemRootPath
, SystemRoot
);
489 return IsValidNTOSInstallationByHandle(&SystemRootPath
);
494 IN PGENERIC_LIST List
)
496 PGENERIC_LIST_ENTRY Entry
;
497 PNTOS_INSTALLATION NtOsInstall
;
498 ULONG NtOsInstallsCount
= GetNumberOfListEntries(List
);
500 DPRINT1("There %s %d installation%s detected:\n",
501 NtOsInstallsCount
>= 2 ? "are" : "is",
503 NtOsInstallsCount
>= 2 ? "s" : "");
505 Entry
= GetFirstListEntry(List
);
508 NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryUserData(Entry
);
509 Entry
= GetNextListEntry(Entry
);
511 DPRINT1(" On disk #%d, partition #%d: Installation \"%S\" in SystemRoot '%wZ'\n",
512 NtOsInstall
->DiskNumber
, NtOsInstall
->PartitionNumber
,
513 NtOsInstall
->InstallationName
, &NtOsInstall
->SystemNtPath
);
519 static PNTOS_INSTALLATION
520 FindExistingNTOSInstall(
521 IN PGENERIC_LIST List
,
522 IN PCWSTR SystemRootArcPath OPTIONAL
,
523 IN PUNICODE_STRING SystemRootNtPath OPTIONAL
// or PCWSTR ?
526 PGENERIC_LIST_ENTRY Entry
;
527 PNTOS_INSTALLATION NtOsInstall
;
528 UNICODE_STRING SystemArcPath
;
531 * We search either via ARC path or NT path.
532 * If both pointers are NULL then we fail straight away.
534 if (!SystemRootArcPath
&& !SystemRootNtPath
)
537 RtlInitUnicodeString(&SystemArcPath
, SystemRootArcPath
);
539 Entry
= GetFirstListEntry(List
);
542 NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryUserData(Entry
);
543 Entry
= GetNextListEntry(Entry
);
546 * Note that if both ARC paths are equal, then the corresponding
547 * NT paths must be the same. However, two ARC paths may be different
548 * but resolve into the same NT path.
550 if ( (SystemRootArcPath
&&
551 RtlEqualUnicodeString(&NtOsInstall
->SystemArcPath
,
552 &SystemArcPath
, TRUE
)) ||
554 RtlEqualUnicodeString(&NtOsInstall
->SystemNtPath
,
555 SystemRootNtPath
, TRUE
)) )
565 static PNTOS_INSTALLATION
567 IN PGENERIC_LIST List
,
568 IN PCWSTR SystemRootArcPath
,
569 IN PUNICODE_STRING SystemRootNtPath
, // or PCWSTR ?
570 IN PCWSTR PathComponent
, // Pointer inside SystemRootNtPath buffer
572 IN ULONG PartitionNumber
,
573 IN PPARTENTRY PartEntry OPTIONAL
,
574 IN PCWSTR InstallationName
)
576 PNTOS_INSTALLATION NtOsInstall
;
577 SIZE_T ArcPathLength
, NtPathLength
;
578 CHAR InstallNameA
[MAX_PATH
];
580 /* Is there already any installation with these settings? */
581 NtOsInstall
= FindExistingNTOSInstall(List
, SystemRootArcPath
, SystemRootNtPath
);
584 DPRINT1("An NTOS installation with name \"%S\" already exists on disk #%d, partition #%d, in SystemRoot '%wZ'\n",
585 NtOsInstall
->InstallationName
, NtOsInstall
->DiskNumber
, NtOsInstall
->PartitionNumber
, &NtOsInstall
->SystemNtPath
);
587 // NOTE: We may use its "IsDefault" attribute, and only keep the entries that have IsDefault == TRUE...
588 // Setting IsDefault to TRUE would imply searching for the "Default" entry in the loader configuration file.
593 ArcPathLength
= (wcslen(SystemRootArcPath
) + 1) * sizeof(WCHAR
);
594 // NtPathLength = ROUND_UP(SystemRootNtPath->Length + sizeof(UNICODE_NULL), sizeof(WCHAR));
595 NtPathLength
= SystemRootNtPath
->Length
+ sizeof(UNICODE_NULL
);
597 /* None was found, so add a new one */
598 NtOsInstall
= RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
,
599 sizeof(*NtOsInstall
) +
600 ArcPathLength
+ NtPathLength
);
604 NtOsInstall
->DiskNumber
= DiskNumber
;
605 NtOsInstall
->PartitionNumber
= PartitionNumber
;
606 NtOsInstall
->PartEntry
= PartEntry
;
608 RtlInitEmptyUnicodeString(&NtOsInstall
->SystemArcPath
,
609 (PWCHAR
)(NtOsInstall
+ 1),
611 RtlCopyMemory(NtOsInstall
->SystemArcPath
.Buffer
, SystemRootArcPath
, ArcPathLength
);
612 NtOsInstall
->SystemArcPath
.Length
= ArcPathLength
- sizeof(UNICODE_NULL
);
614 RtlInitEmptyUnicodeString(&NtOsInstall
->SystemNtPath
,
615 (PWCHAR
)((ULONG_PTR
)(NtOsInstall
+ 1) + ArcPathLength
),
617 RtlCopyUnicodeString(&NtOsInstall
->SystemNtPath
, SystemRootNtPath
);
618 NtOsInstall
->PathComponent
= NtOsInstall
->SystemNtPath
.Buffer
+
619 (PathComponent
- SystemRootNtPath
->Buffer
);
621 RtlStringCchCopyW(NtOsInstall
->InstallationName
,
622 ARRAYSIZE(NtOsInstall
->InstallationName
),
625 // Having the GENERIC_LIST storing the display item string plainly sucks...
626 RtlStringCchPrintfA(InstallNameA
, ARRAYSIZE(InstallNameA
), "%S", InstallationName
);
627 AppendGenericListEntry(List
, InstallNameA
, NtOsInstall
, FALSE
);
633 FindNTOSInstallations(
634 IN OUT PGENERIC_LIST List
,
635 IN PPARTLIST PartList
,
636 IN PPARTENTRY PartEntry
)
639 ULONG DiskNumber
= PartEntry
->DiskEntry
->DiskNumber
;
640 ULONG PartitionNumber
= PartEntry
->PartitionNumber
;
641 HANDLE PartitionDirectoryHandle
;
642 OBJECT_ATTRIBUTES ObjectAttributes
;
643 IO_STATUS_BLOCK IoStatusBlock
;
644 UNICODE_STRING PartitionRootPath
;
645 BOOT_STORE_TYPE Type
;
646 PVOID BootStoreHandle
;
647 ENUM_INSTALLS_DATA Data
;
649 WCHAR PathBuffer
[MAX_PATH
];
651 /* Set PartitionRootPath */
652 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
653 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
654 DiskNumber
, PartitionNumber
);
655 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
656 DPRINT1("FindNTOSInstallations: PartitionRootPath: '%wZ'\n", &PartitionRootPath
);
658 /* Open the partition */
659 InitializeObjectAttributes(&ObjectAttributes
,
661 OBJ_CASE_INSENSITIVE
,
664 Status
= NtOpenFile(&PartitionDirectoryHandle
,
665 FILE_LIST_DIRECTORY
| FILE_TRAVERSE
| SYNCHRONIZE
,
668 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
669 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_DIRECTORY_FILE
);
670 if (!NT_SUCCESS(Status
))
672 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", &PartitionRootPath
, Status
);
677 Data
.PartList
= PartList
;
679 /* Try to see whether we recognize some NT boot loaders */
680 for (Type
= FreeLdr
; Type
< BldrTypeMax
; ++Type
)
682 Status
= FindBootStore(PartitionDirectoryHandle
, Type
, &Version
);
683 if (!NT_SUCCESS(Status
))
685 /* The loader does not exist, continue with another one */
686 DPRINT1("Loader type '%d' does not exist, or an error happened (Status 0x%08lx), continue with another one...\n",
691 /* The loader exists, try to enumerate its boot entries */
692 DPRINT1("Analyse the OS installations for loader type '%d' in disk #%d, partition #%d\n",
693 Type
, DiskNumber
, PartitionNumber
);
695 Status
= OpenBootStoreByHandle(&BootStoreHandle
, PartitionDirectoryHandle
, Type
, FALSE
);
696 if (!NT_SUCCESS(Status
))
698 DPRINT1("Could not open the NTOS boot store of type '%d' (Status 0x%08lx), continue with another one...\n",
702 EnumerateBootStoreEntries(BootStoreHandle
, EnumerateInstallations
, &Data
);
703 CloseBootStore(BootStoreHandle
);
706 /* Close the partition */
707 NtClose(PartitionDirectoryHandle
);
712 ShouldICheckThisPartition(
713 IN PPARTENTRY PartEntry
)
718 return PartEntry
->IsPartitioned
&&
719 !IsContainerPartition(PartEntry
->PartitionType
) /* alternatively: PartEntry->PartitionNumber != 0 */ &&
721 (PartEntry
->FormatState
== Preformatted
/* || PartEntry->FormatState == Formatted */);
724 // EnumerateNTOSInstallations
726 CreateNTOSInstallationsList(
727 IN PPARTLIST PartList
)
730 PLIST_ENTRY Entry
, Entry2
;
731 PDISKENTRY DiskEntry
;
732 PPARTENTRY PartEntry
;
734 List
= CreateGenericList();
738 /* Loop each available disk ... */
739 Entry
= PartList
->DiskListHead
.Flink
;
740 while (Entry
!= &PartList
->DiskListHead
)
742 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
743 Entry
= Entry
->Flink
;
745 DPRINT1("Disk #%d\n", DiskEntry
->DiskNumber
);
747 /* ... and for each disk, loop each available partition */
749 /* First, the primary partitions */
750 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
751 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
753 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
754 Entry2
= Entry2
->Flink
;
756 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
758 DPRINT1(" Primary Partition #%d, index %d - Type 0x%02x, IsLogical = %s, IsPartitioned = %s, IsNew = %s, AutoCreate = %s, FormatState = %lu -- Should I check it? %s\n",
759 PartEntry
->PartitionNumber
, PartEntry
->PartitionIndex
,
760 PartEntry
->PartitionType
, PartEntry
->LogicalPartition
? "TRUE" : "FALSE",
761 PartEntry
->IsPartitioned
? "TRUE" : "FALSE",
762 PartEntry
->New
? "Yes" : "No",
763 PartEntry
->AutoCreate
? "Yes" : "No",
764 PartEntry
->FormatState
,
765 ShouldICheckThisPartition(PartEntry
) ? "YES!" : "NO!");
767 if (ShouldICheckThisPartition(PartEntry
))
768 FindNTOSInstallations(List
, PartList
, PartEntry
);
771 /* Then, the logical partitions (present in the extended partition) */
772 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
773 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
775 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
776 Entry2
= Entry2
->Flink
;
778 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
780 DPRINT1(" Logical Partition #%d, index %d - Type 0x%02x, IsLogical = %s, IsPartitioned = %s, IsNew = %s, AutoCreate = %s, FormatState = %lu -- Should I check it? %s\n",
781 PartEntry
->PartitionNumber
, PartEntry
->PartitionIndex
,
782 PartEntry
->PartitionType
, PartEntry
->LogicalPartition
? "TRUE" : "FALSE",
783 PartEntry
->IsPartitioned
? "TRUE" : "FALSE",
784 PartEntry
->New
? "Yes" : "No",
785 PartEntry
->AutoCreate
? "Yes" : "No",
786 PartEntry
->FormatState
,
787 ShouldICheckThisPartition(PartEntry
) ? "YES!" : "NO!");
789 if (ShouldICheckThisPartition(PartEntry
))
790 FindNTOSInstallations(List
, PartList
, PartEntry
);
794 /**** Debugging: List all the collected installations ****/
795 DumpNTOSInstalls(List
);