ReactOS 0.4.15-dev-7961-gdcf9eb0
osdetect.c
Go to the documentation of this file.
1/*
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
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 IN PPARTENTRY PartEntry OPTIONAL);
59
60typedef struct _ENUM_INSTALLS_DATA
61{
64 // IN PPARTENTRY PartEntry;
66
67// PENUM_BOOT_ENTRIES_ROUTINE
68static NTSTATUS
72 IN PBOOT_STORE_ENTRY BootEntry,
74{
76 PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
77 PNTOS_INSTALLATION NtOsInstall;
78
79 ULONG DiskNumber = 0, PartitionNumber = 0;
81 PDISKENTRY DiskEntry = NULL;
82 PPARTENTRY PartEntry = NULL;
83
84 UNICODE_STRING SystemRootPath;
86
87 USHORT Machine;
89 WCHAR VendorNameBuffer[MAX_PATH];
90
91
92 /* We have a boot entry */
93
94 /* Check for supported boot type "Windows2003" */
95 if (BootEntry->OsOptionsLength < sizeof(NTOS_OPTIONS) ||
96 RtlCompareMemory(&BootEntry->OsOptions /* Signature */,
100 {
101 /* This is not a ReactOS entry */
102 // DPRINT(" An installation '%S' of unsupported type '%S'\n",
103 // BootEntry->FriendlyName, BootEntry->Version ? BootEntry->Version : L"n/a");
104 DPRINT(" An installation '%S' of unsupported type %lu\n",
105 BootEntry->FriendlyName, BootEntry->OsOptionsLength);
106 /* Continue the enumeration */
107 return STATUS_SUCCESS;
108 }
109
110 /* BootType is Windows2003, now check OsLoadPath */
111 if (!Options->OsLoadPath || !*Options->OsLoadPath)
112 {
113 /* Certainly not a ReactOS installation */
114 DPRINT1(" A Win2k3 install '%S' without an ARC path?!\n", BootEntry->FriendlyName);
115 /* Continue the enumeration */
116 return STATUS_SUCCESS;
117 }
118
119 DPRINT(" Found a candidate Win2k3 install '%S' with ARC path '%S'\n",
120 BootEntry->FriendlyName, Options->OsLoadPath);
121 // DPRINT(" Found a Win2k3 install '%S' with ARC path '%S'\n",
122 // BootEntry->FriendlyName, Options->OsLoadPath);
123
124 // TODO: Normalize the ARC path.
125
126 /*
127 * Check whether we already have an installation with this ARC path.
128 * If this is the case, stop there.
129 */
130 NtOsInstall = FindExistingNTOSInstall(Data->List, Options->OsLoadPath, NULL);
131 if (NtOsInstall)
132 {
133 DPRINT(" An NTOS installation with name \"%S\" from vendor \"%S\" already exists in SystemRoot '%wZ'\n",
134 NtOsInstall->InstallationName, NtOsInstall->VendorName, &NtOsInstall->SystemArcPath);
135 /* Continue the enumeration */
136 return STATUS_SUCCESS;
137 }
138
139 /*
140 * Convert the ARC path into an NT path, from which we will deduce
141 * the real disk drive & partition on which the candidate installation
142 * resides, as well verifying whether it is indeed an NTOS installation.
143 */
144 RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
145 if (!ArcPathToNtPath(&SystemRootPath, Options->OsLoadPath, Data->PartList))
146 {
147 DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", Options->OsLoadPath);
148 /* Continue the enumeration */
149 return STATUS_SUCCESS;
150 }
151
152 DPRINT("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n",
153 Options->OsLoadPath, &SystemRootPath);
154
155 /*
156 * Check whether we already have an installation with this NT path.
157 * If this is the case, stop there.
158 */
159 NtOsInstall = FindExistingNTOSInstall(Data->List, NULL /*Options->OsLoadPath*/, &SystemRootPath);
160 if (NtOsInstall)
161 {
162 DPRINT1(" An NTOS installation with name \"%S\" from vendor \"%S\" already exists in SystemRoot '%wZ'\n",
163 NtOsInstall->InstallationName, NtOsInstall->VendorName, &NtOsInstall->SystemNtPath);
164 /* Continue the enumeration */
165 return STATUS_SUCCESS;
166 }
167
168 DPRINT("EnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
169
170 /* Check if this is a valid NTOS installation; stop there if it isn't one */
171 RtlInitEmptyUnicodeString(&VendorName, VendorNameBuffer, sizeof(VendorNameBuffer));
172 if (!IsValidNTOSInstallation(&SystemRootPath, &Machine, &VendorName))
173 {
174 /* Continue the enumeration */
175 return STATUS_SUCCESS;
176 }
177
178 DPRINT("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n",
179 Options->OsLoadPath, &SystemRootPath);
180
181 /* From the NT path, compute the disk, partition and path components */
182 if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
183 {
184 DPRINT("SystemRootPath = '%wZ' points to disk #%d, partition #%d, path '%S'\n",
185 &SystemRootPath, DiskNumber, PartitionNumber, PathComponent);
186
187 /* Retrieve the corresponding disk and partition */
188 if (!GetDiskOrPartition(Data->PartList, DiskNumber, PartitionNumber, &DiskEntry, &PartEntry))
189 {
190 DPRINT1("GetDiskOrPartition(disk #%d, partition #%d) failed\n",
191 DiskNumber, PartitionNumber);
192 }
193 }
194 else
195 {
196 DPRINT1("NtPathToDiskPartComponents(%wZ) failed\n", &SystemRootPath);
197 }
198
199 /* Add the discovered NTOS installation into the list */
201 BootEntry->FriendlyName,
202 Machine,
203 VendorName.Buffer, // FIXME: What if it's not NULL-terminated?
204 Options->OsLoadPath,
205 &SystemRootPath, PathComponent,
206 DiskNumber, PartitionNumber, PartEntry);
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,
266 &FileHandle, &SectionHandle, &ViewBase,
267 NULL, 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 IN PPARTENTRY PartEntry OPTIONAL)
620{
621 PNTOS_INSTALLATION NtOsInstall;
622 SIZE_T ArcPathLength, NtPathLength;
623
624 /* Is there already any installation with these settings? */
625 NtOsInstall = FindExistingNTOSInstall(List, SystemRootArcPath, SystemRootNtPath);
626 if (NtOsInstall)
627 {
628 DPRINT1("An NTOS installation with name \"%S\" from vendor \"%S\" already exists on disk #%d, partition #%d, in SystemRoot '%wZ'\n",
629 NtOsInstall->InstallationName, NtOsInstall->VendorName,
630 NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber, &NtOsInstall->SystemNtPath);
631 //
632 // NOTE: We may use its "IsDefault" attribute, and only keep the entries that have IsDefault == TRUE...
633 // Setting IsDefault to TRUE would imply searching for the "Default" entry in the loader configuration file.
634 //
635 return NtOsInstall;
636 }
637
638 ArcPathLength = (wcslen(SystemRootArcPath) + 1) * sizeof(WCHAR);
639 // NtPathLength = ROUND_UP(SystemRootNtPath->Length + sizeof(UNICODE_NULL), sizeof(WCHAR));
640 NtPathLength = SystemRootNtPath->Length + sizeof(UNICODE_NULL);
641
642 /* None was found, so add a new one */
644 sizeof(*NtOsInstall) +
645 ArcPathLength + NtPathLength);
646 if (!NtOsInstall)
647 return NULL;
648
649 NtOsInstall->DiskNumber = DiskNumber;
650 NtOsInstall->PartitionNumber = PartitionNumber;
651 NtOsInstall->PartEntry = PartEntry;
652
653 NtOsInstall->Machine = Machine;
654
655 RtlInitEmptyUnicodeString(&NtOsInstall->SystemArcPath,
656 (PWCHAR)(NtOsInstall + 1),
657 ArcPathLength);
658 RtlCopyMemory(NtOsInstall->SystemArcPath.Buffer, SystemRootArcPath, ArcPathLength);
659 NtOsInstall->SystemArcPath.Length = ArcPathLength - sizeof(UNICODE_NULL);
660
661 RtlInitEmptyUnicodeString(&NtOsInstall->SystemNtPath,
662 (PWCHAR)((ULONG_PTR)(NtOsInstall + 1) + ArcPathLength),
663 NtPathLength);
664 RtlCopyUnicodeString(&NtOsInstall->SystemNtPath, SystemRootNtPath);
665 NtOsInstall->PathComponent = NtOsInstall->SystemNtPath.Buffer +
666 (PathComponent - SystemRootNtPath->Buffer);
667
669 ARRAYSIZE(NtOsInstall->InstallationName),
670 InstallationName);
671
672 RtlStringCchCopyW(NtOsInstall->VendorName,
673 ARRAYSIZE(NtOsInstall->VendorName),
674 VendorName);
675
676 AppendGenericListEntry(List, NtOsInstall, FALSE);
677
678 return NtOsInstall;
679}
680
681static VOID
684 IN PPARTLIST PartList,
685 IN PPARTENTRY PartEntry)
686{
688 ULONG DiskNumber = PartEntry->DiskEntry->DiskNumber;
689 ULONG PartitionNumber = PartEntry->PartitionNumber;
690 HANDLE PartitionDirectoryHandle;
693 UNICODE_STRING PartitionRootPath;
695 PVOID BootStoreHandle;
698 WCHAR PathBuffer[MAX_PATH];
699
700 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
701
702 /* Set PartitionRootPath */
703 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
704 L"\\Device\\Harddisk%lu\\Partition%lu\\",
705 DiskNumber, PartitionNumber);
706 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
707 DPRINT("FindNTOSInstallations: PartitionRootPath: '%wZ'\n", &PartitionRootPath);
708
709 /* Open the partition */
711 &PartitionRootPath,
713 NULL,
714 NULL);
715 Status = NtOpenFile(&PartitionDirectoryHandle,
721 if (!NT_SUCCESS(Status))
722 {
723 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", &PartitionRootPath, Status);
724 return;
725 }
726
727 Data.List = List;
728 Data.PartList = PartList;
729
730 /* Try to see whether we recognize some NT boot loaders */
731 for (Type = FreeLdr; Type < BldrTypeMax; ++Type)
732 {
733 Status = FindBootStore(PartitionDirectoryHandle, Type, &Version);
734 if (!NT_SUCCESS(Status))
735 {
736 /* The loader does not exist, continue with another one */
737 DPRINT("Loader type '%d' does not exist, or an error happened (Status 0x%08lx), continue with another one...\n",
738 Type, Status);
739 continue;
740 }
741
742 /* The loader exists, try to enumerate its boot entries */
743 DPRINT("Analyze the OS installations for loader type '%d' in disk #%d, partition #%d\n",
744 Type, DiskNumber, PartitionNumber);
745
746 Status = OpenBootStoreByHandle(&BootStoreHandle, PartitionDirectoryHandle, Type, FALSE);
747 if (!NT_SUCCESS(Status))
748 {
749 DPRINT1("Could not open the NTOS boot store of type '%d' (Status 0x%08lx), continue with another one...\n",
750 Type, Status);
751 continue;
752 }
754 CloseBootStore(BootStoreHandle);
755 }
756
757 /* Close the partition */
758 NtClose(PartitionDirectoryHandle);
759}
760
761// static
764 IN PPARTENTRY PartEntry)
765{
766 if (!PartEntry)
767 return FALSE;
768
769 return PartEntry->IsPartitioned &&
770 !IsContainerPartition(PartEntry->PartitionType) /* alternatively: PartEntry->PartitionNumber != 0 */ &&
771 !PartEntry->New &&
772 (PartEntry->FormatState == Preformatted /* || PartEntry->FormatState == Formatted */);
773}
774
775// EnumerateNTOSInstallations
778 IN PPARTLIST PartList)
779{
781 PLIST_ENTRY Entry, Entry2;
782 PDISKENTRY DiskEntry;
783 PPARTENTRY PartEntry;
784
786 if (List == NULL)
787 return NULL;
788
789 /* Loop each available disk ... */
790 Entry = PartList->DiskListHead.Flink;
791 while (Entry != &PartList->DiskListHead)
792 {
793 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
794 Entry = Entry->Flink;
795
796 DPRINT("Disk #%d\n", DiskEntry->DiskNumber);
797
798 /* ... and for each disk, loop each available partition */
799
800 /* First, the primary partitions */
801 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
802 while (Entry2 != &DiskEntry->PrimaryPartListHead)
803 {
804 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
805 Entry2 = Entry2->Flink;
806
807 ASSERT(PartEntry->DiskEntry == DiskEntry);
808
809 DPRINT(" Primary Partition #%d, index %d - Type 0x%02x, IsLogical = %s, IsPartitioned = %s, IsNew = %s, FormatState = %lu -- Should I check it? %s\n",
810 PartEntry->PartitionNumber, PartEntry->PartitionIndex,
811 PartEntry->PartitionType, PartEntry->LogicalPartition ? "TRUE" : "FALSE",
812 PartEntry->IsPartitioned ? "TRUE" : "FALSE",
813 PartEntry->New ? "Yes" : "No",
814 PartEntry->FormatState,
815 ShouldICheckThisPartition(PartEntry) ? "YES!" : "NO!");
816
817 if (ShouldICheckThisPartition(PartEntry))
818 FindNTOSInstallations(List, PartList, PartEntry);
819 }
820
821 /* Then, the logical partitions (present in the extended partition) */
822 Entry2 = DiskEntry->LogicalPartListHead.Flink;
823 while (Entry2 != &DiskEntry->LogicalPartListHead)
824 {
825 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
826 Entry2 = Entry2->Flink;
827
828 ASSERT(PartEntry->DiskEntry == DiskEntry);
829
830 DPRINT(" Logical Partition #%d, index %d - Type 0x%02x, IsLogical = %s, IsPartitioned = %s, IsNew = %s, FormatState = %lu -- Should I check it? %s\n",
831 PartEntry->PartitionNumber, PartEntry->PartitionIndex,
832 PartEntry->PartitionType, PartEntry->LogicalPartition ? "TRUE" : "FALSE",
833 PartEntry->IsPartitioned ? "TRUE" : "FALSE",
834 PartEntry->New ? "Yes" : "No",
835 PartEntry->FormatState,
836 ShouldICheckThisPartition(PartEntry) ? "YES!" : "NO!");
837
838 if (ShouldICheckThisPartition(PartEntry))
839 FindNTOSInstallations(List, PartList, PartEntry);
840 }
841 }
842
843#ifndef NDEBUG
844 /**** Debugging: List all the collected installations ****/
845 DumpNTOSInstalls(List);
846#endif
847
848 return List;
849}
850
851/* EOF */
static const char VendorName[]
Definition: ParaNdis-Oid.c:36
unsigned char BOOLEAN
Type
Definition: Type.h:7
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 BOOLEAN CreateNew)
Definition: bldrsup.c:664
NTSTATUS EnumerateBootStoreEntries(IN PVOID Handle, IN PENUM_BOOT_ENTRIES_ROUTINE EnumBootEntriesRoutine, IN PVOID Parameter OPTIONAL)
Definition: bldrsup.c:1486
NTSTATUS FindBootStore(IN HANDLE PartitionDirectoryHandle, IN BOOT_STORE_TYPE Type, OUT PULONG VersionNumber OPTIONAL)
Definition: bldrsup.c:137
NTSTATUS CloseBootStore(IN PVOID Handle)
Definition: bldrsup.c:754
@ BldrTypeMax
Definition: bldrsup.h:18
@ FreeLdr
Definition: bldrsup.h:15
struct _NTOS_OPTIONS * PNTOS_OPTIONS
#define NTOS_OPTIONS_SIGNATURE
Definition: bldrsup.h:98
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:32
#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:771
NTSTATUS OpenAndMapFile(IN HANDLE RootDirectory OPTIONAL, IN PCWSTR PathNameToFile, OUT PHANDLE FileHandle, OUT PHANDLE SectionHandle, OUT PVOID *BaseAddress, OUT PULONG FileSize OPTIONAL, IN BOOLEAN ReadWriteAccess)
Definition: filesup.c:858
#define UnMapAndCloseFile(FileHandle, SectionHandle, BaseAddress)
Definition: filesup.h:108
#define DoesDirExist(RootDirectory, DirName)
Definition: filesup.h:74
#define DoesFileExist(RootDirectory, FileName)
Definition: filesup.h:77
_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
@ Preformatted
Definition: partlist.h:37
if(dx< 0)
Definition: linetemp.h:194
POINT cp
Definition: magnifier.c:59
struct S1 s1
struct S2 s2
#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
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 UNICODE_NULL
#define IsContainerPartition(PartitionType)
Definition: ntdddisk.h:316
#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
FORCEINLINE BOOLEAN ShouldICheckThisPartition(IN PPARTENTRY PartEntry)
Definition: osdetect.c:763
static PNTOS_INSTALLATION FindExistingNTOSInstall(IN PGENERIC_LIST List, IN PCWSTR SystemRootArcPath OPTIONAL, IN PUNICODE_STRING SystemRootNtPath OPTIONAL)
Definition: osdetect.c:565
static VOID FindNTOSInstallations(IN OUT PGENERIC_LIST List, IN PPARTLIST PartList, IN PPARTENTRY PartEntry)
Definition: osdetect.c:682
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, IN PPARTENTRY PartEntry OPTIONAL)
Definition: osdetect.c:609
static const PCWSTR KnownVendors[]
Definition: osdetect.c:29
struct _ENUM_INSTALLS_DATA * PENUM_INSTALLS_DATA
PGENERIC_LIST CreateNTOSInstallationsList(IN PPARTLIST PartList)
Definition: osdetect.c:777
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:70
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
BOOLEAN GetDiskOrPartition(IN PPARTLIST List, IN ULONG DiskNumber, IN ULONG PartitionNumber OPTIONAL, OUT PDISKENTRY *pDiskEntry, OUT PPARTENTRY *pPartEntry OPTIONAL)
Definition: partlist.c:2163
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define DPRINT
Definition: sndvol32.h:71
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
base of all file and directory entries
Definition: entries.h:83
Definition: bldrsup.h:63
LIST_ENTRY LogicalPartListHead
Definition: partlist.h:129
ULONG DiskNumber
Definition: partlist.h:108
LIST_ENTRY PrimaryPartListHead
Definition: partlist.h:128
IN PPARTLIST PartList
Definition: osdetect.c:63
IN OUT PGENERIC_LIST List
Definition: osdetect.c:62
Definition: genlist.h:11
IMAGE_FILE_HEADER FileHeader
Definition: ntddk_ex.h:183
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
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
PPARTENTRY PartEntry
Definition: osdetect.h:25
UNICODE_STRING SystemArcPath
Definition: osdetect.h:20
PCWSTR PathComponent
Definition: osdetect.h:22
BOOLEAN IsPartitioned
Definition: partlist.h:66
UCHAR PartitionType
Definition: partlist.h:53
BOOLEAN New
Definition: partlist.h:71
struct _DISKENTRY * DiskEntry
Definition: partlist.h:46
BOOLEAN LogicalPartition
Definition: partlist.h:63
FORMATSTATE FormatState
Definition: partlist.h:61
ULONG PartitionNumber
Definition: partlist.h:55
ULONG PartitionIndex
Definition: partlist.h:56
#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_ WDFDEVICE _In_ LPCGUID _Out_ PINTERFACE _In_ USHORT _In_ USHORT Version
Definition: wdffdo.h:469
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
#define FORCEINLINE
Definition: wdftypes.h:67
_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:323
__wchar_t WCHAR
Definition: xmlstorage.h:180