mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 12:14:32 +00:00
[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.
This commit is contained in:
parent
dd2fe4e126
commit
7c3570f9f5
4 changed files with 220 additions and 32 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue