https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1a1a8a8303e941586dd2c…
commit 1a1a8a8303e941586dd2c37d943245ffcdfe6f28
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Fri Nov 4 21:44:46 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Fri Nov 4 21:44:46 2022 +0900
[SHELL32][INCLUDE] Fix PathResolve for double-backslash (#4833)
Co-authored-by: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
Fix shell32!PathResolve and shell32!PathQualifyExW functions for double-backslash.
However it doesn't fix CORE-15204.
CORE-18080, CORE-15204
---
dll/win32/shell32/wine/shellpath.c | 328 ++++++++++++++++++++++--------------
sdk/include/reactos/shlwapi_undoc.h | 1 +
2 files changed, 205 insertions(+), 124 deletions(-)
diff --git a/dll/win32/shell32/wine/shellpath.c b/dll/win32/shell32/wine/shellpath.c
index 70409260e69..b39f7da7c49 100644
--- a/dll/win32/shell32/wine/shellpath.c
+++ b/dll/win32/shell32/wine/shellpath.c
@@ -3,7 +3,7 @@
*
* Copyright 1998, 1999, 2000 Juergen Schmied
* Copyright 2004 Juan Lang
- * Copyright 2018-2021 Katayama Hirofumi MZ
+ * Copyright 2018-2022 Katayama Hirofumi MZ
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -57,8 +57,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
static const BOOL is_win64 = sizeof(void *) > sizeof(int);
-#ifdef __REACTOS__
-
/* FIXME: Remove this */
typedef enum _NT_PRODUCT_TYPE
{
@@ -105,15 +103,16 @@ DoGetProductType(PNT_PRODUCT_TYPE ProductType)
return TRUE;
}
-#endif // __REACTOS__
-
/*
########## Combining and Constructing paths ##########
*/
-/* @implemented */
static BOOL WINAPI
-PathSearchOnExtensionsW(LPWSTR pszPath, LPCWSTR *ppszDirs, BOOL bDoSearch, DWORD
dwWhich)
+PathSearchOnExtensionsW(
+ _Inout_ LPWSTR pszPath,
+ _In_opt_ LPCWSTR *ppszDirs,
+ _In_ BOOL bDoSearch,
+ _In_ DWORD dwWhich)
{
if (*PathFindExtensionW(pszPath) != 0)
return FALSE;
@@ -124,15 +123,13 @@ PathSearchOnExtensionsW(LPWSTR pszPath, LPCWSTR *ppszDirs, BOOL
bDoSearch, DWORD
return PathFileExistsDefExtW(pszPath, dwWhich);
}
-#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
-/* @implemented */
-static BOOL WINAPI PathIsAbsoluteW(LPCWSTR path)
+#if (_WIN32_WINNT >= _WIN32_WINNT_WS03)
+static BOOL WINAPI PathIsAbsoluteW(_In_ LPCWSTR path)
{
return PathIsUNCW(path) || (PathGetDriveNumberW(path) != -1 && path[2] ==
L'\\');
}
-/* @implemented */
-static BOOL WINAPI PathMakeAbsoluteW(LPWSTR path)
+static BOOL WINAPI PathMakeAbsoluteW(_Inout_ LPWSTR path)
{
WCHAR path1[MAX_PATH];
DWORD cch;
@@ -146,90 +143,176 @@ static BOOL WINAPI PathMakeAbsoluteW(LPWSTR path)
}
#endif
-/* NOTE: GetShortPathName fails if the pathname didn't exist.
- GetShortPathNameAbsentW should set the short path name that even doesn't
exist. */
-static DWORD GetShortPathNameAbsentW(LPCWSTR pszLong, LPWSTR pszShort, DWORD cchShort)
-{
- FIXME("GetShortPathNameAbsentW(%ls, %p, %ld): stub\n", pszLong, pszShort,
cchShort);
- StringCchCopyW(pszShort, cchShort, pszLong);
- return lstrlenW(pszShort);
-}
-
BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath);
-/* @unconfirmed */
-static VOID WINAPI PathQualifyExW(LPWSTR pszPath, LPCWSTR pszDir, DWORD dwFlags)
+static VOID WINAPI
+PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir, _In_ DWORD dwFlags)
{
- WCHAR szRoot[MAX_PATH], szCopy[MAX_PATH], szCurDir[MAX_PATH];
- LPWSTR pch;
- LONG cch;
- BOOL bCheckLFN;
+ INT iDrive, cchPathLeft;
+ WCHAR szTemp[MAX_PATH], szRoot[MAX_PATH];
+ PWCHAR pchTemp = szTemp, pchPath;
+ BOOL bLFN = TRUE;
- if (FAILED(StringCchCopyW(szCopy, _countof(szCopy), pszPath)))
- return;
+ TRACE("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszDir),
dwFlags);
- FixSlashesAndColonW(szCopy);
+ /* Save pszPath path into szTemp for rebuilding the path later */
+ if (FAILED(StringCchCopyW(szTemp, _countof(szTemp), pszPath)))
+ return;
- if (pszDir)
- {
- cch = GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
- if (cch <= 0 || cch >= _countof(szCurDir) ||
!SetCurrentDirectoryW(pszDir))
- pszDir = NULL;
- }
+ /* Replace every '/' by '\' */
+ FixSlashesAndColonW(szTemp);
- if (!GetFullPathNameW(szCopy, _countof(szRoot), szRoot, NULL))
- goto Quit;
+ cchPathLeft = MAX_PATH;
- if (PathIsUNCW(szRoot)) /* it begins with double backslash */
+ /* Build the root-like path on pszPath, and set pchTemp */
+ if (!PathIsUNCW(szTemp))
{
- pch = StrChrW(&szRoot[2], L'\\');
- if (pch)
+ /*
+ * Non-UNC path.
+ * Determine and normalize the root drive.
+ */
+ iDrive = PathGetDriveNumberW(szTemp);
+ if (iDrive == -1)
{
- pch = StrChrW(&pch[1], L'\\');
- if (pch)
- *pch = 0;
- if (!PathAddBackslashW(szRoot))
- goto Quit;
- /* szRoot is like \\MyServer\MyShare\ */
- bCheckLFN = TRUE;
+ /*
+ * No drive was specified in the path. Try to find one from the
+ * optional directory (if this fails, fall back to the one of the
+ * Windows directory).
+ */
+ if (!pszDir || FAILED(StringCchCopyW(szRoot, _countof(szRoot), pszDir)))
+ {
+ /* pszDir was invalid or NULL. Fall back to the
+ * Windows directory and find its root. */
+ szRoot[0] = UNICODE_NULL;
+ GetWindowsDirectoryW(szRoot, _countof(szRoot));
+ iDrive = PathGetDriveNumberW(szRoot);
+ if (iDrive != -1)
+ PathBuildRootW(szRoot, iDrive);
+ }
+
+ if (szTemp[0] == L'\\')
+ {
+ PathStripToRootW(szRoot);
+ }
}
else
{
- bCheckLFN = FALSE;
+ /*
+ * A drive is specified in the path, that can be either of the
+ * form 'C:\xxx' or of the form 'C:xxx' (relative path).
Isolate
+ * the root part 'C:' and the rest of the path 'xxx' in
pchTemp.
+ */
+ PathBuildRootW(szRoot, iDrive);
+ pchTemp += 2;
+ if (*pchTemp == L'\\')
+ ++pchTemp;
}
+
+#if 0 // FIXME: IsLFNDriveW has a bug
+ bLFN = IsLFNDriveW(szRoot);
+#endif
+ if (!bLFN)
+ {
+ /* FIXME: Support non-LFN */
+ }
+
+ StringCchCopyW(pszPath, MAX_PATH, szRoot);
+ cchPathLeft -= lstrlenW(pszPath) + 1;
}
- else
+ else /* UNC path: Begins with double backslash */
{
- if (!PathStripToRootW(szRoot) || !PathAddBackslashW(szRoot))
- goto Quit;
- /* szRoot is like X:\ */
- bCheckLFN = TRUE;
+#if 0 // FIXME: IsLFNDriveW has a bug
+ bLFN = IsLFNDriveW(pchTemp);
+#endif
+ if (!bLFN)
+ {
+ /* FIXME: Support non-LFN */
+ }
+ pszPath[2] = UNICODE_NULL; /* Cut off */
+ cchPathLeft -= (2 + 1);
+ pchTemp += 2;
}
+ /* Now pszPath is a root-like path or an empty string. */
- if (bCheckLFN && !IsLFNDriveW(szRoot)) /* not a long filename drive */
+ /* Start appending the path components of szTemp to pszPath. */
+ while (*pchTemp && cchPathLeft > 0)
{
- if (!GetFullPathNameW(szCopy, _countof(szRoot), szRoot, NULL))
- goto Quit;
- if (!GetShortPathNameW(szRoot, szCopy, _countof(szCopy)) &&
- !GetShortPathNameAbsentW(szRoot, szCopy, _countof(szCopy)))
+ /* Collapse any .\ and ..\ parts in the path */
+ if (*pchTemp == L'.')
+ {
+ BOOL bDots = FALSE; /* '.' or '..' ? */
+
+ if (pchTemp[1] == UNICODE_NULL || pchTemp[1] == L'\\')
+ {
+ /* Component '.' */
+ bDots = TRUE;
+ }
+ else if (pchTemp[1] == L'.' && (pchTemp[2] == UNICODE_NULL ||
pchTemp[2] == L'\\'))
+ {
+ /* Component '..' */
+ PathRemoveFileSpecW(pszPath); /* Remove the last component from pszPath
*/
+ bDots = TRUE;
+ }
+
+ /* If a '.' or '..' was encountered, skip to the next
component */
+ if (bDots)
+ {
+ while (*pchTemp && *pchTemp != L'\\')
+ {
+ ++pchTemp;
+ }
+
+ while (*pchTemp == L'\\')
+ {
+ ++pchTemp;
+ }
+
+ continue;
+ }
+ }
+
+ /* Otherwise, copy the other path component */
+
+ if (!PathAddBackslashW(pszPath)) /* Append a backslash at the end */
+ break;
+
+ --cchPathLeft;
+
+ pchPath = &pszPath[lstrlenW(pszPath)];
+
+ if (!bLFN)
{
- goto Quit;
+ /* FIXME: Support non-LFN */
}
+ else
+ {
+ /* Copy the component up to the next separator */
+ while (*pchTemp != UNICODE_NULL && *pchTemp != L'\\'
&& cchPathLeft > 0)
+ {
+ *pchPath++ = *pchTemp++;
+ --cchPathLeft;
+ }
+ }
+
+ /* Skip the backslashes */
+ while (*pchTemp == L'\\')
+ {
+ ++pchTemp;
+ }
+
+ /* Keep null-terminated */
+ *pchPath = UNICODE_NULL;
}
- PathRemoveBackslashW(szCopy);
- StringCchCopyW(pszPath, MAX_PATH, szCopy);
+ /* Remove any trailing backslash */
+ PathRemoveBackslashW(pszPath);
- if ((dwFlags & 1) == 0)
+ if (!(dwFlags & 1)) /* Remove the trailing dot? */
{
- cch = lstrlenW(pszPath);
- if (cch > 0 && pszPath[cch - 1] == L'.')
- pszPath[cch - 1] = 0;
+ pchPath = CharPrevW(pszPath, pszPath + lstrlenW(pszPath));
+ if (*pchPath == L'.')
+ *pchPath = UNICODE_NULL;
}
-
-Quit:
- if (pszDir)
- SetCurrentDirectoryW(szCurDir);
}
/*************************************************************************
@@ -634,7 +717,7 @@ BOOL WINAPI PathResolveA(LPSTR path, LPCSTR *dirs, DWORD flags)
DWORD iDir, cDirs, cbDirs;
WCHAR pathW[MAX_PATH];
- TRACE("PathResolveA(%s,%p,0x%08x)\n", debugstr_a(path), dirs, flags);
+ TRACE("(%s,%p,0x%08x)\n", debugstr_a(path), dirs, flags);
if (dirs)
{
@@ -673,81 +756,78 @@ Cleanup:
return ret;
}
-BOOL WINAPI PathResolveW(LPWSTR path, LPCWSTR *dirs, DWORD flags)
+BOOL WINAPI PathResolveW(_Inout_ LPWSTR path, _Inout_opt_ LPCWSTR *dirs, _In_ DWORD
flags)
{
- DWORD dwWhich = ((flags & PRF_DONTFINDLNK) ? (WHICH_DEFAULT & ~WHICH_LNK) :
WHICH_DEFAULT);
+ DWORD dwWhich = WHICH_DEFAULT; /* The extensions to be searched */
+
+ TRACE("(%s,%p,0x%08x)\n", debugstr_w(path), dirs, flags);
- TRACE("PathResolveW(%s,%p,0x%08x)\n", debugstr_w(path), dirs, flags);
+ if (flags & PRF_DONTFINDLNK)
+ dwWhich &= ~WHICH_LNK; /* Don't search '.LNK' (shortcut) */
if (flags & PRF_VERIFYEXISTS)
- SetLastError(ERROR_FILE_NOT_FOUND);
+ SetLastError(ERROR_FILE_NOT_FOUND); /* We set this error code at first in
verification */
PathUnquoteSpacesW(path);
- if (PathIsRootW(path))
+ if (PathIsRootW(path)) /* Root path */
{
- if ((path[0] == L'\\' && path[1] == 0) ||
- PathIsUNCServerW(path) || PathIsUNCServerShareW(path))
- {
- if (flags & PRF_FIRSTDIRDEF)
- PathQualifyExW(path, dirs[0], 0);
- else
- PathQualifyExW(path, NULL, 0);
- }
+ if (path[0] == L'\\' && path[1] == UNICODE_NULL) /* '\'
only? */
+ PathQualifyExW(path, ((flags & PRF_FIRSTDIRDEF) ? *dirs : NULL), 0); /*
Qualify */
if (flags & PRF_VERIFYEXISTS)
- return PathFileExistsAndAttributesW(path, NULL);
+ return PathFileExistsAndAttributesW(path, NULL); /* Check the existence */
+
return TRUE;
}
- else if (PathIsFileSpecW(path))
+
+ if (PathIsFileSpecW(path)) /* Filename only */
{
- if ((flags & PRF_TRYPROGRAMEXTENSIONS) &&
PathSearchOnExtensionsW(path, dirs, TRUE, dwWhich))
- return TRUE;
+ /* Try to find the path with program extensions applied? */
+ if ((flags & PRF_TRYPROGRAMEXTENSIONS) &&
+ PathSearchOnExtensionsW(path, dirs, TRUE, dwWhich))
+ {
+ return TRUE; /* Found */
+ }
+ /* Try to find the filename in the directories */
if (PathFindOnPathW(path, dirs))
- {
-#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
- if (!(flags & PRF_REQUIREABSOLUTE))
- return TRUE;
+ goto CheckAbsoluteAndFinish;
- if (!PathIsAbsoluteW(path))
- return PathMakeAbsoluteW(path) &&
PathFileExistsAndAttributesW(path, NULL);
-#else
- return TRUE;
-#endif
- }
+ return FALSE; /* Not found */
}
- else if (!PathIsURLW(path))
- {
- if (flags & PRF_FIRSTDIRDEF)
- PathQualifyExW(path, *dirs, 1);
- else
- PathQualifyExW(path, NULL, 1);
- if (flags & PRF_VERIFYEXISTS)
- {
- if ((flags & PRF_TRYPROGRAMEXTENSIONS) &&
- PathSearchOnExtensionsW(path, dirs, FALSE, dwWhich))
- {
- return TRUE;
- }
- else if (!PathFileExistsAndAttributesW(path, NULL))
- {
- return FALSE;
- }
- }
+ if (PathIsURLW(path)) /* URL? */
+ return FALSE;
-#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
- if (flags & PRF_REQUIREABSOLUTE)
- {
- if (!PathIsAbsoluteW(path))
- return PathMakeAbsoluteW(path) &&
PathFileExistsAndAttributesW(path, NULL);
- }
-#endif
+ /* Qualify the path */
+ PathQualifyExW(path, ((flags & PRF_FIRSTDIRDEF) ? *dirs : NULL), 1);
+
+ TRACE("(%s)\n", debugstr_w(path));
+
+ if (!(flags & PRF_VERIFYEXISTS)) /* Don't verify the existence? */
return TRUE;
+
+ /* Try to find the path with program extensions applied? */
+ if (!(flags & PRF_TRYPROGRAMEXTENSIONS) ||
+ !PathSearchOnExtensionsW(path, dirs, FALSE, dwWhich))
+ {
+ if (!PathFileExistsAndAttributesW(path, NULL))
+ return FALSE; /* Not found */
}
- return FALSE;
+CheckAbsoluteAndFinish:
+#if (_WIN32_WINNT >= _WIN32_WINNT_WS03)
+ if (!(flags & PRF_REQUIREABSOLUTE) || PathIsAbsoluteW(path))
+ return TRUE;
+
+ if (!PathMakeAbsoluteW(path))
+ return FALSE;
+
+ return PathFileExistsAndAttributesW(path, NULL);
+#else
+ return TRUE; /* Found */
+#endif
}
/*************************************************************************
diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h
index d62b4ec65c4..631dd68b757 100644
--- a/sdk/include/reactos/shlwapi_undoc.h
+++ b/sdk/include/reactos/shlwapi_undoc.h
@@ -168,6 +168,7 @@ ShellMessageBoxWrapW(
BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath, DWORD dwWhich);
BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich);
VOID WINAPI FixSlashesAndColonW(LPWSTR);
+BOOL WINAPI PathIsValidCharW(WCHAR c, DWORD dwClass);
#ifdef __cplusplus
} /* extern "C" */