https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7c3570f9f5362309a6681…
commit 7c3570f9f5362309a668172c913f2ff339e4467e
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Tue Jan 9 03:21:38 2018 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Nov 6 00:04:30 2018 +0100
[REACTOS] Add helpers and modify ConvertNtPathToWin32Path() to make it use a cache of
NT/Win32 path mappings.
This increases performance for each time the SETUPLIB calls (using NT paths)
Win32 SetupAPI functions which of course only accept Win32 paths.
- Handle also the fact that a NT path to convert may start with
\Device\HarddiskX\PartitionY\..., which can be a symlink to
\Device\HarddiskVolumeN\... on some systems. In that case, the
Win32 path mapping should be done slightly differently.
- Add support for network mapped drives.
---
base/setup/reactos/reactos.c | 198 ++++++++++++++++++++++++++++-----
base/setup/reactos/reactos.h | 34 ++++++
base/setup/reactos/spapisup/fileqsup.c | 17 ++-
base/setup/reactos/spapisup/infsupp.c | 3 +-
4 files changed, 220 insertions(+), 32 deletions(-)
diff --git a/base/setup/reactos/reactos.c b/base/setup/reactos/reactos.c
index 626b0ad9f8..230eafa38c 100644
--- a/base/setup/reactos/reactos.c
+++ b/base/setup/reactos/reactos.c
@@ -1192,37 +1192,99 @@ BOOL LoadSetupData(
return ret;
}
+VOID
+InitNtToWin32PathMappingList(
+ IN OUT PNT_WIN32_PATH_MAPPING_LIST MappingList)
+{
+ InitializeListHead(&MappingList->List);
+ MappingList->MappingsCount = 0;
+}
+
+VOID
+FreeNtToWin32PathMappingList(
+ IN OUT PNT_WIN32_PATH_MAPPING_LIST MappingList)
+{
+ PLIST_ENTRY ListEntry;
+ PVOID Entry;
+
+ while (!IsListEmpty(&MappingList->List))
+ {
+ ListEntry = RemoveHeadList(&MappingList->List);
+ Entry = (PVOID)CONTAINING_RECORD(ListEntry, NT_WIN32_PATH_MAPPING, ListEntry);
+ HeapFree(ProcessHeap, 0, Entry);
+ }
+
+ MappingList->MappingsCount = 0;
+}
+
/*
* Attempts to convert a pure NT file path into a corresponding Win32 path.
* Adapted from GetInstallSourceWin32() in dll/win32/syssetup/wizard.c
*/
BOOL
ConvertNtPathToWin32Path(
+ IN OUT PNT_WIN32_PATH_MAPPING_LIST MappingList,
OUT PWSTR pwszPath,
IN DWORD cchPathMax,
IN PCWSTR pwszNTPath)
{
BOOL FoundDrive = FALSE, RetryOnce = FALSE;
+ PLIST_ENTRY ListEntry;
+ PNT_WIN32_PATH_MAPPING Entry;
+ PCWSTR pwszNtPathToMap = pwszNTPath;
+ PCWSTR pwszRemaining = NULL;
DWORD cchDrives;
PWCHAR pwszDrive;
- PCWSTR pwszRemaining = NULL;
WCHAR wszDrives[512];
WCHAR wszNTPath[MAX_PATH];
- WCHAR TargetPath[MAX_PATH] = L"";
+ WCHAR TargetPath[MAX_PATH];
*pwszPath = UNICODE_NULL;
+ /*
+ * We find first a mapping inside the MappingList. If one is found, use it
+ * to build the Win32 path. If there is none, we need to create one by
+ * checking the Win32 drives (and possibly NT symlinks too).
+ * In case of success, add the newly found mapping to the list and use it
+ * to build the Win32 path.
+ */
+
+ for (ListEntry = MappingList->List.Flink;
+ ListEntry != &MappingList->List;
+ ListEntry = ListEntry->Flink)
+ {
+ Entry = CONTAINING_RECORD(ListEntry, NT_WIN32_PATH_MAPPING, ListEntry);
+
+ DPRINT("Testing '%S' --> '%S'\n",
Entry->Win32Path, Entry->NtPath);
+
+ /* Check whether the queried NT path prefixes the user-provided NT path */
+ FoundDrive = !_wcsnicmp(pwszNtPathToMap, Entry->NtPath,
wcslen(Entry->NtPath));
+ if (FoundDrive)
+ {
+ /* Found it! */
+
+ /* Set the pointers and go build the Win32 path */
+ pwszDrive = Entry->Win32Path;
+ pwszRemaining = pwszNTPath + wcslen(Entry->NtPath);
+ goto Quit;
+ }
+ }
+
+ /*
+ * No mapping exists for this path yet: try to find one now.
+ */
+
/* Retrieve the mounted drives (available drive letters) */
cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
{
/* Buffer too small or failure */
- DPRINT1("GetLogicalDriveStringsW failed\n");
+ DPRINT1("ConvertNtPathToWin32Path: GetLogicalDriveStringsW failed\n");
return FALSE;
}
-
-Retry: // We go back there once if RetryOnce == TRUE
+/* We go back there once if RetryOnce == TRUE */
+Retry:
/* Enumerate the mounted drives */
for (pwszDrive = wszDrives; *pwszDrive; pwszDrive += wcslen(pwszDrive) + 1)
@@ -1235,25 +1297,87 @@ Retry: // We go back there once if RetryOnce == TRUE
DPRINT("Testing '%S' --> '%S'\n", pwszDrive,
wszNTPath);
/* Check whether the queried NT path prefixes the user-provided NT path */
- if (!_wcsnicmp(wszNTPath, pwszNTPath, wcslen(wszNTPath)))
+ FoundDrive = !_wcsnicmp(pwszNtPathToMap, wszNTPath, wcslen(wszNTPath));
+ if (!FoundDrive)
+ {
+ PWCHAR ptr, ptr2;
+
+ /*
+ * Check whether this was a network share that has a drive letter,
+ * but the user-provided NT path points to this share without
+ * mentioning the drive letter.
+ *
+ * The format is:
\Device\<network_redirector>\;X:<data>\share\path
+ * The corresponding drive letter is 'X'.
+ * A system-provided network redirector (LanManRedirector or Mup)
+ * or a 3rd-party one may be used.
+ *
+ * We check whether the user-provided NT path has the form:
+ * \Device\<network_redirector>\<data>\share\path
+ * as it obviously did not have the full form (the previous check
+ * would have been OK otherwise).
+ */
+ if (!_wcsnicmp(wszNTPath, L"\\Device\\",
_countof(L"\\Device\\")-1) &&
+ (ptr = wcschr(wszNTPath + _countof(L"\\Device\\")-1,
L'\\')) &&
+ wcslen(++ptr) >= 3 && ptr[0] == L';' && ptr[2]
== L':')
+ {
+ /*
+ * Normally the specified drive letter should correspond
+ * to the one used for the mapping. But we will ignore
+ * if it happens not to be the case.
+ */
+ if (pwszDrive[0] != ptr[1])
+ {
+ DPRINT1("Peculiar: expected network share drive letter %C
different from actual one %C\n",
+ pwszDrive[0], ptr[1]);
+ }
+
+ /* Remove the drive letter from the NT network share path */
+ ptr2 = ptr + 3;
+ /* Swallow as many possible consecutive backslashes as there could be */
+ while (*ptr2 == L'\\') ++ptr2;
+
+ memmove(ptr, ptr2, (wcslen(ptr2) + 1) * sizeof(WCHAR));
+
+ /* Now do the check again */
+ FoundDrive = !_wcsnicmp(pwszNtPathToMap, wszNTPath, wcslen(wszNTPath));
+ }
+ }
+ if (FoundDrive)
{
/* Found it! */
- FoundDrive = TRUE;
- if (!RetryOnce && pwszNTPath != TargetPath)
+
+ pwszDrive[2] = UNICODE_NULL; // Remove the backslash
+
+ if (pwszNtPathToMap == pwszNTPath)
+ {
+ ASSERT(!RetryOnce && pwszNTPath != TargetPath);
pwszRemaining = pwszNTPath + wcslen(wszNTPath);
+ }
break;
}
}
if (FoundDrive)
{
- pwszDrive[2] = UNICODE_NULL; // Remove the backslash
- StringCchPrintfW(pwszPath, cchPathMax,
- L"%s%s",
- pwszDrive,
- pwszRemaining);
- DPRINT1("ConvertNtPathToWin32Path: %S\n", pwszPath);
- return TRUE;
+ /* A mapping was found, add it to the cache */
+ Entry = HeapAlloc(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*Entry));
+ if (!Entry)
+ {
+ DPRINT1("ConvertNtPathToWin32Path: Cannot allocate memory\n");
+ return FALSE;
+ }
+ StringCchCopyNW(Entry->NtPath, _countof(Entry->NtPath),
+ pwszNTPath, pwszRemaining - pwszNTPath);
+ StringCchCopyW(Entry->Win32Path, _countof(Entry->Win32Path), pwszDrive);
+
+ /* Insert it as the most recent entry */
+ InsertHeadList(&MappingList->List, &Entry->ListEntry);
+ MappingList->MappingsCount++;
+
+ /* Set the pointers and go build the Win32 path */
+ pwszDrive = Entry->Win32Path;
+ goto Quit;
}
/*
@@ -1309,10 +1433,12 @@ Retry: // We go back there once if RetryOnce == TRUE
if (!NT_SUCCESS(Status))
{
/* Not a symlink, or something else happened: bail out */
- DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed, Status 0x%08lx\n",
&SymLink, Status);
+ DPRINT1("ConvertNtPathToWin32Path: NtOpenSymbolicLinkObject(%wZ) failed,
Status 0x%08lx\n",
+ &SymLink, Status);
return FALSE;
}
+ *TargetPath = UNICODE_NULL;
RtlInitEmptyUnicodeString(&Target, TargetPath, sizeof(TargetPath));
/* Resolve the link and close its handle */
@@ -1323,25 +1449,41 @@ Retry: // We go back there once if RetryOnce == TRUE
if (!NT_SUCCESS(Status))
{
/* Not a symlink, or something else happened: bail out */
- DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed, Status 0x%08lx\n",
&SymLink, Status);
+ DPRINT1("ConvertNtPathToWin32Path: NtQuerySymbolicLinkObject(%wZ)
failed, Status 0x%08lx\n",
+ &SymLink, Status);
return FALSE;
}
- /* Set pointers */
+ /* Set the pointers */
pwszRemaining = pwszNTPath + Length;
- pwszNTPath = TargetPath;
+ pwszNtPathToMap = TargetPath; // Point to our local buffer
/* Retry once */
RetryOnce = TRUE;
goto Retry;
}
+ ASSERT(!FoundDrive);
+
+Quit:
+ if (FoundDrive)
+ {
+ StringCchPrintfW(pwszPath, cchPathMax,
+ L"%s%s",
+ pwszDrive,
+ pwszRemaining);
+ DPRINT("ConvertNtPathToWin32Path: %S\n", pwszPath);
+ return TRUE;
+ }
+
return FALSE;
}
/* Used to enable and disable the shutdown privilege */
/* static */ BOOL
-EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
+EnablePrivilege(
+ IN LPCWSTR lpszPrivilegeName,
+ IN BOOL bEnablePrivilege)
{
BOOL Success;
HANDLE hToken;
@@ -1382,6 +1524,14 @@ _tWinMain(HINSTANCE hInst,
ProcessHeap = GetProcessHeap();
+ SetupData.hInstance = hInst;
+ SetupData.hInstallThread = NULL;
+ SetupData.hHaltInstallEvent = NULL;
+ SetupData.bStopInstall = FALSE;
+
+ /* Initialize the NT to Win32 path prefix mapping list */
+ InitNtToWin32PathMappingList(&SetupData.MappingList);
+
/* Initialize Setup, phase 0 */
InitializeSetup(&SetupData.USetupData, 0);
@@ -1406,11 +1556,6 @@ _tWinMain(HINSTANCE hInst,
if (!LoadSetupData(&SetupData))
goto Quit;
- SetupData.hInstance = hInst;
- SetupData.hInstallThread = NULL;
- SetupData.hHaltInstallEvent = NULL;
- SetupData.bStopInstall = FALSE;
-
CheckUnattendedSetup(&SetupData.USetupData);
SetupData.bUnattend = IsUnattendedSetup; // FIXME :-)
@@ -1544,6 +1689,9 @@ Quit:
/* Setup has finished */
FinishSetup(&SetupData.USetupData);
+ /* Free the NT to Win32 path prefix mapping list */
+ FreeNtToWin32PathMappingList(&SetupData.MappingList);
+
#if 0 // NOTE: Disabled for testing purposes only!
EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
ExitWindowsEx(EWX_REBOOT, 0);
diff --git a/base/setup/reactos/reactos.h b/base/setup/reactos/reactos.h
index 0c4a76eb40..ded1d85f74 100644
--- a/base/setup/reactos/reactos.h
+++ b/base/setup/reactos/reactos.h
@@ -66,6 +66,35 @@ typedef struct _KBLAYOUT
#endif
+/*
+ * A mapping entry that maps an NT path to a corresponding Win32 path.
+ *
+ * Example is:
+ * NT path: "\Device\Harddisk0\Partition1\some\path1"
+ * Win32 path: "C:\some\path1"
+ *
+ * Here, the NT path prefix to be cached is only
+ * "\Device\Harddisk0\Partition1\", to be mapped with "C:\".
+ *
+ * Then the same entry would be reused if one wants to convert
+ * the NT path "\Device\Harddisk0\Partition1\another\path2",
+ * which converts to the Win32 path "C:\another\path2" .
+ */
+typedef struct _NT_WIN32_PATH_MAPPING
+{
+ LIST_ENTRY ListEntry;
+ WCHAR NtPath[MAX_PATH]; // MAX_PATH for both entries should be more than enough.
+ WCHAR Win32Path[MAX_PATH];
+} NT_WIN32_PATH_MAPPING, *PNT_WIN32_PATH_MAPPING;
+
+/* The list of NT to Win32 path prefix mappings */
+typedef struct _NT_WIN32_PATH_MAPPING_LIST
+{
+ LIST_ENTRY List;
+ ULONG MappingsCount;
+} NT_WIN32_PATH_MAPPING_LIST, *PNT_WIN32_PATH_MAPPING_LIST;
+
+
typedef struct _SETUPDATA
{
/* General */
@@ -81,6 +110,8 @@ typedef struct _SETUPDATA
TCHAR szAbortMessage[512];
TCHAR szAbortTitle[64];
+ NT_WIN32_PATH_MAPPING_LIST MappingList;
+
USETUP_DATA USetupData;
BOOLEAN RepairUpdateFlag; // flag for update/repair an installed reactos
@@ -113,6 +144,8 @@ typedef struct _SETUPDATA
extern HANDLE ProcessHeap;
extern BOOLEAN IsUnattendedSetup;
+extern SETUPDATA SetupData;
+
typedef struct _IMGINFO
{
@@ -128,6 +161,7 @@ typedef struct _IMGINFO
*/
BOOL
ConvertNtPathToWin32Path(
+ IN OUT PNT_WIN32_PATH_MAPPING_LIST MappingList,
OUT PWSTR pwszPath,
IN DWORD cchPathMax,
IN PCWSTR pwszNTPath);
diff --git a/base/setup/reactos/spapisup/fileqsup.c
b/base/setup/reactos/spapisup/fileqsup.c
index 9c15f8cdac..ea46c03f75 100644
--- a/base/setup/reactos/spapisup/fileqsup.c
+++ b/base/setup/reactos/spapisup/fileqsup.c
@@ -38,7 +38,8 @@ SpFileQueueCopy_NtToWin32(
* the Win32 SetupQueueCopyW API only takes Win32 paths. We therefore
* map the NT path to Win32 path and then call the Win32 API.
*/
- if (!ConvertNtPathToWin32Path(Win32SourceRootPath,
+ if (!ConvertNtPathToWin32Path(&SetupData.MappingList,
+ Win32SourceRootPath,
_countof(Win32SourceRootPath),
SourceRootPath))
{
@@ -46,7 +47,8 @@ SpFileQueueCopy_NtToWin32(
}
/* SourcePath, SourceFileName and SourceCabinet are appended to SourceRootPath by the
SetupApi function */
- if (!ConvertNtPathToWin32Path(Win32TargetDirectory,
+ if (!ConvertNtPathToWin32Path(&SetupData.MappingList,
+ Win32TargetDirectory,
_countof(Win32TargetDirectory),
TargetDirectory))
{
@@ -64,7 +66,7 @@ SpFileQueueCopy_NtToWin32(
SourcePath,
SourceFileName,
// Undocumented on MSDN is the fact that this parameter is mandatory *IF* one wants
to take the TagFile into account!
- L"foobar",
+ L"ReactOS",
// SourceTagFile -- Special behaviour: use cabinet file present in ArchiveDir path!
The API does not check for a ".cab" extension.
SourceCabinet,
Win32TargetDirectory,
@@ -88,7 +90,8 @@ SpFileQueueDelete_NtToWin32(
* the Win32 SetupQueueDeleteW API only takes Win32 paths. We therefore
* map the NT path to Win32 path and then call the Win32 API.
*/
- if (!ConvertNtPathToWin32Path(Win32PathPart1,
+ if (!ConvertNtPathToWin32Path(&SetupData.MappingList,
+ Win32PathPart1,
_countof(Win32PathPart1),
PathPart1))
{
@@ -116,7 +119,8 @@ SpFileQueueRename_NtToWin32(
* the Win32 SetupQueueRenameW API only takes Win32 paths. We therefore
* map the NT path to Win32 path and then call the Win32 API.
*/
- if (!ConvertNtPathToWin32Path(Win32SourcePath,
+ if (!ConvertNtPathToWin32Path(&SetupData.MappingList,
+ Win32SourcePath,
_countof(Win32SourcePath),
SourcePath))
{
@@ -126,7 +130,8 @@ SpFileQueueRename_NtToWin32(
if (TargetPath)
{
- if (!ConvertNtPathToWin32Path(Win32TargetPath,
+ if (!ConvertNtPathToWin32Path(&SetupData.MappingList,
+ Win32TargetPath,
_countof(Win32TargetPath),
TargetPath))
{
diff --git a/base/setup/reactos/spapisup/infsupp.c
b/base/setup/reactos/spapisup/infsupp.c
index 7c40e8421e..98e48b07bb 100644
--- a/base/setup/reactos/spapisup/infsupp.c
+++ b/base/setup/reactos/spapisup/infsupp.c
@@ -48,7 +48,8 @@ SetupOpenInfFileExW(
* the Win32 SetupOpenInfFileW API only takes Win32 paths. We therefore
* map the NT path to Win32 path and then call the Win32 API.
*/
- if (!ConvertNtPathToWin32Path(Win32FileName,
+ if (!ConvertNtPathToWin32Path(&SetupData.MappingList,
+ Win32FileName,
_countof(Win32FileName),
FileName))
{