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
11 #include <ndk/ldrtypes.h>
12 #include <ndk/ldrfuncs.h>
21 /* GLOBALS ******************************************************************/
23 extern PPARTLIST PartitionList
;
25 /* Language-independent Vendor strings */
26 static const PCWSTR KnownVendors
[] = { L
"ReactOS", L
"Microsoft" };
29 /* VERSION RESOURCE API ******************************************************/
32 * NT-oriented version resource management, adapted from dll/win32/version.
33 * We only deal with 32-bit PE executables.
40 OUT PULONG ResourceSize OPTIONAL
)
42 // #define RT_VERSION MAKEINTRESOURCE(16) // See winuser.h
43 #define VS_VERSION_INFO 1 // See psdk/verrsrc.h
44 #define VS_FILE_INFO RT_VERSION
47 LDR_RESOURCE_INFO ResourceInfo
;
48 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
52 /* Try to find the resource */
53 ResourceInfo
.Type
= 16; // RT_VERSION;
54 ResourceInfo
.Name
= VS_VERSION_INFO
; // MAKEINTRESOURCEW(VS_VERSION_INFO);
55 ResourceInfo
.Language
= 0; // Don't care about the language
57 Status
= LdrFindResource_U(BaseAddress
,
61 if (!NT_SUCCESS(Status
))
63 DPRINT1("NtGetVersionResource: Version resource not found, Status 0x%08lx\n", Status
);
67 /* Access the resource */
68 Status
= LdrAccessResource(BaseAddress
,
72 if (!NT_SUCCESS(Status
))
74 DPRINT1("NtGetVersionResource: Cannot access Version resource, Status 0x%08lx\n", Status
);
79 if (ResourceSize
) *ResourceSize
= Size
;
81 return STATUS_SUCCESS
;
84 /* NOTE: the xxx_STRUCT16 version differs by storing strings in ANSI, not in UNICODE */
85 typedef struct _VS_VERSION_INFO_STRUCT32
89 WORD wType
; /* 1:Text, 0:Binary */
91 #if 0 /* variable length structure */
95 VS_VERSION_INFO_STRUCT32 Children
[];
97 } VS_VERSION_INFO_STRUCT32
, *PVS_VERSION_INFO_STRUCT32
;
98 typedef const VS_VERSION_INFO_STRUCT32
*PCVS_VERSION_INFO_STRUCT32
;
100 #define DWORD_ALIGN( base, ptr ) \
101 ( (ULONG_PTR)(base) + ((((ULONG_PTR)(ptr) - (ULONG_PTR)(base)) + 3) & ~3) )
103 #define VersionInfo32_Value( ver ) \
104 DWORD_ALIGN( (ver), (ver)->szKey + wcslen((ver)->szKey) + 1 )
106 #define VersionInfo32_Children( ver ) \
107 (PCVS_VERSION_INFO_STRUCT32)( VersionInfo32_Value( ver ) + \
108 ( ( (ver)->wValueLength * \
109 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
111 #define VersionInfo32_Next( ver ) \
112 (PVS_VERSION_INFO_STRUCT32)( (ULONG_PTR)ver + (((ver)->wLength + 3) & ~3) )
114 static PCVS_VERSION_INFO_STRUCT32
115 VersionInfo32_FindChild(
116 IN PCVS_VERSION_INFO_STRUCT32 info
,
120 PCVS_VERSION_INFO_STRUCT32 child
= VersionInfo32_Children(info
);
122 while ((ULONG_PTR
)child
< (ULONG_PTR
)info
+ info
->wLength
)
124 if (!_wcsnicmp(child
->szKey
, szKey
, cbKey
) && !child
->szKey
[cbKey
])
127 if (child
->wLength
== 0) return NULL
;
128 child
= VersionInfo32_Next(child
);
135 VersionInfo32_QueryValue(
136 IN PCVS_VERSION_INFO_STRUCT32 info
,
137 IN PCWSTR lpSubBlock
,
138 OUT PVOID
* lplpBuffer
,
139 OUT PUINT puLen OPTIONAL
,
140 OUT BOOL
* pbText OPTIONAL
)
144 DPRINT("lpSubBlock : (%S)\n", lpSubBlock
);
148 /* Find next path component */
149 for (lpNextSlash
= lpSubBlock
; *lpNextSlash
; lpNextSlash
++)
151 if (*lpNextSlash
== '\\')
155 /* Skip empty components */
156 if (lpNextSlash
== lpSubBlock
)
162 /* We have a non-empty component: search info for key */
163 info
= VersionInfo32_FindChild(info
, lpSubBlock
, lpNextSlash
- lpSubBlock
);
166 if (puLen
) *puLen
= 0;
167 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
170 /* Skip path component */
171 lpSubBlock
= lpNextSlash
;
175 *lplpBuffer
= (PVOID
)VersionInfo32_Value(info
);
177 *puLen
= info
->wValueLength
;
179 *pbText
= info
->wType
;
181 return STATUS_SUCCESS
;
186 IN
const VOID
* pBlock
,
187 IN PCWSTR lpSubBlock
,
188 OUT PVOID
* lplpBuffer
,
191 PCVS_VERSION_INFO_STRUCT32 info
= pBlock
;
193 DPRINT("%s (%p, %S, %p, %p)\n", __FUNCTION__
, pBlock
, lpSubBlock
, lplpBuffer
, puLen
);
198 if (!lpSubBlock
|| !*lpSubBlock
)
201 return VersionInfo32_QueryValue(info
, lpSubBlock
, lplpBuffer
, puLen
, NULL
);
206 /* FUNCTIONS ****************************************************************/
210 BOOL
IsWindowsOS(VOID
)
213 // Load the "SystemRoot\System32\Config\SOFTWARE" hive and mount it,
214 // then go to (SOFTWARE\\)Microsoft\\Windows NT\\CurrentVersion,
215 // check the REG_SZ value "ProductName" and see whether it's "Windows"
216 // or "ReactOS". One may also check the REG_SZ "CurrentVersion" value,
217 // the REG_SZ "SystemRoot" and "PathName" values (what are the differences??).
219 // Optionally, looking at the SYSTEM hive, CurrentControlSet\\Control,
220 // REG_SZ values "SystemBootDevice" (and "FirmwareBootDevice" ??)...
223 /* ReactOS reports as Windows NT 5.2 */
226 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
227 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
228 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
231 DWORD dwType
= 0, dwBufSize
= 0;
233 ret
= RegQueryValueExW(hKey
, L
"ProductName", NULL
, &dwType
, NULL
, &dwBufSize
);
234 if (ret
== ERROR_SUCCESS
&& dwType
== REG_SZ
)
236 LPTSTR lpszProductName
= (LPTSTR
)MemAlloc(0, dwBufSize
);
237 RegQueryValueExW(hKey
, L
"ProductName", NULL
, &dwType
, (LPBYTE
)lpszProductName
, &dwBufSize
);
239 bIsWindowsOS
= (FindSubStrI(lpszProductName
, _T("Windows")) != NULL
);
241 MemFree(lpszProductName
);
252 typedef enum _NTOS_BOOT_LOADER_TYPE
254 FreeLdr
, // ReactOS' FreeLDR
255 NtLdr
, // Windows <= 2k3 NTLDR
256 // BootMgr, // Vista+ BCD-oriented BOOTMGR
257 } NTOS_BOOT_LOADER_TYPE
;
259 typedef struct _NTOS_BOOT_LOADER_FILES
261 NTOS_BOOT_LOADER_TYPE Type
;
262 PCWSTR LoaderExecutable
;
263 PCWSTR LoaderConfigurationFile
;
264 // EnumerateInstallations;
265 } NTOS_BOOT_LOADER_FILES
, *PNTOS_BOOT_LOADER_FILES
;
267 // Question 1: What if config file is optional?
268 // Question 2: What if many config files are possible?
269 NTOS_BOOT_LOADER_FILES NtosBootLoaders
[] =
271 {FreeLdr
, L
"freeldr.sys", L
"freeldr.ini"},
272 {NtLdr
, L
"ntldr" , L
"boot.ini"},
273 {NtLdr
, L
"setupldr" , L
"txtsetup.sif"},
274 // {BootMgr, L"bootmgr" , ???}
280 EnumerateInstallationsFreeLdr()
284 PINICACHESECTION IniSection
;
285 PINICACHESECTION OsIniSection
;
286 WCHAR SectionName
[80];
288 WCHAR SystemPath
[200];
289 WCHAR SectionName2
[200];
293 /* Open an *existing* FreeLdr.ini configuration file */
294 Status
= IniCacheLoad(&IniCache
, IniPath
, FALSE
);
295 if (!NT_SUCCESS(Status
))
298 /* Get "Operating Systems" section */
299 IniSection
= IniCacheGetSection(IniCache
, L
"Operating Systems");
300 if (IniSection
== NULL
)
302 IniCacheDestroy(IniCache
);
303 return STATUS_UNSUCCESSFUL
;
306 /* NOTE that we enumerate all the valid installations, not just the default one */
309 Status
= IniCacheGetKey(IniSection
, SectionName
, &KeyData
);
310 if (!NT_SUCCESS(Status
))
313 // TODO some foobaring...
315 // TODO 2 : Remind the entry name so that we may display it as available installation...
317 /* Search for an existing ReactOS entry */
318 OsIniSection
= IniCacheGetSection(IniCache
, SectionName2
);
319 if (OsIniSection
!= NULL
)
321 BOOLEAN UseExistingEntry
= TRUE
;
323 /* Check for supported boot type "Windows2003" */
324 Status
= IniCacheGetKey(OsIniSection
, L
"BootType", &KeyData
);
325 if (NT_SUCCESS(Status
))
327 if ((KeyData
== NULL
) ||
328 ( (_wcsicmp(KeyData
, L
"Windows2003") != 0) &&
329 (_wcsicmp(KeyData
, L
"\"Windows2003\"") != 0) ))
331 /* This is not a ReactOS entry */
332 UseExistingEntry
= FALSE
;
337 UseExistingEntry
= FALSE
;
340 if (UseExistingEntry
)
342 /* BootType is Windows2003. Now check SystemPath. */
343 Status
= IniCacheGetKey(OsIniSection
, L
"SystemPath", &KeyData
);
344 if (NT_SUCCESS(Status
))
346 swprintf(SystemPath
, L
"\"%s\"", ArcPath
);
347 if ((KeyData
== NULL
) ||
348 ( (_wcsicmp(KeyData
, ArcPath
) != 0) &&
349 (_wcsicmp(KeyData
, SystemPath
) != 0) ))
351 /* This entry is a ReactOS entry, but the SystemRoot
352 does not match the one we are looking for. */
353 UseExistingEntry
= FALSE
;
358 UseExistingEntry
= FALSE
;
364 IniCacheDestroy(IniCache
);
371 * FindSubStrI(PCWSTR str, PCWSTR strSearch) :
372 * Searches for a sub-string 'strSearch' inside 'str', similarly to what
373 * wcsstr(str, strSearch) does, but ignores the case during the comparisons.
375 PWSTR
FindSubStrI(PCWSTR str
, PCWSTR strSearch
)
377 PWSTR cp
= (PWSTR
)str
;
386 s2
= (PWSTR
)strSearch
;
388 while (*s1
&& *s2
&& (towupper(*s1
) == towupper(*s2
)))
401 CheckForValidPEAndVendor(
402 IN HANDLE RootDirectory OPTIONAL
,
403 IN PCWSTR PathName OPTIONAL
,
404 IN PCWSTR FileName
, // OPTIONAL
405 IN PCWSTR VendorName
// Better would be OUT PCWSTR*, and the function returning NTSTATUS ?
408 BOOLEAN Success
= FALSE
;
410 HANDLE FileHandle
, SectionHandle
;
413 PVOID VersionBuffer
= NULL
; // Read-only
417 Status
= OpenAndMapFile(RootDirectory
, PathName
, FileName
,
418 &FileHandle
, &SectionHandle
, &ViewBase
);
419 if (!NT_SUCCESS(Status
))
421 DPRINT1("Failed to open and map file %wZ, Status 0x%08lx\n", &FileName
, Status
);
422 return FALSE
; // Status;
425 /* Make sure it's a valid PE file */
426 if (!RtlImageNtHeader(ViewBase
))
428 DPRINT1("File %wZ does not seem to be a valid PE, bail out\n", &FileName
);
429 Status
= STATUS_INVALID_IMAGE_FORMAT
;
434 * Search for a valid executable version and vendor.
435 * NOTE: The module is loaded as a data file, it should be marked as such.
437 Status
= NtGetVersionResource((PVOID
)((ULONG_PTR
)ViewBase
| 1), &VersionBuffer
, NULL
);
438 if (!NT_SUCCESS(Status
))
440 DPRINT1("Failed to get version resource for file %wZ, Status 0x%08lx\n", &FileName
, Status
);
444 Status
= NtVerQueryValue(VersionBuffer
, L
"\\VarFileInfo\\Translation", &pvData
, &BufLen
);
445 if (NT_SUCCESS(Status
))
447 USHORT wCodePage
= 0, wLangID
= 0;
448 WCHAR FileInfo
[MAX_PATH
];
449 UNICODE_STRING Vendor
;
451 wCodePage
= LOWORD(*(ULONG
*)pvData
);
452 wLangID
= HIWORD(*(ULONG
*)pvData
);
454 StringCchPrintfW(FileInfo
, ARRAYSIZE(FileInfo
),
455 L
"StringFileInfo\\%04X%04X\\CompanyName",
458 Status
= NtVerQueryValue(VersionBuffer
, FileInfo
, &pvData
, &BufLen
);
459 if (NT_SUCCESS(Status
) && pvData
)
461 /* BufLen includes the NULL terminator count */
462 RtlInitEmptyUnicodeString(&Vendor
, pvData
, BufLen
* sizeof(WCHAR
));
463 Vendor
.Length
= Vendor
.MaximumLength
- sizeof(UNICODE_NULL
);
465 DPRINT1("Found version vendor: \"%wZ\" for file %wZ\n", &Vendor
, &FileName
);
467 Success
= !!FindSubStrI(pvData
, VendorName
);
471 DPRINT1("No version vendor found for file %wZ\n", &FileName
);
476 /* Finally, unmap and close the file */
477 UnMapFile(SectionHandle
, ViewBase
);
484 IsValidNTOSInstallation(
485 IN HANDLE PartitionHandle
,
486 IN PCWSTR SystemRoot
)
488 BOOLEAN Success
= FALSE
;
490 WCHAR PathBuffer
[MAX_PATH
];
492 // DoesPathExist(PartitionHandle, SystemRoot, L"System32\\"); etc...
494 /* Check for the existence of \SystemRoot\System32 */
495 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
), L
"%s%s", SystemRoot
, L
"System32\\");
496 if (!DoesPathExist(PartitionHandle
, PathBuffer
))
498 // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
502 /* Check for the existence of \SystemRoot\System32\drivers */
503 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
), L
"%s%s", SystemRoot
, L
"System32\\drivers\\");
504 if (!DoesPathExist(PartitionHandle
, PathBuffer
))
506 // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
510 /* Check for the existence of \SystemRoot\System32\config */
511 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
), L
"%s%s", SystemRoot
, L
"System32\\config\\");
512 if (!DoesPathExist(PartitionHandle
, PathBuffer
))
514 // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
520 * Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
521 * (but we don't check here whether they are actually valid).
523 if (!DoesFileExist(PartitionHandle
, SystemRoot
, L
"System32\\config\\SYSTEM"))
525 // DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &FileName, Status);
528 if (!DoesFileExist(PartitionHandle
, SystemRoot
, L
"System32\\config\\SOFTWARE"))
530 // DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &FileName, Status);
535 for (i
= 0; i
< ARRAYSIZE(KnownVendors
); ++i
)
537 /* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and verify its version */
538 Success
= CheckForValidPEAndVendor(PartitionHandle
, SystemRoot
, L
"System32\\ntoskrnl.exe", KnownVendors
[i
]);
540 /* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
542 /* Check for the existence of \SystemRoot\System32\ntdll.dll */
543 Success
= CheckForValidPEAndVendor(PartitionHandle
, SystemRoot
, L
"System32\\ntdll.dll", KnownVendors
[i
]);
545 /* We have found a correct vendor combination */
555 IN PGENERIC_LIST List
)
557 PGENERIC_LIST_ENTRY Entry
;
558 PNTOS_INSTALLATION NtOsInstall
;
559 ULONG NtOsInstallsCount
= GetNumberOfListEntries(List
);
561 DPRINT1("There %s %d installation%s detected:\n",
562 NtOsInstallsCount
>= 2 ? "are" : "is",
564 NtOsInstallsCount
>= 2 ? "s" : "");
566 Entry
= GetFirstListEntry(List
);
569 NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryUserData(Entry
);
570 Entry
= GetNextListEntry(Entry
);
572 DPRINT1(" On disk #%d, partition #%d: Installation \"%S\" in SystemRoot %S\n",
573 NtOsInstall
->DiskNumber
, NtOsInstall
->PartitionNumber
,
574 NtOsInstall
->InstallationName
, NtOsInstall
->SystemRoot
);
580 static PNTOS_INSTALLATION
581 FindExistingNTOSInstall(
582 IN PGENERIC_LIST List
,
584 IN ULONG PartitionNumber
,
585 IN PCWSTR SystemRoot
)
587 PGENERIC_LIST_ENTRY Entry
;
588 PNTOS_INSTALLATION NtOsInstall
;
590 Entry
= GetFirstListEntry(List
);
593 NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryUserData(Entry
);
594 Entry
= GetNextListEntry(Entry
);
596 if (NtOsInstall
->DiskNumber
== DiskNumber
&&
597 NtOsInstall
->PartitionNumber
== PartitionNumber
&&
598 _wcsicmp(NtOsInstall
->SystemRoot
, SystemRoot
) == 0)
608 static PNTOS_INSTALLATION
610 IN PGENERIC_LIST List
,
612 IN ULONG PartitionNumber
,
613 IN PCWSTR SystemRoot
,
614 IN PCWSTR InstallationName
)
616 PNTOS_INSTALLATION NtOsInstall
;
617 CHAR InstallNameA
[MAX_PATH
];
619 /* Is there already any installation with these settings? */
620 NtOsInstall
= FindExistingNTOSInstall(List
, DiskNumber
, PartitionNumber
, SystemRoot
);
623 DPRINT1("An NTOS installation with name \"%S\" already exists on disk #%d, partition #%d, in SystemRoot %S\n",
624 NtOsInstall
->InstallationName
, NtOsInstall
->DiskNumber
, NtOsInstall
->PartitionNumber
, NtOsInstall
->SystemRoot
);
628 /* None was found, so add a new one */
629 NtOsInstall
= RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(*NtOsInstall
));
633 NtOsInstall
->DiskNumber
= DiskNumber
;
634 NtOsInstall
->PartitionNumber
= PartitionNumber
;
635 StringCchCopyW(NtOsInstall
->SystemRoot
, ARRAYSIZE(NtOsInstall
->SystemRoot
), SystemRoot
);
636 StringCchCopyW(NtOsInstall
->InstallationName
, ARRAYSIZE(NtOsInstall
->InstallationName
), InstallationName
);
638 // Having the GENERIC_LIST storing the display item string plainly sucks...
639 StringCchPrintfA(InstallNameA
, ARRAYSIZE(InstallNameA
), "%S", InstallationName
);
640 AppendGenericListEntry(List
, InstallNameA
, NtOsInstall
, FALSE
);
646 FindNTOSInstallations(
647 IN PGENERIC_LIST List
,
649 IN ULONG PartitionNumber
)
653 HANDLE PartitionHandle
, FileHandle
;
654 OBJECT_ATTRIBUTES ObjectAttributes
;
655 IO_STATUS_BLOCK IoStatusBlock
;
656 UNICODE_STRING PartitionRootPath
;
657 HANDLE SectionHandle
;
660 WCHAR PathBuffer
[MAX_PATH
];
661 WCHAR SystemRoot
[MAX_PATH
];
662 WCHAR InstallNameW
[MAX_PATH
];
664 /* Set PartitionRootPath */
666 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
667 DiskNumber
, PartitionNumber
);
668 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
669 DPRINT1("FindNTOSInstallations: PartitionRootPath: %wZ\n", &PartitionRootPath
);
671 /* Open the partition */
672 InitializeObjectAttributes(&ObjectAttributes
,
674 OBJ_CASE_INSENSITIVE
,
677 Status
= NtOpenFile(&PartitionHandle
,
678 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
681 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
682 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_DIRECTORY_FILE
);
683 if (!NT_SUCCESS(Status
))
685 DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath
, Status
);
689 /* Try to see whether we recognize some NT boot loaders */
690 for (i
= 0; i
< ARRAYSIZE(NtosBootLoaders
); ++i
)
692 /* Check whether the loader executable exists */
693 if (!DoesFileExist(PartitionHandle
, NULL
, NtosBootLoaders
[i
].LoaderExecutable
))
695 /* The loader does not exist, continue with another one */
696 DPRINT1("Loader executable %S does not exist, continue with another one...\n", NtosBootLoaders
[i
].LoaderExecutable
);
700 /* Check whether the loader configuration file exists */
701 Status
= OpenAndMapFile(PartitionHandle
, NULL
, NtosBootLoaders
[i
].LoaderConfigurationFile
,
702 &FileHandle
, &SectionHandle
, &ViewBase
);
703 if (!NT_SUCCESS(Status
))
705 /* The loader does not exist, continue with another one */
706 // FIXME: Consider it might be optional??
707 DPRINT1("Loader configuration file %S does not exist, continue with another one...\n", NtosBootLoaders
[i
].LoaderConfigurationFile
);
711 /* The loader configuration file exists, interpret it to find valid installations */
713 DPRINT1("TODO: Analyse the OS installations inside %S !\n", NtosBootLoaders
[i
].LoaderConfigurationFile
);
715 // Here we get a SystemRootPath for each installation // FIXME!
716 // FIXME: Do NOT hardcode the path!! But retrieve it from boot.ini etc...
717 StringCchCopyW(SystemRoot
, ARRAYSIZE(SystemRoot
), L
"WINDOWS\\");
718 if (IsValidNTOSInstallation(PartitionHandle
, SystemRoot
))
720 DPRINT1("Found a valid NTOS installation in disk #%d, partition #%d, SystemRoot %S\n",
721 DiskNumber
, PartitionNumber
, SystemRoot
);
722 StringCchPrintfW(InstallNameW
, ARRAYSIZE(InstallNameW
), L
"%C: \\Device\\Harddisk%lu\\Partition%lu\\%s \"%s\"",
723 'X' /* FIXME: Partition letter */, DiskNumber
, PartitionNumber
, SystemRoot
, L
"Windows (placeholder)");
724 AddNTOSInstallation(List
, DiskNumber
, PartitionNumber
, SystemRoot
, InstallNameW
);
727 // Here we get a SystemRootPath for each installation // FIXME!
728 // FIXME: Do NOT hardcode the path!! But retrieve it from boot.ini etc...
729 StringCchCopyW(SystemRoot
, ARRAYSIZE(SystemRoot
), L
"ReactOS\\");
730 if (IsValidNTOSInstallation(PartitionHandle
, SystemRoot
))
732 DPRINT1("Found a valid NTOS installation in disk #%d, partition #%d, SystemRoot %S\n",
733 DiskNumber
, PartitionNumber
, SystemRoot
);
734 StringCchPrintfW(InstallNameW
, ARRAYSIZE(InstallNameW
), L
"%C: \\Device\\Harddisk%lu\\Partition%lu\\%s \"%s\"",
735 'X' /* FIXME: Partition letter */, DiskNumber
, PartitionNumber
, SystemRoot
, L
"ReactOS (placeholder)");
736 AddNTOSInstallation(List
, DiskNumber
, PartitionNumber
, SystemRoot
, InstallNameW
);
739 /* Finally, unmap and close the file */
740 UnMapFile(SectionHandle
, ViewBase
);
744 /* Close the partition */
745 NtClose(PartitionHandle
);
750 ShouldICheckThisPartition(
751 IN PPARTENTRY PartEntry
)
756 return PartEntry
->IsPartitioned
&&
757 !IsContainerPartition(PartEntry
->PartitionType
) /* alternatively: PartEntry->PartitionNumber != 0 */ &&
759 (PartEntry
->FormatState
== Preformatted
/* || PartEntry->FormatState == Formatted */);
762 // EnumerateNTOSInstallations
764 CreateNTOSInstallationsList(
765 IN PPARTLIST PartList
)
768 PLIST_ENTRY Entry
, Entry2
;
769 PDISKENTRY DiskEntry
;
770 PPARTENTRY PartEntry
;
772 List
= CreateGenericList();
776 /* Loop each available disk ... */
777 Entry
= PartList
->DiskListHead
.Flink
;
778 while (Entry
!= &PartList
->DiskListHead
)
780 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
781 Entry
= Entry
->Flink
;
783 DPRINT1("Disk #%d\n", DiskEntry
->DiskNumber
);
785 /* ... and for each disk, loop each available partition */
787 /* First, the primary partitions */
788 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
789 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
791 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
792 Entry2
= Entry2
->Flink
;
794 DPRINT1(" Primary Partition #%d, index %d - Type 0x%02x, IsLogical = %s, IsPartitioned = %s, IsNew = %s, AutoCreate = %s, FormatState = %lu -- Should I check it? %s\n",
795 PartEntry
->PartitionNumber
, PartEntry
->PartitionIndex
,
796 PartEntry
->PartitionType
, PartEntry
->LogicalPartition
? "TRUE" : "FALSE",
797 PartEntry
->IsPartitioned
? "TRUE" : "FALSE",
798 PartEntry
->New
? "Yes" : "No",
799 PartEntry
->AutoCreate
? "Yes" : "No",
800 PartEntry
->FormatState
,
801 ShouldICheckThisPartition(PartEntry
) ? "YES!" : "NO!");
803 if (ShouldICheckThisPartition(PartEntry
))
804 FindNTOSInstallations(List
, DiskEntry
->DiskNumber
, PartEntry
->PartitionNumber
);
807 /* Then, the logical partitions (present in the extended partition) */
808 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
809 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
811 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
812 Entry2
= Entry2
->Flink
;
814 DPRINT1(" Logical Partition #%d, index %d - Type 0x%02x, IsLogical = %s, IsPartitioned = %s, IsNew = %s, AutoCreate = %s, FormatState = %lu -- Should I check it? %s\n",
815 PartEntry
->PartitionNumber
, PartEntry
->PartitionIndex
,
816 PartEntry
->PartitionType
, PartEntry
->LogicalPartition
? "TRUE" : "FALSE",
817 PartEntry
->IsPartitioned
? "TRUE" : "FALSE",
818 PartEntry
->New
? "Yes" : "No",
819 PartEntry
->AutoCreate
? "Yes" : "No",
820 PartEntry
->FormatState
,
821 ShouldICheckThisPartition(PartEntry
) ? "YES!" : "NO!");
823 if (ShouldICheckThisPartition(PartEntry
))
824 FindNTOSInstallations(List
, DiskEntry
->DiskNumber
, PartEntry
->PartitionNumber
);
828 /**** Debugging: List all the collected installations ****/
829 ListNTOSInstalls(List
);