[USETUP] Further improve the OS detection code.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 22 May 2017 22:59:11 +0000 (22:59 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 31 May 2018 16:01:01 +0000 (18:01 +0200)
- Improve FindExistingNTOSInstall() so that we can find an existing installation either by system root
  ARC path or NT path. This is used during the enumeration of available installations from the boot.ini/freeldr.ini
  and during other existence & validity checks of NTOS installations.
- Improve AddNTOSInstallation() so that we can save the system root ARC path and NT path of the installation,
  as well as its partition entry structure pointer, for caching & later retrieval purposes.
- Remove some deprecated comments & todos, and implement other todos.
- Improve the output of some DPRINTs.
- Fix the return value of FindSubStrI.

svn path=/branches/setup_improvements/; revision=74632

base/setup/usetup/osdetect.c
base/setup/usetup/osdetect.h

index 34c18e7..97cc643 100644 (file)
@@ -29,7 +29,7 @@ static const PCWSTR KnownVendors[] = { L"ReactOS", L"Microsoft" };
 
 BOOL IsWindowsOS(VOID)
 {
-    // TODO:
+    // TODO:
     // Load the "SystemRoot\System32\Config\SOFTWARE" hive and mount it,
     // then go to (SOFTWARE\\)Microsoft\\Windows NT\\CurrentVersion,
     // check the REG_SZ value "ProductName" and see whether it's "Windows"
@@ -100,12 +100,22 @@ IsValidNTOSInstallation(
     IN HANDLE SystemRootDirectory OPTIONAL,
     IN PCWSTR SystemRoot OPTIONAL);
 
+static PNTOS_INSTALLATION
+FindExistingNTOSInstall(
+    IN PGENERIC_LIST List,
+    IN PCWSTR SystemRootArcPath OPTIONAL,
+    IN PUNICODE_STRING SystemRootNtPath OPTIONAL // or PCWSTR ?
+    );
+
 static PNTOS_INSTALLATION
 AddNTOSInstallation(
     IN PGENERIC_LIST List,
+    IN PCWSTR SystemRootArcPath,
+    IN PUNICODE_STRING SystemRootNtPath, // or PCWSTR ?
+    IN PCWSTR PathComponent,    // Pointer inside SystemRootNtPath buffer
     IN ULONG DiskNumber,
     IN ULONG PartitionNumber,
-    IN PCWSTR SystemRoot,
+    IN PPARTENTRY PartEntry OPTIONAL,
     IN PCWSTR InstallationName);
 
 static NTSTATUS
@@ -121,7 +131,15 @@ FreeLdrEnumerateInstallations(
     PINICACHEITERATOR Iterator;
     PINICACHESECTION IniSection, OsIniSection;
     PWCHAR SectionName, KeyData;
-    WCHAR InstallName[MAX_PATH];
+    UNICODE_STRING InstallName;
+
+    HANDLE SystemRootDirectory;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PNTOS_INSTALLATION NtOsInstall;
+    UNICODE_STRING SystemRootPath;
+    WCHAR SystemRoot[MAX_PATH];
+    WCHAR InstallNameW[MAX_PATH];
 
     /* Open an *existing* FreeLdr.ini configuration file */
     Status = IniCacheLoadFromMemory(&IniCache, FileBuffer, FileLength, FALSE);
@@ -149,16 +167,16 @@ FreeLdrEnumerateInstallations(
             PWCHAR End   = wcschr(Begin, L'"');
             if (!End)
                 End = Begin + wcslen(Begin);
-            StringCchCopyNW(InstallName, ARRAYSIZE(InstallName),
-                            Begin, End - Begin);
+            RtlInitEmptyUnicodeString(&InstallName, Begin, (ULONG_PTR)End - (ULONG_PTR)Begin);
+            InstallName.Length = InstallName.MaximumLength;
         }
         else
         {
             /* Non-quoted name, copy everything */
-            StringCchCopyW(InstallName, ARRAYSIZE(InstallName), KeyData);
+            RtlInitUnicodeString(&InstallName, KeyData);
         }
 
-        DPRINT1("Possible installation '%S' in OS section '%S'\n", InstallName, SectionName);
+        DPRINT1("Possible installation '%wZ' in OS section '%S'\n", &InstallName, SectionName);
 
         /* Search for an existing ReactOS entry */
         OsIniSection = IniCacheGetSection(IniCache, SectionName);
@@ -188,27 +206,25 @@ FreeLdrEnumerateInstallations(
         Status = IniCacheGetKey(OsIniSection, L"SystemPath", &KeyData);
         if (!NT_SUCCESS(Status))
         {
-            DPRINT1("    A Win2k3 install '%S' without an ARC path?!\n", InstallName);
+            DPRINT1("    A Win2k3 install '%wZ' without an ARC path?!\n", &InstallName);
             continue;
         }
 
-        {
-        HANDLE SystemRootDirectory;
-        OBJECT_ATTRIBUTES ObjectAttributes;
-        IO_STATUS_BLOCK IoStatusBlock;
-        UNICODE_STRING SystemRootPath;
-        WCHAR SystemRoot[MAX_PATH];
-        WCHAR InstallNameW[MAX_PATH];
-
-        DPRINT1("    Found a candidate Win2k3 install '%S' with ARC path '%S'\n", InstallName, KeyData);
+        DPRINT1("    Found a candidate Win2k3 install '%wZ' with ARC path '%S'\n", &InstallName, KeyData);
 
-        // Note that in ARC path, the disk number is the BIOS disk number, so a conversion
-        // should be done.
+        // TODO: Normalize the ARC path.
 
-        // TODO 1: Normalize the ARC path.
-
-        // TODO 2: Check whether we already have an installation with this ARC path.
-        //         If that's the case, stop there. If not, continue...
+        /*
+         * Check whether we already have an installation with this ARC path.
+         * If this is the case, stop there.
+         */
+        NtOsInstall = FindExistingNTOSInstall(List, KeyData, NULL);
+        if (NtOsInstall)
+        {
+            DPRINT1("    An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
+                    NtOsInstall->InstallationName, &NtOsInstall->SystemArcPath);
+            continue;
+        }
 
         /*
          * Convert the ARC path into an NT path, from which we will deduce
@@ -218,18 +234,26 @@ FreeLdrEnumerateInstallations(
         RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
         if (!ArcPathToNtPath(&SystemRootPath, KeyData, PartList))
         {
-            DPRINT1("ArcPathToNtPath(%S) failed, installation skipped.\n", KeyData);
-            // FIXME: Do not continue!
+            DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", KeyData);
             continue;
         }
 
-        DPRINT1("ArcPathToNtPath() succeeded: %S --> %wZ\n", KeyData, &SystemRootPath);
+        DPRINT1("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n", KeyData, &SystemRootPath);
 
-        // TODO 3: Check whether we already have an installation with this NT path.
-        //         If that's the case, stop there. If not, continue...
+        /*
+         * Check whether we already have an installation with this NT path.
+         * If this is the case, stop there.
+         */
+        NtOsInstall = FindExistingNTOSInstall(List, NULL /*KeyData*/, &SystemRootPath);
+        if (NtOsInstall)
+        {
+            DPRINT1("    An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
+                    NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
+            continue;
+        }
 
         /* Set SystemRootPath */
-        DPRINT1("FreeLdrEnumerateInstallations: SystemRootPath: %wZ\n", &SystemRootPath);
+        DPRINT1("FreeLdrEnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
 
         /* Open SystemRootPath */
         InitializeObjectAttributes(&ObjectAttributes,
@@ -245,18 +269,18 @@ FreeLdrEnumerateInstallations(
                             FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
         if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Failed to open SystemRoot %wZ, Status 0x%08lx\n", &SystemRootPath, Status);
+            DPRINT1("Failed to open SystemRoot '%wZ', Status 0x%08lx\n", &SystemRootPath, Status);
             continue;
         }
 
         if (IsValidNTOSInstallation(SystemRootDirectory, NULL))
         {
-            ULONG DiskNumber, PartitionNumber;
-            PCWSTR PathComponent;
+            ULONG DiskNumber = 0, PartitionNumber = 0;
+            PCWSTR PathComponent = NULL;
             PDISKENTRY DiskEntry = NULL;
             PPARTENTRY PartEntry = NULL;
 
-            DPRINT1("Found a valid NTOS installation in SystemRoot ARC path %S, NT path %wZ\n", KeyData, &SystemRootPath);
+            DPRINT1("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n", KeyData, &SystemRootPath);
 
             /* From the NT path, compute the disk, partition and path components */
             if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
@@ -276,20 +300,21 @@ FreeLdrEnumerateInstallations(
             if (PartEntry && PartEntry->DriveLetter)
             {
                 /* We have retrieved a partition that is mounted */
-                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%C:%s  \"%s\"",
-                                 PartEntry->DriveLetter, PathComponent, InstallName);
+                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%C:%s  \"%wZ\"",
+                                 PartEntry->DriveLetter, PathComponent, &InstallName);
             }
             else
             {
                 /* We failed somewhere, just show the NT path */
-                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ  \"%s\"",
-                                 &SystemRootPath, InstallName);
+                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ  \"%wZ\"",
+                                 &SystemRootPath, &InstallName);
             }
-            AddNTOSInstallation(List, 0, 0 /*DiskNumber, PartitionNumber*/, KeyData, InstallNameW);
+            AddNTOSInstallation(List, KeyData, &SystemRootPath, PathComponent,
+                                DiskNumber, PartitionNumber, PartEntry,
+                                InstallNameW);
         }
 
         NtClose(SystemRootDirectory);
-        }
     }
     while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
 
@@ -313,7 +338,15 @@ NtLdrEnumerateInstallations(
     PINICACHEITERATOR Iterator;
     PINICACHESECTION IniSection;
     PWCHAR SectionName, KeyData;
-    WCHAR InstallName[MAX_PATH];
+    UNICODE_STRING InstallName;
+
+    HANDLE SystemRootDirectory;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PNTOS_INSTALLATION NtOsInstall;
+    UNICODE_STRING SystemRootPath;
+    WCHAR SystemRoot[MAX_PATH];
+    WCHAR InstallNameW[MAX_PATH];
 
     /* Open an *existing* FreeLdr.ini configuration file */
     Status = IniCacheLoadFromMemory(&IniCache, FileBuffer, FileLength, FALSE);
@@ -341,40 +374,32 @@ NtLdrEnumerateInstallations(
             PWCHAR End   = wcschr(Begin, L'"');
             if (!End)
                 End = Begin + wcslen(Begin);
-            StringCchCopyNW(InstallName, ARRAYSIZE(InstallName),
-                            Begin, End - Begin);
+            RtlInitEmptyUnicodeString(&InstallName, Begin, (ULONG_PTR)End - (ULONG_PTR)Begin);
+            InstallName.Length = InstallName.MaximumLength;
         }
         else
         {
             /* Non-quoted name, copy everything */
-            StringCchCopyW(InstallName, ARRAYSIZE(InstallName), KeyData);
+            RtlInitUnicodeString(&InstallName, KeyData);
         }
 
-        DPRINT1("Possible installation '%S' with ARC path '%S'\n", InstallName, SectionName);
+        DPRINT1("Possible installation '%wZ' with ARC path '%S'\n", &InstallName, SectionName);
 
-        // FIXME TODO: Determine whether we indeed have an ARC path, in which case
-        // this is an NT installation, or, whether we have something else like a DOS
-        // path, which means that we are booting a boot sector...
+        DPRINT1("    Found a Win2k3 install '%wZ' with ARC path '%S'\n", &InstallName, SectionName);
 
-        DPRINT1("    Found a Win2k3 install '%S' with ARC path '%S'\n", InstallName, SectionName);
-        // TODO: Dissect it in order to retrieve the real disk drive & partition numbers.
-        // Note that in ARC path, the disk number is the BIOS disk number, so a conversion
-        // should be done.
-        {
-        HANDLE SystemRootDirectory;
-        OBJECT_ATTRIBUTES ObjectAttributes;
-        IO_STATUS_BLOCK IoStatusBlock;
-        UNICODE_STRING SystemRootPath;
-        WCHAR SystemRoot[MAX_PATH];
-        WCHAR InstallNameW[MAX_PATH];
+        // TODO: Normalize the ARC path.
 
-        // Note that in ARC path, the disk number is the BIOS disk number, so a conversion
-        // should be done.
-
-        // TODO 1: Normalize the ARC path.
-
-        // TODO 2: Check whether we already have an installation with this ARC path.
-        //         If that's the case, stop there. If not, continue...
+        /*
+         * Check whether we already have an installation with this ARC path.
+         * If this is the case, stop there.
+         */
+        NtOsInstall = FindExistingNTOSInstall(List, SectionName, NULL);
+        if (NtOsInstall)
+        {
+            DPRINT1("    An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
+                    NtOsInstall->InstallationName, &NtOsInstall->SystemArcPath);
+            continue;
+        }
 
         /*
          * Convert the ARC path into an NT path, from which we will deduce
@@ -384,18 +409,26 @@ NtLdrEnumerateInstallations(
         RtlInitEmptyUnicodeString(&SystemRootPath, SystemRoot, sizeof(SystemRoot));
         if (!ArcPathToNtPath(&SystemRootPath, SectionName, PartList))
         {
-            DPRINT1("ArcPathToNtPath(%S) failed, installation skipped.\n", SectionName);
-            // FIXME: Do not continue!
+            DPRINT1("ArcPathToNtPath(%S) failed, skip the installation.\n", SectionName);
             continue;
         }
 
-        DPRINT1("ArcPathToNtPath() succeeded: %S --> %wZ\n", SectionName, &SystemRootPath);
+        DPRINT1("ArcPathToNtPath() succeeded: '%S' --> '%wZ'\n", SectionName, &SystemRootPath);
 
-        // TODO 3: Check whether we already have an installation with this NT path.
-        //         If that's the case, stop there. If not, continue...
+        /*
+         * Check whether we already have an installation with this NT path.
+         * If this is the case, stop there.
+         */
+        NtOsInstall = FindExistingNTOSInstall(List, NULL /*SectionName*/, &SystemRootPath);
+        if (NtOsInstall)
+        {
+            DPRINT1("    An NTOS installation with name \"%S\" already exists in SystemRoot '%wZ'\n",
+                    NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
+            continue;
+        }
 
         /* Set SystemRootPath */
-        DPRINT1("NtLdrEnumerateInstallations: SystemRootPath: %wZ\n", &SystemRootPath);
+        DPRINT1("NtLdrEnumerateInstallations: SystemRootPath: '%wZ'\n", &SystemRootPath);
 
         /* Open SystemRootPath */
         InitializeObjectAttributes(&ObjectAttributes,
@@ -411,18 +444,18 @@ NtLdrEnumerateInstallations(
                             FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
         if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Failed to open SystemRoot %wZ, Status 0x%08lx\n", &SystemRootPath, Status);
+            DPRINT1("Failed to open SystemRoot '%wZ', Status 0x%08lx\n", &SystemRootPath, Status);
             continue;
         }
 
         if (IsValidNTOSInstallation(SystemRootDirectory, NULL))
         {
-            ULONG DiskNumber, PartitionNumber;
-            PCWSTR PathComponent;
+            ULONG DiskNumber = 0, PartitionNumber = 0;
+            PCWSTR PathComponent = NULL;
             PDISKENTRY DiskEntry = NULL;
             PPARTENTRY PartEntry = NULL;
 
-            DPRINT1("Found a valid NTOS installation in SystemRoot ARC path %S, NT path %wZ\n", SectionName, &SystemRootPath);
+            DPRINT1("Found a valid NTOS installation in SystemRoot ARC path '%S', NT path '%wZ'\n", SectionName, &SystemRootPath);
 
             /* From the NT path, compute the disk, partition and path components */
             if (NtPathToDiskPartComponents(SystemRootPath.Buffer, &DiskNumber, &PartitionNumber, &PathComponent))
@@ -442,20 +475,21 @@ NtLdrEnumerateInstallations(
             if (PartEntry && PartEntry->DriveLetter)
             {
                 /* We have retrieved a partition that is mounted */
-                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%C:%s  \"%s\"",
-                                 PartEntry->DriveLetter, PathComponent, InstallName);
+                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%C:%s  \"%wZ\"",
+                                 PartEntry->DriveLetter, PathComponent, &InstallName);
             }
             else
             {
                 /* We failed somewhere, just show the NT path */
-                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ  \"%s\"",
-                                 &SystemRootPath, InstallName);
+                StringCchPrintfW(InstallNameW, ARRAYSIZE(InstallNameW), L"%wZ  \"%wZ\"",
+                                 &SystemRootPath, &InstallName);
             }
-            AddNTOSInstallation(List, 0, 0 /*DiskNumber, PartitionNumber*/, SectionName, InstallNameW);
+            AddNTOSInstallation(List, SectionName, &SystemRootPath, PathComponent,
+                                DiskNumber, PartitionNumber, PartEntry,
+                                InstallNameW);
         }
 
         NtClose(SystemRootDirectory);
-        }
     }
     while (IniCacheFindNextValue(Iterator, &SectionName, &KeyData));
 
@@ -471,18 +505,18 @@ Quit:
  *    Searches for a sub-string 'strSearch' inside 'str', similarly to what
  *    wcsstr(str, strSearch) does, but ignores the case during the comparisons.
  */
-PWSTR FindSubStrI(PCWSTR str, PCWSTR strSearch)
+PCWSTR FindSubStrI(PCWSTR str, PCWSTR strSearch)
 {
-    PWSTR cp = (PWSTR)str;
-    PWSTR s1, s2;
+    PCWSTR cp = str;
+    PCWSTR s1, s2;
 
     if (!*strSearch)
-        return (PWSTR)str;
+        return str;
 
     while (*cp)
     {
         s1 = cp;
-        s2 = (PWSTR)strSearch;
+        s2 = strSearch;
 
         while (*s1 && *s2 && (towupper(*s1) == towupper(*s2)))
             ++s1, ++s2;
@@ -523,14 +557,14 @@ CheckForValidPEAndVendor(
                             &FileHandle, &SectionHandle, &ViewBase, NULL);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open and map file %S, Status 0x%08lx\n", FileName, Status);
+        DPRINT1("Failed to open and map file '%S', Status 0x%08lx\n", FileName, Status);
         return FALSE; // Status;
     }
 
     /* Make sure it's a valid PE file */
     if (!RtlImageNtHeader(ViewBase))
     {
-        DPRINT1("File %S does not seem to be a valid PE, bail out\n", FileName);
+        DPRINT1("File '%S' does not seem to be a valid PE, bail out\n", FileName);
         Status = STATUS_INVALID_IMAGE_FORMAT;
         goto UnmapFile;
     }
@@ -542,7 +576,7 @@ CheckForValidPEAndVendor(
     Status = NtGetVersionResource((PVOID)((ULONG_PTR)ViewBase | 1), &VersionBuffer, NULL);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to get version resource for file %S, Status 0x%08lx\n", FileName, Status);
+        DPRINT1("Failed to get version resource for file '%S', Status 0x%08lx\n", FileName, Status);
         goto UnmapFile;
     }
 
@@ -568,7 +602,7 @@ CheckForValidPEAndVendor(
         if (NT_SUCCESS(Status) /*&& pvData*/)
         {
             /* BufLen includes the NULL terminator count */
-            DPRINT1("Found version vendor: \"%S\" for file %S\n", pvData, FileName);
+            DPRINT1("Found version vendor: \"%S\" for file '%S'\n", pvData, FileName);
 
             StringCbCopyNW(VendorName->Buffer, VendorName->MaximumLength,
                            pvData, BufLen * sizeof(WCHAR));
@@ -579,7 +613,7 @@ CheckForValidPEAndVendor(
     }
 
     if (!NT_SUCCESS(Status))
-        DPRINT1("No version vendor found for file %S\n", FileName);
+        DPRINT1("No version vendor found for file '%S'\n", FileName);
 
 UnmapFile:
     /* Finally, unmap and close the file */
@@ -602,8 +636,8 @@ IsValidNTOSInstallation(
 {
     BOOLEAN Success = FALSE;
     USHORT i;
-    WCHAR PathBuffer[MAX_PATH];
     UNICODE_STRING VendorName;
+    WCHAR PathBuffer[MAX_PATH];
 
     /*
      * Use either the 'SystemRootDirectory' handle or the 'SystemRoot' string,
@@ -623,7 +657,7 @@ IsValidNTOSInstallation(
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), L"%s%s", SystemRoot ? SystemRoot : L"", L"System32\\");
     if (!DoesPathExist(SystemRootDirectory, PathBuffer))
     {
-        // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
+        // DPRINT1("Failed to open directory '%wZ', Status 0x%08lx\n", &FileName, Status);
         return FALSE;
     }
 
@@ -631,7 +665,7 @@ IsValidNTOSInstallation(
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), L"%s%s", SystemRoot ? SystemRoot : L"", L"System32\\drivers\\");
     if (!DoesPathExist(SystemRootDirectory, PathBuffer))
     {
-        // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
+        // DPRINT1("Failed to open directory '%wZ', Status 0x%08lx\n", &FileName, Status);
         return FALSE;
     }
 
@@ -639,7 +673,7 @@ IsValidNTOSInstallation(
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), L"%s%s", SystemRoot ? SystemRoot : L"", L"System32\\config\\");
     if (!DoesPathExist(SystemRootDirectory, PathBuffer))
     {
-        // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
+        // DPRINT1("Failed to open directory '%wZ', Status 0x%08lx\n", &FileName, Status);
         return FALSE;
     }
 
@@ -650,12 +684,12 @@ IsValidNTOSInstallation(
      */
     if (!DoesFileExist(SystemRootDirectory, SystemRoot, L"System32\\config\\SYSTEM"))
     {
-        // DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &FileName, Status);
+        // DPRINT1("Failed to open file '%wZ', Status 0x%08lx\n", &FileName, Status);
         return FALSE;
     }
     if (!DoesFileExist(SystemRootDirectory, SystemRoot, L"System32\\config\\SOFTWARE"))
     {
-        // DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &FileName, Status);
+        // DPRINT1("Failed to open file '%wZ', Status 0x%08lx\n", &FileName, Status);
         return FALSE;
     }
 #endif
@@ -723,9 +757,9 @@ DumpNTOSInstalls(
         NtOsInstall = (PNTOS_INSTALLATION)GetListEntryUserData(Entry);
         Entry = GetNextListEntry(Entry);
 
-        DPRINT1("    On disk #%d, partition #%d: Installation \"%S\" in SystemRoot %S\n",
+        DPRINT1("    On disk #%d, partition #%d: Installation \"%S\" in SystemRoot '%wZ'\n",
                 NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber,
-                NtOsInstall->InstallationName, NtOsInstall->SystemRoot);
+                NtOsInstall->InstallationName, &NtOsInstall->SystemNtPath);
     }
 
     DPRINT1("Done.\n");
@@ -734,12 +768,22 @@ DumpNTOSInstalls(
 static PNTOS_INSTALLATION
 FindExistingNTOSInstall(
     IN PGENERIC_LIST List,
-    IN ULONG DiskNumber,
-    IN ULONG PartitionNumber,
-    IN PCWSTR SystemRoot)
+    IN PCWSTR SystemRootArcPath OPTIONAL,
+    IN PUNICODE_STRING SystemRootNtPath OPTIONAL // or PCWSTR ?
+    )
 {
     PGENERIC_LIST_ENTRY Entry;
     PNTOS_INSTALLATION NtOsInstall;
+    UNICODE_STRING SystemArcPath;
+
+    /*
+     * We search either via ARC path or NT path.
+     * If both pointers are NULL then we fail straight away.
+     */
+    if (!SystemRootArcPath && !SystemRootNtPath)
+        return NULL;
+
+    RtlInitUnicodeString(&SystemArcPath, SystemRootArcPath);
 
     Entry = GetFirstListEntry(List);
     while (Entry)
@@ -747,9 +791,17 @@ FindExistingNTOSInstall(
         NtOsInstall = (PNTOS_INSTALLATION)GetListEntryUserData(Entry);
         Entry = GetNextListEntry(Entry);
 
-        if (NtOsInstall->DiskNumber == DiskNumber &&
-            NtOsInstall->PartitionNumber == PartitionNumber &&
-            _wcsicmp(NtOsInstall->SystemRoot, SystemRoot) == 0)
+        /*
+         * Note that if both ARC paths are equal, then the corresponding
+         * NT paths must be the same. However, two ARC paths may be different
+         * but resolve into the same NT path.
+         */
+        if ( (SystemRootArcPath &&
+              RtlEqualUnicodeString(&NtOsInstall->SystemArcPath,
+                                    &SystemArcPath, TRUE)) ||
+             (SystemRootNtPath  &&
+              RtlEqualUnicodeString(&NtOsInstall->SystemNtPath,
+                                    SystemRootNtPath, TRUE)) )
         {
             /* Found it! */
             return NtOsInstall;
@@ -762,20 +814,24 @@ FindExistingNTOSInstall(
 static PNTOS_INSTALLATION
 AddNTOSInstallation(
     IN PGENERIC_LIST List,
+    IN PCWSTR SystemRootArcPath,
+    IN PUNICODE_STRING SystemRootNtPath, // or PCWSTR ?
+    IN PCWSTR PathComponent,    // Pointer inside SystemRootNtPath buffer
     IN ULONG DiskNumber,
     IN ULONG PartitionNumber,
-    IN PCWSTR SystemRoot,
+    IN PPARTENTRY PartEntry OPTIONAL,
     IN PCWSTR InstallationName)
 {
     PNTOS_INSTALLATION NtOsInstall;
+    SIZE_T ArcPathLength, NtPathLength;
     CHAR InstallNameA[MAX_PATH];
 
     /* Is there already any installation with these settings? */
-    NtOsInstall = FindExistingNTOSInstall(List, DiskNumber, PartitionNumber, SystemRoot);
+    NtOsInstall = FindExistingNTOSInstall(List, SystemRootArcPath, SystemRootNtPath);
     if (NtOsInstall)
     {
-        DPRINT1("An NTOS installation with name \"%S\" already exists on disk #%d, partition #%d, in SystemRoot %S\n",
-                NtOsInstall->InstallationName, NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber, NtOsInstall->SystemRoot);
+        DPRINT1("An NTOS installation with name \"%S\" already exists on disk #%d, partition #%d, in SystemRoot '%wZ'\n",
+                NtOsInstall->InstallationName, NtOsInstall->DiskNumber, NtOsInstall->PartitionNumber, &NtOsInstall->SystemNtPath);
         //
         // NOTE: We may use its "IsDefault" attribute, and only keep the entries that have IsDefault == TRUE...
         // Setting IsDefault to TRUE would imply searching for the "Default" entry in the loader configuration file.
@@ -783,14 +839,34 @@ AddNTOSInstallation(
         return NtOsInstall;
     }
 
+    ArcPathLength = (wcslen(SystemRootArcPath) + 1) * sizeof(WCHAR);
+    // NtPathLength  = ROUND_UP(SystemRootNtPath->Length + sizeof(UNICODE_NULL), sizeof(WCHAR));
+    NtPathLength  = SystemRootNtPath->Length + sizeof(UNICODE_NULL);
+
     /* None was found, so add a new one */
-    NtOsInstall = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*NtOsInstall));
+    NtOsInstall = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY,
+                                  sizeof(*NtOsInstall) +
+                                  ArcPathLength + NtPathLength);
     if (!NtOsInstall)
         return NULL;
 
     NtOsInstall->DiskNumber = DiskNumber;
     NtOsInstall->PartitionNumber = PartitionNumber;
-    StringCchCopyW(NtOsInstall->SystemRoot, ARRAYSIZE(NtOsInstall->SystemRoot), SystemRoot);
+    NtOsInstall->PartEntry = PartEntry;
+
+    RtlInitEmptyUnicodeString(&NtOsInstall->SystemArcPath,
+                              (PWCHAR)(NtOsInstall + 1),
+                              ArcPathLength);
+    RtlCopyMemory(NtOsInstall->SystemArcPath.Buffer, SystemRootArcPath, ArcPathLength);
+    NtOsInstall->SystemArcPath.Length = ArcPathLength - sizeof(UNICODE_NULL);
+
+    RtlInitEmptyUnicodeString(&NtOsInstall->SystemNtPath,
+                              (PWCHAR)((ULONG_PTR)(NtOsInstall + 1) + ArcPathLength),
+                              NtPathLength);
+    RtlCopyUnicodeString(&NtOsInstall->SystemNtPath, SystemRootNtPath);
+    NtOsInstall->PathComponent = NtOsInstall->SystemNtPath.Buffer +
+                                    (PathComponent - SystemRootNtPath->Buffer);
+
     StringCchCopyW(NtOsInstall->InstallationName, ARRAYSIZE(NtOsInstall->InstallationName), InstallationName);
 
     // Having the GENERIC_LIST storing the display item string plainly sucks...
@@ -807,27 +883,25 @@ FindNTOSInstallations(
     IN PPARTENTRY PartEntry)
 {
     NTSTATUS Status;
-    UINT i;
+    ULONG DiskNumber = PartEntry->DiskEntry->DiskNumber;
+    ULONG PartitionNumber = PartEntry->PartitionNumber;
     HANDLE PartitionHandle, FileHandle;
     OBJECT_ATTRIBUTES ObjectAttributes;
     IO_STATUS_BLOCK IoStatusBlock;
     UNICODE_STRING PartitionRootPath;
+    UINT i;
     HANDLE SectionHandle;
     // SIZE_T ViewSize;
     ULONG FileSize;
     PVOID ViewBase;
     WCHAR PathBuffer[MAX_PATH];
 
-PDISKENTRY DiskEntry = PartEntry->DiskEntry;
-ULONG DiskNumber = DiskEntry->DiskNumber;
-ULONG PartitionNumber = PartEntry->PartitionNumber;
-
     /* Set PartitionRootPath */
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
                      L"\\Device\\Harddisk%lu\\Partition%lu\\",
                      DiskNumber, PartitionNumber);
     RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
-    DPRINT1("FindNTOSInstallations: PartitionRootPath: %wZ\n", &PartitionRootPath);
+    DPRINT1("FindNTOSInstallations: PartitionRootPath: '%wZ'\n", &PartitionRootPath);
 
     /* Open the partition */
     InitializeObjectAttributes(&ObjectAttributes,
@@ -843,7 +917,7 @@ ULONG PartitionNumber = PartEntry->PartitionNumber;
                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
+        DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", &PartitionRootPath, Status);
         return;
     }
 
@@ -854,7 +928,7 @@ ULONG PartitionNumber = PartEntry->PartitionNumber;
         if (!DoesFileExist(PartitionHandle, NULL, NtosBootLoaders[i].LoaderExecutable))
         {
             /* The loader does not exist, continue with another one */
-            DPRINT1("Loader executable %S does not exist, continue with another one...\n", NtosBootLoaders[i].LoaderExecutable);
+            DPRINT1("Loader executable '%S' does not exist, continue with another one...\n", NtosBootLoaders[i].LoaderExecutable);
             continue;
         }
 
@@ -865,7 +939,7 @@ ULONG PartitionNumber = PartEntry->PartitionNumber;
         {
             /* The loader does not exist, continue with another one */
             // FIXME: Consider it might be optional??
-            DPRINT1("Loader configuration file %S does not exist, continue with another one...\n", NtosBootLoaders[i].LoaderConfigurationFile);
+            DPRINT1("Loader configuration file '%S' does not exist, continue with another one...\n", NtosBootLoaders[i].LoaderConfigurationFile);
             continue;
         }
 
index bef666a..5076784 100644 (file)
@@ -9,15 +9,15 @@
 typedef struct _NTOS_INSTALLATION
 {
     LIST_ENTRY ListEntry;
-    ULONG DiskNumber;
-    ULONG PartitionNumber;
-    PPARTENTRY PartEntry;
 // BOOLEAN IsDefault;   // TRUE / FALSE whether this installation is marked as "default" in its corresponding loader configuration file.
 // Vendor???? (Microsoft / ReactOS)
-/**/WCHAR SystemRoot[MAX_PATH];/**/
     UNICODE_STRING SystemArcPath;   // Normalized ARC path
     UNICODE_STRING SystemNtPath;    // Corresponding NT path
-/**/WCHAR InstallationName[MAX_PATH];/**/
+    PCWSTR PathComponent;           // Pointer inside SystemNtPath.Buffer
+    ULONG DiskNumber;
+    ULONG PartitionNumber;
+    PPARTENTRY PartEntry;
+    WCHAR InstallationName[MAX_PATH];
 } NTOS_INSTALLATION, *PNTOS_INSTALLATION;
 
 // EnumerateNTOSInstallations