ReactOS 0.4.16-dev-178-g8ba6102
osdetect.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: NT 5.x family (MS Windows <= 2003, and ReactOS)
5 * operating systems detection code.
6 * COPYRIGHT: Copyright 2017-2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include "precomp.h"
12
13#include "ntverrsrc.h"
14// #include "arcname.h"
15#include "bldrsup.h"
16#include "filesup.h"
17#include "genlist.h"
18#include "partlist.h"
19#include "arcname.h"
20#include "osdetect.h"
21
22#define NDEBUG
23#include <debug.h>
24
25
26/* GLOBALS ******************************************************************/
27
28/* Language-independent Vendor strings */
30
31
32/* FUNCTIONS ****************************************************************/
33
34static BOOLEAN
36 IN PUNICODE_STRING SystemRootPath,
37 OUT PUSHORT Machine OPTIONAL,
39
43 IN PCWSTR SystemRootArcPath OPTIONAL,
44 IN PUNICODE_STRING SystemRootNtPath OPTIONAL // or PCWSTR ?
45 );
46
50 _In_ PCWSTR InstallationName,
51 _In_ USHORT Machine,
53 _In_ PCWSTR SystemRootArcPath,
54 _In_ PUNICODE_STRING SystemRootNtPath, // or PCWSTR ?
55 _In_ PCWSTR PathComponent, // Pointer inside SystemRootNtPath buffer
56 _In_ ULONG DiskNumber,
58
59typedef struct _ENUM_INSTALLS_DATA
60{
64
65// PENUM_BOOT_ENTRIES_ROUTINE
66static NTSTATUS
70 IN PBOOT_STORE_ENTRY BootEntry,
72{
74 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
75 PNTOS_INSTALLATION NtOsInstall;
76
77 ULONG DiskNumber = 0, PartitionNumber = 0;
79
80 UNICODE_STRING SystemRootPath;
82
83 USHORT Machine;
85 WCHAR VendorNameBuffer[MAX_PATH];
86
87
88 /* We have a boot entry */
89
90 /* Check for supported boot type "Windows2003" */
91 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) ||
92 RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
96 {
97 /* This is not a ReactOS entry */
98 // DPRINT(" An installation '%S' of unsupported type '%S'\n",
99 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a");
100 DPRINT(" An installation '%S' of unsupported type %lu\n",
101 BootEntry->FriendlyName, BootEntry->OsOptionsLength);
102 /* Continue the enumeration */
103 return STATUS_SUCCESS;
104 }
105
106 /* BootType is Windows2003, now check OsLoadPath */
107 if (!Options->OsLoadPath || !*Options->OsLoadPath)
108 {
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;
113 }
114
115 DPRINT(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n",
116 BootEntry->FriendlyName, Options->OsLoadPath);
117 // DPRINT(" Found a Win2k3 install '%S' with ARC path '%S'\n",
118 // BootEntry->FriendlyName, Options->OsLoadPath);
119
120 // TODO: Normalize the ARC path.
121
122 /*
123 * Check whether we already have an installation with this ARC path.
124 * If this is the case, stop there.
125 */
126 NtOsInstall = FindExistingNTOSInstall(Data->List, Options->OsLoadPath, NULL);
127 if (NtOsInstall)
128 {
129 DPRINT(" An NTOS installation with name \"%S\" from vendor \"%S\" already exists in SystemRoot '%wZ'\n",
130 NtOsInstall->InstallationName, NtOsInstall->VendorName, &NtOsInstall->SystemArcPath);
131 /* Continue the enumeration */
132 return STATUS_SUCCESS;
133 }
134
135 /*
136 * Convert the ARC path into an NT path, from which we will deduce the
137 * real disk & partition on which the candidate installation resides,
138 * as well as verifying whether it is indeed an NTOS installation.
139 */
140 RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
141 if (!ArcPathToNtPath(&SystemRootPath, Options->OsLoadPath, Data->PartList))
142 {
143 DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", Options->OsLoadPath);
144 /* Continue the enumeration */
145 return STATUS_SUCCESS;
146 }
147
148 DPRINT("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n",
149 Options->OsLoadPath, &SystemRootPath);
150
151 /*
152 * Check whether we already have an installation with this NT path.
153 * If this is the case, stop there.
154 */
155 NtOsInstall = FindExistingNTOSInstall(Data->List, NULL /*Options->OsLoadPath*/, &SystemRootPath);
156 if (NtOsInstall)
157 {
158 DPRINT1(" An NTOS installation with name \"%S\" from vendor \"%S\" already exists in SystemRoot '%wZ'\n",
159 NtOsInstall->InstallationName, NtOsInstall->VendorName, &NtOsInstall->SystemNtPath);
160 /* Continue the enumeration */
161 return STATUS_SUCCESS;
162 }
163
164 DPRINT("EnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
165
166 /* Check if this is a valid NTOS installation; stop there if it isn't one */
167 RtlInitEmptyUnicodeString(&VendorName, VendorNameBuffer, sizeof(VendorNameBuffer));
168 if (!IsValidNTOSInstallation(&SystemRootPath, &Machine, &VendorName))
169 {
170 /* Continue the enumeration */
171 return STATUS_SUCCESS;
172 }
173
174 DPRINT("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n",
175 Options->OsLoadPath, &SystemRootPath);
176
177 /* From the NT path, compute the disk, partition and path components */
178 if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
179 {
180 DPRINT("SystemRootPath = '%wZ' points to disk #%d, partition #%d, path '%S'\n",
181 &SystemRootPath, DiskNumber, PartitionNumber, PathComponent);
182 }
183 else
184 {
185 DPRINT1("NtPathToDiskPartComponents(%wZ) failed\n", &SystemRootPath);
186 }
187
188 /* Add the discovered NTOS installation into the list */
189 NtOsInstall = AddNTOSInstallation(Data->List,
190 BootEntry->FriendlyName,
191 Machine,
192 VendorName.Buffer, // FIXME: What if it's not NULL-terminated?
193 Options->OsLoadPath,
194 &SystemRootPath, PathComponent,
195 DiskNumber, PartitionNumber);
196 if (NtOsInstall)
197 {
198 /* Retrieve the volume corresponding to the disk and partition numbers */
199 PPARTENTRY PartEntry = SelectPartition(Data->PartList, DiskNumber, PartitionNumber);
200 if (!PartEntry)
201 {
202 DPRINT1("SelectPartition(disk #%d, partition #%d) failed\n",
203 DiskNumber, PartitionNumber);
204 }
205 NtOsInstall->Volume = (PartEntry ? PartEntry->Volume : NULL);
206 }
207
208 /* Continue the enumeration */
209 return STATUS_SUCCESS;
210}
211
212/*
213 * FindSubStrI(PCWSTR str, PCWSTR strSearch) :
214 * Searches for a sub-string 'strSearch' inside 'str', similarly to what
215 * wcsstr(str, strSearch) does, but ignores the case during the comparisons.
216 */
218{
219 PCWSTR cp = str;
220 PCWSTR s1, s2;
221
222 if (!*strSearch)
223 return str;
224
225 while (*cp)
226 {
227 s1 = cp;
228 s2 = strSearch;
229
230 while (*s1 && *s2 && (towupper(*s1) == towupper(*s2)))
231 ++s1, ++s2;
232
233 if (!*s2)
234 return cp;
235
236 ++cp;
237 }
238
239 return NULL;
240}
241
242static BOOLEAN
245 IN PCWSTR PathNameToFile,
246 OUT PUSHORT Machine,
248{
251 HANDLE FileHandle, SectionHandle;
252 // SIZE_T ViewSize;
253 PVOID ViewBase;
254 PIMAGE_NT_HEADERS NtHeader;
255 PVOID VersionBuffer = NULL; // Read-only
256 PVOID pvData = NULL;
257 UINT BufLen = 0;
258
259 if (VendorName->MaximumLength < sizeof(UNICODE_NULL))
260 return FALSE;
261
262 *VendorName->Buffer = UNICODE_NULL;
263 VendorName->Length = 0;
264
265 Status = OpenAndMapFile(RootDirectory, PathNameToFile,
267 &SectionHandle, &ViewBase, FALSE);
268 if (!NT_SUCCESS(Status))
269 {
270 DPRINT1("Failed to open and map file '%S', Status 0x%08lx\n", PathNameToFile, Status);
271 return FALSE; // Status;
272 }
273
274 /* Make sure it's a valid NT PE file */
275 NtHeader = RtlImageNtHeader(ViewBase);
276 if (!NtHeader)
277 {
278 DPRINT1("File '%S' does not seem to be a valid NT PE file, bail out\n", PathNameToFile);
280 goto UnmapCloseFile;
281 }
282
283 /* Retrieve the target architecture of this PE module */
284 *Machine = NtHeader->FileHeader.Machine;
285
286 /*
287 * Search for a valid executable version and vendor.
288 * NOTE: The module is loaded as a data file, it should be marked as such.
289 */
290 Status = NtGetVersionResource((PVOID)((ULONG_PTR)ViewBase | 1), &VersionBuffer, NULL);
291 if (!NT_SUCCESS(Status))
292 {
293 DPRINT1("Failed to get version resource for file '%S', Status 0x%08lx\n", PathNameToFile, Status);
294 goto UnmapCloseFile;
295 }
296
297 Status = NtVerQueryValue(VersionBuffer, L"\\VarFileInfo\\Translation", &pvData, &BufLen);
298 if (NT_SUCCESS(Status))
299 {
300 USHORT wCodePage = 0, wLangID = 0;
302
303 wCodePage = LOWORD(*(ULONG*)pvData);
304 wLangID = HIWORD(*(ULONG*)pvData);
305
307 L"StringFileInfo\\%04X%04X\\CompanyName",
308 wCodePage, wLangID);
309
310 Status = NtVerQueryValue(VersionBuffer, FileInfo, &pvData, &BufLen);
311
312 /* Fixup the Status in case pvData is NULL */
313 if (NT_SUCCESS(Status) && !pvData)
315
316 if (NT_SUCCESS(Status) /*&& pvData*/)
317 {
318 /* BufLen includes the NULL terminator count */
319 DPRINT("Found version vendor: \"%S\" for file '%S'\n", pvData, PathNameToFile);
320
321 RtlStringCbCopyNW(VendorName->Buffer, VendorName->MaximumLength,
322 pvData, BufLen * sizeof(WCHAR));
323 VendorName->Length = (USHORT)wcslen(VendorName->Buffer) * sizeof(WCHAR);
324
325 Success = TRUE;
326 }
327 }
328
329 if (!NT_SUCCESS(Status))
330 DPRINT("No version vendor found for file '%S'\n", PathNameToFile);
331
332UnmapCloseFile:
333 /* Finally, unmap and close the file */
334 UnMapAndCloseFile(FileHandle, SectionHandle, ViewBase);
335
336 return Success;
337}
338
339//
340// TODO: Instead of returning TRUE/FALSE, it would be nice to return
341// a flag indicating:
342// - whether the installation is actually valid;
343// - if it's broken or not (aka. needs for repair, or just upgrading).
344//
345static BOOLEAN
347 IN HANDLE SystemRootDirectory,
348 OUT PUSHORT Machine OPTIONAL,
350{
352 PCWSTR PathName;
353 USHORT i;
354 USHORT LocalMachine;
355 UNICODE_STRING LocalVendorName;
356 WCHAR VendorNameBuffer[MAX_PATH];
357
358 /* Check for VendorName validity */
359 if (VendorName->MaximumLength < sizeof(UNICODE_NULL))
360 {
361 /* Don't use it, invalidate the pointer */
363 }
364 else
365 {
366 /* Zero it out */
367 *VendorName->Buffer = UNICODE_NULL;
368 VendorName->Length = 0;
369 }
370
371 /* Check for the existence of \SystemRoot\System32 */
372 PathName = L"System32\\";
373 if (!DoesDirExist(SystemRootDirectory, PathName))
374 {
375 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
376 return FALSE;
377 }
378
379 /* Check for the existence of \SystemRoot\System32\drivers */
380 PathName = L"System32\\drivers\\";
381 if (!DoesDirExist(SystemRootDirectory, PathName))
382 {
383 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
384 return FALSE;
385 }
386
387 /* Check for the existence of \SystemRoot\System32\config */
388 PathName = L"System32\\config\\";
389 if (!DoesDirExist(SystemRootDirectory, PathName))
390 {
391 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
392 return FALSE;
393 }
394
395#if 0
396 /*
397 * Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
398 * (but we don't check here whether they are actually valid).
399 */
400 PathName = L"System32\\config\\SYSTEM";
401 if (!DoesFileExist(SystemRootDirectory, PathName))
402 {
403 // DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
404 return FALSE;
405 }
406 PathName = L"System32\\config\\SOFTWARE";
407 if (!DoesFileExist(SystemRootDirectory, PathName))
408 {
409 // DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
410 return FALSE;
411 }
412#endif
413
414 RtlInitEmptyUnicodeString(&LocalVendorName, VendorNameBuffer, sizeof(VendorNameBuffer));
415
416 /* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and retrieves its vendor name */
417 PathName = L"System32\\ntoskrnl.exe";
418 Success = CheckForValidPEAndVendor(SystemRootDirectory, PathName, &LocalMachine, &LocalVendorName);
419 if (!Success)
420 DPRINT1("Kernel executable '%S' is either not a PE file, or does not have any vendor?\n", PathName);
421
422 /*
423 * The kernel gives the OS its flavour. If we failed due to the absence of
424 * ntoskrnl.exe this might be due to the fact this particular installation
425 * uses a custom kernel that has a different name, overridden in the boot
426 * parameters. We then rely on the existence of ntdll.dll, which cannot be
427 * renamed on a valid NT system.
428 */
429 if (Success)
430 {
431 for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
432 {
433 Success = !!FindSubStrI(LocalVendorName.Buffer, KnownVendors[i]);
434 if (Success)
435 {
436 /* We have found a correct vendor combination */
437 DPRINT("IsValidNTOSInstallation: We've got an NTOS installation from %S !\n", KnownVendors[i]);
438 break;
439 }
440 }
441
442 /* Return the target architecture */
443 if (Machine)
444 {
445 /* Copy the value and invalidate the pointer */
446 *Machine = LocalMachine;
447 Machine = NULL;
448 }
449
450 /* Return the vendor name */
451 if (VendorName)
452 {
453 /* Copy the string and invalidate the pointer */
454 RtlCopyUnicodeString(VendorName, &LocalVendorName);
456 }
457 }
458
459 /* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
460
461 /* Check for the existence of \SystemRoot\System32\ntdll.dll and retrieves its vendor name */
462 PathName = L"System32\\ntdll.dll";
463 Success = CheckForValidPEAndVendor(SystemRootDirectory, PathName, &LocalMachine, &LocalVendorName);
464 if (!Success)
465 DPRINT1("User-mode DLL '%S' is either not a PE file, or does not have any vendor?\n", PathName);
466
467 if (Success)
468 {
469 for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
470 {
471 if (!!FindSubStrI(LocalVendorName.Buffer, KnownVendors[i]))
472 {
473 /* We have found a correct vendor combination */
474 DPRINT("IsValidNTOSInstallation: The user-mode DLL '%S' is from %S\n", PathName, KnownVendors[i]);
475 break;
476 }
477 }
478
479 /* Return the target architecture if not already obtained */
480 if (Machine)
481 {
482 /* Copy the value and invalidate the pointer */
483 *Machine = LocalMachine;
484 Machine = NULL;
485 }
486
487 /* Return the vendor name if not already obtained */
488 if (VendorName)
489 {
490 /* Copy the string and invalidate the pointer */
491 RtlCopyUnicodeString(VendorName, &LocalVendorName);
493 }
494 }
495
496 return Success;
497}
498
499static BOOLEAN
501 IN PUNICODE_STRING SystemRootPath,
502 OUT PUSHORT Machine,
504{
508 HANDLE SystemRootDirectory;
510
511 /* Open SystemRootPath */
513 SystemRootPath,
515 NULL,
516 NULL);
517 Status = NtOpenFile(&SystemRootDirectory,
523 if (!NT_SUCCESS(Status))
524 {
525 DPRINT1("Failed to open SystemRoot '%wZ', Status 0x%08lx\n", SystemRootPath, Status);
526 return FALSE;
527 }
528
529 Success = IsValidNTOSInstallationByHandle(SystemRootDirectory,
530 Machine, VendorName);
531
532 /* Done! */
533 NtClose(SystemRootDirectory);
534 return Success;
535}
536
537#ifndef NDEBUG
538static VOID
539DumpNTOSInstalls(
541{
543 PNTOS_INSTALLATION NtOsInstall;
544 ULONG NtOsInstallsCount = GetNumberOfListEntries(List);
545
546 DPRINT("There %s %d installation%s detected:\n",
547 NtOsInstallsCount >= 2 ? "are" : "is",
548 NtOsInstallsCount,
549 NtOsInstallsCount >= 2 ? "s" : "");
550
552 {
554
555 DPRINT(" On disk #%d, partition #%d: Installation \"%S\" in SystemRoot '%wZ'\n",
556 NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber,
557 NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
558 }
559
560 DPRINT("Done.\n");
561}
562#endif
563
567 IN PCWSTR SystemRootArcPath OPTIONAL,
568 IN PUNICODE_STRING SystemRootNtPath OPTIONAL // or PCWSTR ?
569 )
570{
572 PNTOS_INSTALLATION NtOsInstall;
573 UNICODE_STRING SystemArcPath;
574
575 /*
576 * We search either via ARC path or NT path.
577 * If both pointers are NULL then we fail straight away.
578 */
579 if (!SystemRootArcPath && !SystemRootNtPath)
580 return NULL;
581
582 RtlInitUnicodeString(&SystemArcPath, SystemRootArcPath);
583
585 {
587
588 /*
589 * Note that if both ARC paths are equal, then the corresponding
590 * NT paths must be the same. However, two ARC paths may be different
591 * but resolve into the same NT path.
592 */
593 if ( (SystemRootArcPath &&
595 &SystemArcPath, TRUE)) ||
596 (SystemRootNtPath &&
598 SystemRootNtPath, TRUE)) )
599 {
600 /* Found it! */
601 return NtOsInstall;
602 }
603 }
604
605 return NULL;
606}
607
611 _In_ PCWSTR InstallationName,
612 _In_ USHORT Machine,
614 _In_ PCWSTR SystemRootArcPath,
615 _In_ PUNICODE_STRING SystemRootNtPath, // or PCWSTR ?
616 _In_ PCWSTR PathComponent, // Pointer inside SystemRootNtPath buffer
617 _In_ ULONG DiskNumber,
619{
620 PNTOS_INSTALLATION NtOsInstall;
621 SIZE_T ArcPathLength, NtPathLength;
622
623 /* Is there already any installation with these settings? */
624 NtOsInstall = FindExistingNTOSInstall(List, SystemRootArcPath, SystemRootNtPath);
625 if (NtOsInstall)
626 {
627 DPRINT1("An NTOS installation with name \"%S\" from vendor \"%S\" already exists on disk #%d, partition #%d, in SystemRoot '%wZ'\n",
628 NtOsInstall->InstallationName, NtOsInstall->VendorName,
629 NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber, &NtOsInstall->SystemNtPath);
630 //
631 // NOTE: We may use its "IsDefault" attribute, and only keep the entries that have IsDefault == TRUE...
632 // Setting IsDefault to TRUE would imply searching for the "Default" entry in the loader configuration file.
633 //
634 return NtOsInstall;
635 }
636
637 ArcPathLength = (wcslen(SystemRootArcPath) + 1) * sizeof(WCHAR);
638 // NtPathLength = ROUND_UP(SystemRootNtPath->Length + sizeof(UNICODE_NULL), sizeof(WCHAR));
639 NtPathLength = SystemRootNtPath->Length + sizeof(UNICODE_NULL);
640
641 /* None was found, so add a new one */
643 sizeof(*NtOsInstall) +
644 ArcPathLength + NtPathLength);
645 if (!NtOsInstall)
646 return NULL;
647
648 NtOsInstall->DiskNumber = DiskNumber;
649 NtOsInstall->PartitionNumber = PartitionNumber;
650 NtOsInstall->Machine = Machine;
651
652 RtlInitEmptyUnicodeString(&NtOsInstall->SystemArcPath,
653 (PWCHAR)(NtOsInstall + 1),
654 ArcPathLength);
655 RtlCopyMemory(NtOsInstall->SystemArcPath.Buffer, SystemRootArcPath, ArcPathLength);
656 NtOsInstall->SystemArcPath.Length = ArcPathLength - sizeof(UNICODE_NULL);
657
658 RtlInitEmptyUnicodeString(&NtOsInstall->SystemNtPath,
659 (PWCHAR)((ULONG_PTR)(NtOsInstall + 1) + ArcPathLength),
660 NtPathLength);
661 RtlCopyUnicodeString(&NtOsInstall->SystemNtPath, SystemRootNtPath);
662 NtOsInstall->PathComponent = NtOsInstall->SystemNtPath.Buffer +
663 (PathComponent - SystemRootNtPath->Buffer);
664
666 ARRAYSIZE(NtOsInstall->InstallationName),
667 InstallationName);
668
669 RtlStringCchCopyW(NtOsInstall->VendorName,
670 ARRAYSIZE(NtOsInstall->VendorName),
671 VendorName);
672
673 AppendGenericListEntry(List, NtOsInstall, FALSE);
674
675 return NtOsInstall;
676}
677
678static VOID
681 _In_ PPARTLIST PartList,
683{
685 HANDLE VolumeRootDirHandle;
688 UNICODE_STRING VolumeRootPath;
690 PVOID BootStoreHandle;
694
695 /* Set VolumeRootPath */
696 RtlStringCchPrintfW(PathBuffer, _countof(PathBuffer),
697 L"%s\\", Volume->Info.DeviceName);
698 RtlInitUnicodeString(&VolumeRootPath, PathBuffer);
699 DPRINT("FindNTOSInstallations(%wZ)\n", &VolumeRootPath);
700
701 /* Open the volume */
703 &VolumeRootPath,
705 NULL,
706 NULL);
707 Status = NtOpenFile(&VolumeRootDirHandle,
713 if (!NT_SUCCESS(Status))
714 {
715 DPRINT1("Failed to open volume '%wZ', Status 0x%08lx\n", &VolumeRootPath, Status);
716 return;
717 }
718
719 Data.List = List;
720 Data.PartList = PartList;
721
722 /* Try to see whether we recognize some NT boot loaders */
723 for (Type = FreeLdr; Type < BldrTypeMax; ++Type)
724 {
725 Status = FindBootStore(VolumeRootDirHandle, Type, &Version);
726 if (!NT_SUCCESS(Status))
727 {
728 /* The loader does not exist, continue with another one */
729 DPRINT("Loader type '%d' does not exist, or an error happened (Status 0x%08lx), continue with another one...\n",
730 Type, Status);
731 continue;
732 }
733
734 /* The loader exists, try to enumerate its boot entries */
735 DPRINT("Analyze the OS installations for loader type '%d' in Volume %wZ (Disk #%d, Partition #%d)\n",
736 Type, &VolumeRootPath,
737 Volume->PartEntry->DiskEntry->DiskNumber,
738 Volume->PartEntry->PartitionNumber);
739
740 Status = OpenBootStoreByHandle(&BootStoreHandle, VolumeRootDirHandle, Type,
742 if (!NT_SUCCESS(Status))
743 {
744 DPRINT1("Could not open the NTOS boot store of type '%d' (Status 0x%08lx), continue with another one...\n",
745 Type, Status);
746 continue;
747 }
749 CloseBootStore(BootStoreHandle);
750 }
751
752 /* Close the volume */
753 NtClose(VolumeRootDirHandle);
754}
755
761// EnumerateNTOSInstallations
764 _In_ PPARTLIST PartList)
765{
770
772 if (!List)
773 return NULL;
774
775 /* Loop each available volume */
776 for (Entry = PartList->VolumesList.Flink;
777 Entry != &PartList->VolumesList;
778 Entry = Entry->Flink)
779 {
780 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
781 /* Valid OS installations can be found only on basic volumes */
782 if (!Volume->PartEntry) // TODO: In the future: (!Volume->IsSimpleVolume)
783 continue;
784
785 CheckVolume = (!Volume->New && (Volume->FormatState == Formatted));
786
787#ifndef NDEBUG
788 {
789 PPARTENTRY PartEntry = Volume->PartEntry;
790 ASSERT(PartEntry->Volume == Volume);
791 DPRINT("Volume %S (%c%c) on Disk #%d, Partition #%d (%s), "
792 "index %d - Type 0x%02x, IsVolNew = %s, FormatState = %lu -- Should I check it? %s\n",
793 Volume->Info.DeviceName,
794 !Volume->Info.DriveLetter ? '-' : (CHAR)Volume->Info.DriveLetter,
795 !Volume->Info.DriveLetter ? '-' : ':',
796 PartEntry->DiskEntry->DiskNumber,
797 PartEntry->PartitionNumber,
798 PartEntry->LogicalPartition ? "Logical" : "Primary",
799 PartEntry->PartitionIndex,
800 PartEntry->PartitionType,
801 Volume->New ? "Yes" : "No",
802 Volume->FormatState,
803 CheckVolume ? "YES!" : "NO!");
804 }
805#endif
806
807 if (CheckVolume)
809 }
810
811#ifndef NDEBUG
812 /**** Debugging: List all the collected installations ****/
813 DumpNTOSInstalls(List);
814#endif
815
816 return List;
817}
818
819/* EOF */
static const char VendorName[]
Definition: ParaNdis-Oid.c:36
unsigned char BOOLEAN
Type
Definition: Type.h:7
static NTSTATUS CheckVolume(IN PCWSTR VolumePath, IN LONG TimeOut, IN BOOLEAN CheckOnlyIfDirty)
Definition: autochk.c:391
LONG NTSTATUS
Definition: precomp.h:26
HANDLE ProcessHeap
Definition: servman.c:15
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
#define DPRINT1
Definition: precomp.h:8
BOOLEAN ArcPathToNtPath(OUT PUNICODE_STRING NtPath, IN PCWSTR ArcPath, IN PPARTLIST PartList OPTIONAL)
Definition: arcname.c:819
WCHAR RootDirectory[MAX_PATH]
Definition: format.c:74
NTSTATUS OpenBootStoreByHandle(_Out_ PVOID *Handle, _In_ HANDLE PartitionDirectoryHandle, _In_ BOOT_STORE_TYPE Type, _In_ BOOT_STORE_OPENMODE OpenMode, _In_ BOOT_STORE_ACCESS Access)
Definition: bldrsup.c:897
NTSTATUS CloseBootStore(_In_ PVOID Handle)
Definition: bldrsup.c:1014
NTSTATUS EnumerateBootStoreEntries(IN PVOID Handle, IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine, IN PVOID Parameter OPTIONAL)
Definition: bldrsup.c:1703
NTSTATUS FindBootStore(IN HANDLE PartitionDirectoryHandle, IN BOOT_STORE_TYPE Type, OUT PULONG VersionNumber OPTIONAL)
Definition: bldrsup.c:151
@ BS_ReadAccess
Definition: bldrsup.h:144
@ BldrTypeMax
Definition: bldrsup.h:18
@ FreeLdr
Definition: bldrsup.h:15
struct _NTOS_OPTIONS * PNTOS_OPTIONS
@ BS_OpenExisting
Definition: bldrsup.h:135
#define NTOS_OPTIONS_SIGNATURE
Definition: bldrsup.h:102
enum _BOOT_STORE_TYPE BOOT_STORE_TYPE
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
static const WCHAR SystemRoot[]
Definition: reg.c:38
#define RtlImageNtHeader
Definition: compat.h:806
#define MAX_PATH
Definition: compat.h:34
#define FILE_SHARE_READ
Definition: compat.h:136
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
static const WCHAR Signature[]
Definition: parser.c:141
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
@ Success
Definition: eventcreate.c:712
#define BufLen
Definition: fatfs.h:167
BOOLEAN NtPathToDiskPartComponents(IN PCWSTR NtPath, OUT PULONG pDiskNumber, OUT PULONG pPartNumber, OUT PCWSTR *PathComponent OPTIONAL)
Definition: filesup.c:770
NTSTATUS OpenAndMapFile(_In_opt_ HANDLE RootDirectory, _In_ PCWSTR PathNameToFile, _Out_opt_ PHANDLE FileHandle, _Out_opt_ PULONG FileSize, _Out_ PHANDLE SectionHandle, _Out_ PVOID *BaseAddress, _In_ BOOLEAN ReadWriteAccess)
Opens and maps a file in memory.
Definition: filesup.c:886
#define UnMapAndCloseFile(FileHandle, SectionHandle, BaseAddress)
Definition: filesup.h:121
#define DoesDirExist(RootDirectory, DirName)
Definition: filesup.h:80
#define DoesFileExist(RootDirectory, FileName)
Definition: filesup.h:83
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define RTL_FIELD_SIZE(type, field)
Definition: kdb_expr.c:86
PGENERIC_LIST CreateGenericList(VOID)
Definition: genlist.c:20
PGENERIC_LIST_ENTRY GetFirstListEntry(IN PGENERIC_LIST List)
Definition: genlist.c:104
BOOLEAN AppendGenericListEntry(IN OUT PGENERIC_LIST List, IN PVOID Data, IN BOOLEAN Current)
Definition: genlist.c:62
ULONG GetNumberOfListEntries(IN PGENERIC_LIST List)
Definition: genlist.c:140
PVOID GetListEntryData(IN PGENERIC_LIST_ENTRY Entry)
Definition: genlist.c:126
PGENERIC_LIST_ENTRY GetNextListEntry(IN PGENERIC_LIST_ENTRY Entry)
Definition: genlist.c:114
@ Formatted
Definition: partlist.h:37
if(dx< 0)
Definition: linetemp.h:194
POINT cp
Definition: magnifier.c:59
struct S1 s1
struct S2 s2
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define ASSERT(a)
Definition: mode.c:44
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define _Inout_
Definition: ms_sal.h:378
#define _In_
Definition: ms_sal.h:308
unsigned int UINT
Definition: ndis.h:50
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3952
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_LIST_DIRECTORY
Definition: nt_native.h:629
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
#define FILE_TRAVERSE
Definition: nt_native.h:643
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define RTL_NUMBER_OF_FIELD(type, field)
Definition: ntbasedef.h:703
#define UNICODE_NULL
#define STATUS_INVALID_IMAGE_FORMAT
Definition: ntstatus.h:359
NTSTRSAFEAPI RtlStringCchCopyW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:127
NTSTRSAFEVAPI RtlStringCchPrintfW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1110
NTSTRSAFEAPI RtlStringCbCopyNW(_Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc, _In_ size_t cbToCopy)
Definition: ntstrsafe.h:416
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NtGetVersionResource(IN PVOID BaseAddress, OUT PVOID *Resource, OUT PULONG ResourceSize OPTIONAL)
Definition: ntverrsrc.c:26
NTSTATUS NtVerQueryValue(IN const VOID *pBlock, IN PCWSTR lpSubBlock, OUT PVOID *lplpBuffer, OUT PUINT puLen)
Definition: ntverrsrc.c:174
struct _ENUM_INSTALLS_DATA ENUM_INSTALLS_DATA
static PNTOS_INSTALLATION FindExistingNTOSInstall(IN PGENERIC_LIST List, IN PCWSTR SystemRootArcPath OPTIONAL, IN PUNICODE_STRING SystemRootNtPath OPTIONAL)
Definition: osdetect.c:565
PGENERIC_LIST CreateNTOSInstallationsList(_In_ PPARTLIST PartList)
Create a list of available NT OS installations on the computer, by searching for recognized ones on e...
Definition: osdetect.c:763
static const PCWSTR KnownVendors[]
Definition: osdetect.c:29
static VOID FindNTOSInstallations(_Inout_ PGENERIC_LIST List, _In_ PPARTLIST PartList, _In_ PVOLENTRY Volume)
Definition: osdetect.c:679
static PNTOS_INSTALLATION AddNTOSInstallation(_In_ PGENERIC_LIST List, _In_ PCWSTR InstallationName, _In_ USHORT Machine, _In_ PCWSTR VendorName, _In_ PCWSTR SystemRootArcPath, _In_ PUNICODE_STRING SystemRootNtPath, _In_ PCWSTR PathComponent, _In_ ULONG DiskNumber, _In_ ULONG PartitionNumber)
Definition: osdetect.c:609
struct _ENUM_INSTALLS_DATA * PENUM_INSTALLS_DATA
static BOOLEAN IsValidNTOSInstallationByHandle(IN HANDLE SystemRootDirectory, OUT PUSHORT Machine OPTIONAL, OUT PUNICODE_STRING VendorName OPTIONAL)
Definition: osdetect.c:346
static BOOLEAN IsValidNTOSInstallation(IN PUNICODE_STRING SystemRootPath, OUT PUSHORT Machine OPTIONAL, OUT PUNICODE_STRING VendorName OPTIONAL)
Definition: osdetect.c:500
static BOOLEAN CheckForValidPEAndVendor(IN HANDLE RootDirectory OPTIONAL, IN PCWSTR PathNameToFile, OUT PUSHORT Machine, OUT PUNICODE_STRING VendorName)
Definition: osdetect.c:243
static NTSTATUS NTAPI EnumerateInstallations(IN BOOT_STORE_TYPE Type, IN PBOOT_STORE_ENTRY BootEntry, IN PVOID Parameter OPTIONAL)
Definition: osdetect.c:68
PCWSTR FindSubStrI(PCWSTR str, PCWSTR strSearch)
Definition: osdetect.c:217
#define VENDOR_MICROSOFT
Definition: osdetect.h:13
struct _NTOS_INSTALLATION * PNTOS_INSTALLATION
#define VENDOR_REACTOS
Definition: osdetect.h:12
#define LOWORD(l)
Definition: pedump.c:82
unsigned short USHORT
Definition: pedump.c:61
const WCHAR * str
PPARTENTRY SelectPartition(_In_ PPARTLIST List, _In_ ULONG DiskNumber, _In_ ULONG PartitionNumber)
Definition: partlist.c:2266
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define DPRINT
Definition: sndvol32.h:73
#define _countof(array)
Definition: sndvol32.h:70
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
base of all file and directory entries
Definition: entries.h:83
Definition: bldrsup.h:67
_Inout_ PGENERIC_LIST List
Definition: osdetect.c:61
_In_ PPARTLIST PartList
Definition: osdetect.c:62
Definition: genlist.h:11
IMAGE_FILE_HEADER FileHeader
Definition: ntddk_ex.h:183
Definition: typedefs.h:120
ULONG PartitionNumber
Definition: osdetect.h:24
WCHAR InstallationName[MAX_PATH]
Definition: osdetect.h:26
UNICODE_STRING SystemNtPath
Definition: osdetect.h:21
WCHAR VendorName[MAX_PATH]
Definition: osdetect.h:27
UNICODE_STRING SystemArcPath
Definition: osdetect.h:20
PCWSTR PathComponent
Definition: osdetect.h:22
UCHAR PartitionType
Definition: partlist.h:73
PVOLENTRY Volume
Definition: partlist.h:95
struct _DISKENTRY * DiskEntry
Definition: partlist.h:66
BOOLEAN LogicalPartition
Definition: partlist.h:79
ULONG PartitionNumber
Definition: partlist.h:75
ULONG PartitionIndex
Definition: partlist.h:76
#define towupper(c)
Definition: wctype.h:99
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint16_t * PUSHORT
Definition: typedefs.h:56
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
#define OUT
Definition: typedefs.h:40
_In_ PWDFDEVICE_INIT _In_ PWDF_REMOVE_LOCK_OPTIONS Options
Definition: wdfdevice.h:3534
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
_Must_inspect_result_ _In_ WDFDEVICE _In_ LPCGUID _Out_ PINTERFACE _In_ USHORT _In_ USHORT Version
Definition: wdffdo.h:469
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
_In_ ULONG _In_opt_ PVOID pvData
Definition: winddi.h:3749
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2061
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175