ReactOS 0.4.16-dev-598-gc07fba4
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
217PCWSTR
218NTAPI
221 _In_ PCWSTR strSearch)
222{
223 PCWSTR cp = str;
224 PCWSTR s1, s2;
225
226 if (!*strSearch)
227 return str;
228
229 while (*cp)
230 {
231 s1 = cp;
232 s2 = strSearch;
233
234 while (*s1 && *s2 && (towupper(*s1) == towupper(*s2)))
235 ++s1, ++s2;
236
237 if (!*s2)
238 return cp;
239
240 ++cp;
241 }
242
243 return NULL;
244}
245
246static BOOLEAN
249 IN PCWSTR PathNameToFile,
250 OUT PUSHORT Machine,
252{
255 HANDLE FileHandle, SectionHandle;
256 // SIZE_T ViewSize;
257 PVOID ViewBase;
258 PIMAGE_NT_HEADERS NtHeader;
259 PVOID VersionBuffer = NULL; // Read-only
260 PVOID pvData = NULL;
261 UINT BufLen = 0;
262
263 if (VendorName->MaximumLength < sizeof(UNICODE_NULL))
264 return FALSE;
265
266 *VendorName->Buffer = UNICODE_NULL;
267 VendorName->Length = 0;
268
269 Status = OpenAndMapFile(RootDirectory, PathNameToFile,
271 &SectionHandle, &ViewBase, FALSE);
272 if (!NT_SUCCESS(Status))
273 {
274 DPRINT1("Failed to open and map file '%S', Status 0x%08lx\n", PathNameToFile, Status);
275 return FALSE; // Status;
276 }
277
278 /* Make sure it's a valid NT PE file */
279 NtHeader = RtlImageNtHeader(ViewBase);
280 if (!NtHeader)
281 {
282 DPRINT1("File '%S' does not seem to be a valid NT PE file, bail out\n", PathNameToFile);
284 goto UnmapCloseFile;
285 }
286
287 /* Retrieve the target architecture of this PE module */
288 *Machine = NtHeader->FileHeader.Machine;
289
290 /*
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.
293 */
294 Status = NtGetVersionResource((PVOID)((ULONG_PTR)ViewBase | 1), &VersionBuffer, NULL);
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT1("Failed to get version resource for file '%S', Status 0x%08lx\n", PathNameToFile, Status);
298 goto UnmapCloseFile;
299 }
300
301 Status = NtVerQueryValue(VersionBuffer, L"\\VarFileInfo\\Translation", &pvData, &BufLen);
302 if (NT_SUCCESS(Status))
303 {
304 USHORT wCodePage = 0, wLangID = 0;
306
307 wCodePage = LOWORD(*(ULONG*)pvData);
308 wLangID = HIWORD(*(ULONG*)pvData);
309
311 L"StringFileInfo\\%04X%04X\\CompanyName",
312 wCodePage, wLangID);
313
314 Status = NtVerQueryValue(VersionBuffer, FileInfo, &pvData, &BufLen);
315
316 /* Fixup the Status in case pvData is NULL */
317 if (NT_SUCCESS(Status) && !pvData)
319
320 if (NT_SUCCESS(Status) /*&& pvData*/)
321 {
322 /* BufLen includes the NULL terminator count */
323 DPRINT("Found version vendor: \"%S\" for file '%S'\n", pvData, PathNameToFile);
324
325 RtlStringCbCopyNW(VendorName->Buffer, VendorName->MaximumLength,
326 pvData, BufLen * sizeof(WCHAR));
327 VendorName->Length = (USHORT)wcslen(VendorName->Buffer) * sizeof(WCHAR);
328
329 Success = TRUE;
330 }
331 }
332
333 if (!NT_SUCCESS(Status))
334 DPRINT("No version vendor found for file '%S'\n", PathNameToFile);
335
336UnmapCloseFile:
337 /* Finally, unmap and close the file */
338 UnMapAndCloseFile(FileHandle, SectionHandle, ViewBase);
339
340 return Success;
341}
342
343//
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).
348//
349static BOOLEAN
351 IN HANDLE SystemRootDirectory,
352 OUT PUSHORT Machine OPTIONAL,
354{
356 PCWSTR PathName;
357 USHORT i;
358 USHORT LocalMachine;
359 UNICODE_STRING LocalVendorName;
360 WCHAR VendorNameBuffer[MAX_PATH];
361
362 /* Check for VendorName validity */
363 if (VendorName->MaximumLength < sizeof(UNICODE_NULL))
364 {
365 /* Don't use it, invalidate the pointer */
367 }
368 else
369 {
370 /* Zero it out */
371 *VendorName->Buffer = UNICODE_NULL;
372 VendorName->Length = 0;
373 }
374
375 /* Check for the existence of \SystemRoot\System32 */
376 PathName = L"System32\\";
377 if (!DoesDirExist(SystemRootDirectory, PathName))
378 {
379 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
380 return FALSE;
381 }
382
383 /* Check for the existence of \SystemRoot\System32\drivers */
384 PathName = L"System32\\drivers\\";
385 if (!DoesDirExist(SystemRootDirectory, PathName))
386 {
387 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
388 return FALSE;
389 }
390
391 /* Check for the existence of \SystemRoot\System32\config */
392 PathName = L"System32\\config\\";
393 if (!DoesDirExist(SystemRootDirectory, PathName))
394 {
395 // DPRINT1("Failed to open directory '%S', Status 0x%08lx\n", PathName, Status);
396 return FALSE;
397 }
398
399#if 0
400 /*
401 * Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
402 * (but we don't check here whether they are actually valid).
403 */
404 PathName = L"System32\\config\\SYSTEM";
405 if (!DoesFileExist(SystemRootDirectory, PathName))
406 {
407 // DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
408 return FALSE;
409 }
410 PathName = L"System32\\config\\SOFTWARE";
411 if (!DoesFileExist(SystemRootDirectory, PathName))
412 {
413 // DPRINT1("Failed to open file '%S', Status 0x%08lx\n", PathName, Status);
414 return FALSE;
415 }
416#endif
417
418 RtlInitEmptyUnicodeString(&LocalVendorName, VendorNameBuffer, sizeof(VendorNameBuffer));
419
420 /* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and retrieves its vendor name */
421 PathName = L"System32\\ntoskrnl.exe";
422 Success = CheckForValidPEAndVendor(SystemRootDirectory, PathName, &LocalMachine, &LocalVendorName);
423 if (!Success)
424 DPRINT1("Kernel executable '%S' is either not a PE file, or does not have any vendor?\n", PathName);
425
426 /*
427 * The kernel gives the OS its flavour. If we failed due to the absence of
428 * ntoskrnl.exe this might be due to the fact this particular installation
429 * uses a custom kernel that has a different name, overridden in the boot
430 * parameters. We then rely on the existence of ntdll.dll, which cannot be
431 * renamed on a valid NT system.
432 */
433 if (Success)
434 {
435 for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
436 {
437 Success = !!FindSubStrI(LocalVendorName.Buffer, KnownVendors[i]);
438 if (Success)
439 {
440 /* We have found a correct vendor combination */
441 DPRINT("IsValidNTOSInstallation: We've got an NTOS installation from %S !\n", KnownVendors[i]);
442 break;
443 }
444 }
445
446 /* Return the target architecture */
447 if (Machine)
448 {
449 /* Copy the value and invalidate the pointer */
450 *Machine = LocalMachine;
451 Machine = NULL;
452 }
453
454 /* Return the vendor name */
455 if (VendorName)
456 {
457 /* Copy the string and invalidate the pointer */
458 RtlCopyUnicodeString(VendorName, &LocalVendorName);
460 }
461 }
462
463 /* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
464
465 /* Check for the existence of \SystemRoot\System32\ntdll.dll and retrieves its vendor name */
466 PathName = L"System32\\ntdll.dll";
467 Success = CheckForValidPEAndVendor(SystemRootDirectory, PathName, &LocalMachine, &LocalVendorName);
468 if (!Success)
469 DPRINT1("User-mode DLL '%S' is either not a PE file, or does not have any vendor?\n", PathName);
470
471 if (Success)
472 {
473 for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
474 {
475 if (!!FindSubStrI(LocalVendorName.Buffer, KnownVendors[i]))
476 {
477 /* We have found a correct vendor combination */
478 DPRINT("IsValidNTOSInstallation: The user-mode DLL '%S' is from %S\n", PathName, KnownVendors[i]);
479 break;
480 }
481 }
482
483 /* Return the target architecture if not already obtained */
484 if (Machine)
485 {
486 /* Copy the value and invalidate the pointer */
487 *Machine = LocalMachine;
488 Machine = NULL;
489 }
490
491 /* Return the vendor name if not already obtained */
492 if (VendorName)
493 {
494 /* Copy the string and invalidate the pointer */
495 RtlCopyUnicodeString(VendorName, &LocalVendorName);
497 }
498 }
499
500 return Success;
501}
502
503static BOOLEAN
505 IN PUNICODE_STRING SystemRootPath,
506 OUT PUSHORT Machine,
508{
512 HANDLE SystemRootDirectory;
514
515 /* Open SystemRootPath */
517 SystemRootPath,
519 NULL,
520 NULL);
521 Status = NtOpenFile(&SystemRootDirectory,
527 if (!NT_SUCCESS(Status))
528 {
529 DPRINT1("Failed to open SystemRoot '%wZ', Status 0x%08lx\n", SystemRootPath, Status);
530 return FALSE;
531 }
532
533 Success = IsValidNTOSInstallationByHandle(SystemRootDirectory,
534 Machine, VendorName);
535
536 /* Done! */
537 NtClose(SystemRootDirectory);
538 return Success;
539}
540
541#ifndef NDEBUG
542static VOID
543DumpNTOSInstalls(
545{
547 PNTOS_INSTALLATION NtOsInstall;
548 ULONG NtOsInstallsCount = GetNumberOfListEntries(List);
549
550 DPRINT("There %s %d installation%s detected:\n",
551 NtOsInstallsCount >= 2 ? "are" : "is",
552 NtOsInstallsCount,
553 NtOsInstallsCount >= 2 ? "s" : "");
554
556 {
558
559 DPRINT(" On disk #%d, partition #%d: Installation \"%S\" in SystemRoot '%wZ'\n",
560 NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber,
561 NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
562 }
563
564 DPRINT("Done.\n");
565}
566#endif
567
571 IN PCWSTR SystemRootArcPath OPTIONAL,
572 IN PUNICODE_STRING SystemRootNtPath OPTIONAL // or PCWSTR ?
573 )
574{
576 PNTOS_INSTALLATION NtOsInstall;
577 UNICODE_STRING SystemArcPath;
578
579 /*
580 * We search either via ARC path or NT path.
581 * If both pointers are NULL then we fail straight away.
582 */
583 if (!SystemRootArcPath && !SystemRootNtPath)
584 return NULL;
585
586 RtlInitUnicodeString(&SystemArcPath, SystemRootArcPath);
587
589 {
591
592 /*
593 * Note that if both ARC paths are equal, then the corresponding
594 * NT paths must be the same. However, two ARC paths may be different
595 * but resolve into the same NT path.
596 */
597 if ( (SystemRootArcPath &&
599 &SystemArcPath, TRUE)) ||
600 (SystemRootNtPath &&
602 SystemRootNtPath, TRUE)) )
603 {
604 /* Found it! */
605 return NtOsInstall;
606 }
607 }
608
609 return NULL;
610}
611
615 _In_ PCWSTR InstallationName,
616 _In_ USHORT Machine,
618 _In_ PCWSTR SystemRootArcPath,
619 _In_ PUNICODE_STRING SystemRootNtPath, // or PCWSTR ?
620 _In_ PCWSTR PathComponent, // Pointer inside SystemRootNtPath buffer
621 _In_ ULONG DiskNumber,
623{
624 PNTOS_INSTALLATION NtOsInstall;
625 SIZE_T ArcPathLength, NtPathLength;
626
627 /* Is there already any installation with these settings? */
628 NtOsInstall = FindExistingNTOSInstall(List, SystemRootArcPath, SystemRootNtPath);
629 if (NtOsInstall)
630 {
631 DPRINT1("An NTOS installation with name \"%S\" from vendor \"%S\" already exists on disk #%d, partition #%d, in SystemRoot '%wZ'\n",
632 NtOsInstall->InstallationName, NtOsInstall->VendorName,
633 NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber, &NtOsInstall->SystemNtPath);
634 //
635 // NOTE: We may use its "IsDefault" attribute, and only keep the entries that have IsDefault == TRUE...
636 // Setting IsDefault to TRUE would imply searching for the "Default" entry in the loader configuration file.
637 //
638 return NtOsInstall;
639 }
640
641 ArcPathLength = (wcslen(SystemRootArcPath) + 1) * sizeof(WCHAR);
642 // NtPathLength = ROUND_UP(SystemRootNtPath->Length + sizeof(UNICODE_NULL), sizeof(WCHAR));
643 NtPathLength = SystemRootNtPath->Length + sizeof(UNICODE_NULL);
644
645 /* None was found, so add a new one */
647 sizeof(*NtOsInstall) +
648 ArcPathLength + NtPathLength);
649 if (!NtOsInstall)
650 return NULL;
651
652 NtOsInstall->DiskNumber = DiskNumber;
653 NtOsInstall->PartitionNumber = PartitionNumber;
654 NtOsInstall->Machine = Machine;
655
656 RtlInitEmptyUnicodeString(&NtOsInstall->SystemArcPath,
657 (PWCHAR)(NtOsInstall + 1),
658 ArcPathLength);
659 RtlCopyMemory(NtOsInstall->SystemArcPath.Buffer, SystemRootArcPath, ArcPathLength);
660 NtOsInstall->SystemArcPath.Length = ArcPathLength - sizeof(UNICODE_NULL);
661
662 RtlInitEmptyUnicodeString(&NtOsInstall->SystemNtPath,
663 (PWCHAR)((ULONG_PTR)(NtOsInstall + 1) + ArcPathLength),
664 NtPathLength);
665 RtlCopyUnicodeString(&NtOsInstall->SystemNtPath, SystemRootNtPath);
666 NtOsInstall->PathComponent = NtOsInstall->SystemNtPath.Buffer +
667 (PathComponent - SystemRootNtPath->Buffer);
668
670 ARRAYSIZE(NtOsInstall->InstallationName),
671 InstallationName);
672
673 RtlStringCchCopyW(NtOsInstall->VendorName,
674 ARRAYSIZE(NtOsInstall->VendorName),
675 VendorName);
676
677 AppendGenericListEntry(List, NtOsInstall, FALSE);
678
679 return NtOsInstall;
680}
681
682static VOID
685 _In_ PPARTLIST PartList,
687{
689 HANDLE VolumeRootDirHandle;
692 UNICODE_STRING VolumeRootPath;
694 PVOID BootStoreHandle;
698
699 /* Set VolumeRootPath */
700 RtlStringCchPrintfW(PathBuffer, _countof(PathBuffer),
701 L"%s\\", Volume->Info.DeviceName);
702 RtlInitUnicodeString(&VolumeRootPath, PathBuffer);
703 DPRINT("FindNTOSInstallations(%wZ)\n", &VolumeRootPath);
704
705 /* Open the volume */
707 &VolumeRootPath,
709 NULL,
710 NULL);
711 Status = NtOpenFile(&VolumeRootDirHandle,
717 if (!NT_SUCCESS(Status))
718 {
719 DPRINT1("Failed to open volume '%wZ', Status 0x%08lx\n", &VolumeRootPath, Status);
720 return;
721 }
722
723 Data.List = List;
724 Data.PartList = PartList;
725
726 /* Try to see whether we recognize some NT boot loaders */
727 for (Type = FreeLdr; Type < BldrTypeMax; ++Type)
728 {
729 Status = FindBootStore(VolumeRootDirHandle, Type, &Version);
730 if (!NT_SUCCESS(Status))
731 {
732 /* The loader does not exist, continue with another one */
733 DPRINT("Loader type '%d' does not exist, or an error happened (Status 0x%08lx), continue with another one...\n",
734 Type, Status);
735 continue;
736 }
737
738 /* The loader exists, try to enumerate its boot entries */
739 DPRINT("Analyze the OS installations for loader type '%d' in Volume %wZ (Disk #%d, Partition #%d)\n",
740 Type, &VolumeRootPath,
741 Volume->PartEntry->DiskEntry->DiskNumber,
742 Volume->PartEntry->PartitionNumber);
743
744 Status = OpenBootStoreByHandle(&BootStoreHandle, VolumeRootDirHandle, Type,
746 if (!NT_SUCCESS(Status))
747 {
748 DPRINT1("Could not open the NTOS boot store of type '%d' (Status 0x%08lx), continue with another one...\n",
749 Type, Status);
750 continue;
751 }
753 CloseBootStore(BootStoreHandle);
754 }
755
756 /* Close the volume */
757 NtClose(VolumeRootDirHandle);
758}
759
765// EnumerateNTOSInstallations
767NTAPI
769 _In_ PPARTLIST PartList)
770{
775
777 if (!List)
778 return NULL;
779
780 /* Loop each available volume */
781 for (Entry = PartList->VolumesList.Flink;
782 Entry != &PartList->VolumesList;
783 Entry = Entry->Flink)
784 {
785 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
786 /* Valid OS installations can be found only on basic volumes */
787 if (!Volume->PartEntry) // TODO: In the future: (!Volume->IsSimpleVolume)
788 continue;
789
790 CheckVolume = (!Volume->New && (Volume->FormatState == Formatted));
791
792#ifndef NDEBUG
793 {
794 PPARTENTRY PartEntry = Volume->PartEntry;
795 ASSERT(PartEntry->Volume == Volume);
796 DPRINT("Volume %S (%c%c) on Disk #%d, Partition #%d (%s), "
797 "index %d - Type 0x%02x, IsVolNew = %s, FormatState = %lu -- Should I check it? %s\n",
798 Volume->Info.DeviceName,
799 !Volume->Info.DriveLetter ? '-' : (CHAR)Volume->Info.DriveLetter,
800 !Volume->Info.DriveLetter ? '-' : ':',
801 PartEntry->DiskEntry->DiskNumber,
802 PartEntry->PartitionNumber,
803 PartEntry->LogicalPartition ? "Logical" : "Primary",
804 PartEntry->PartitionIndex,
805 PartEntry->PartitionType,
806 Volume->New ? "Yes" : "No",
807 Volume->FormatState,
808 CheckVolume ? "YES!" : "NO!");
809 }
810#endif
811
812 if (CheckVolume)
814 }
815
816#ifndef NDEBUG
817 /**** Debugging: List all the collected installations ****/
818 DumpNTOSInstalls(List);
819#endif
820
821 return List;
822}
823
824/* 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:763
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:879
#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
ULONG NTAPI GetNumberOfListEntries(IN PGENERIC_LIST List)
Definition: genlist.c:149
PGENERIC_LIST NTAPI CreateGenericList(VOID)
Definition: genlist.c:21
BOOLEAN NTAPI AppendGenericListEntry(IN OUT PGENERIC_LIST List, IN PVOID Data, IN BOOLEAN Current)
Definition: genlist.c:65
PGENERIC_LIST_ENTRY NTAPI GetFirstListEntry(IN PGENERIC_LIST List)
Definition: genlist.c:110
PGENERIC_LIST_ENTRY NTAPI GetNextListEntry(IN PGENERIC_LIST_ENTRY Entry)
Definition: genlist.c:121
PVOID NTAPI GetListEntryData(IN PGENERIC_LIST_ENTRY Entry)
Definition: genlist.c:134
@ 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
unsigned int UINT
Definition: ndis.h:50
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
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:3953
#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:711
#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:569
static const PCWSTR KnownVendors[]
Definition: osdetect.c:29
static VOID FindNTOSInstallations(_Inout_ PGENERIC_LIST List, _In_ PPARTLIST PartList, _In_ PVOLENTRY Volume)
Definition: osdetect.c:683
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:613
struct _ENUM_INSTALLS_DATA * PENUM_INSTALLS_DATA
PGENERIC_LIST NTAPI 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:768
static BOOLEAN IsValidNTOSInstallationByHandle(IN HANDLE SystemRootDirectory, OUT PUSHORT Machine OPTIONAL, OUT PUNICODE_STRING VendorName OPTIONAL)
Definition: osdetect.c:350
static BOOLEAN IsValidNTOSInstallation(IN PUNICODE_STRING SystemRootPath, OUT PUSHORT Machine OPTIONAL, OUT PUNICODE_STRING VendorName OPTIONAL)
Definition: osdetect.c:504
PCWSTR NTAPI FindSubStrI(_In_ PCWSTR str, _In_ PCWSTR strSearch)
Finds the first occurrence of a sub-string 'strSearch' inside 'str', using case-insensitive compariso...
Definition: osdetect.c:219
static BOOLEAN CheckForValidPEAndVendor(IN HANDLE RootDirectory OPTIONAL, IN PCWSTR PathNameToFile, OUT PUSHORT Machine, OUT PUNICODE_STRING VendorName)
Definition: osdetect.c:247
static NTSTATUS NTAPI EnumerateInstallations(IN BOOT_STORE_TYPE Type, IN PBOOT_STORE_ENTRY BootEntry, IN PVOID Parameter OPTIONAL)
Definition: osdetect.c:68
#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:2268
#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