https://git.reactos.org/?p=reactos.git;a=commitdiff;h=11a71418d50f48ff0e10d…
commit 11a71418d50f48ff0e10d2dbbe243afaf34c4368
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Thu Nov 10 23:18:04 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Thu Nov 10 23:18:04 2022 +0900
[SHELL32] Implement IsLFNDriveA/W and improve PathResolve (#4866)
- Fix IsLFNDriveA and IsLFNDriveW functions.
- Add IsRemovableDrive helper function.
- Fix PathQualifyExW by using IsLFNDriveW.
CORE-11335
---
dll/win32/shell32/wine/shellpath.c | 176 ++++++++++++++++++++++++++++++++-----
1 file changed, 153 insertions(+), 23 deletions(-)
diff --git a/dll/win32/shell32/wine/shellpath.c b/dll/win32/shell32/wine/shellpath.c
index b39f7da7c49..604d98020d0 100644
--- a/dll/win32/shell32/wine/shellpath.c
+++ b/dll/win32/shell32/wine/shellpath.c
@@ -40,6 +40,7 @@
#include <strsafe.h>
#include <wine/debug.h>
#include <wine/unicode.h>
+#include <assert.h>
#include <shlwapi_undoc.h>
#include <shellutils.h>
@@ -103,6 +104,14 @@ DoGetProductType(PNT_PRODUCT_TYPE ProductType)
return TRUE;
}
+BOOL APIENTRY IsRemovableDrive(DWORD iDrive)
+{
+ WCHAR szRoot[] = L"C:\\";
+ assert(L'A' + iDrive <= L'Z');
+ szRoot[0] = (WCHAR)(L'A' + iDrive);
+ return GetDriveTypeW(szRoot) == DRIVE_REMOVABLE;
+}
+
/*
########## Combining and Constructing paths ##########
*/
@@ -151,7 +160,7 @@ PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir,
_In_ DWORD dw
INT iDrive, cchPathLeft;
WCHAR szTemp[MAX_PATH], szRoot[MAX_PATH];
PWCHAR pchTemp = szTemp, pchPath;
- BOOL bLFN = TRUE;
+ BOOL bLFN;
TRACE("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszDir),
dwFlags);
@@ -208,12 +217,27 @@ PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir,
_In_ DWORD dw
++pchTemp;
}
-#if 0 // FIXME: IsLFNDriveW has a bug
bLFN = IsLFNDriveW(szRoot);
-#endif
if (!bLFN)
{
- /* FIXME: Support non-LFN */
+ PWCHAR pch;
+ for (pch = pchTemp; *pch != UNICODE_NULL; ++pch)
+ {
+#define PATH_CHAR_CLASS_DOT 0x00000004
+#define PATH_CHAR_CLASS_BACKSLASH 0x00000008
+#define PATH_CHAR_CLASS_COLON 0x00000010
+#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100
+#define VALID_SHORT_PATH_CHAR_CLASSES ( \
+ PATH_CHAR_CLASS_DOT | \
+ PATH_CHAR_CLASS_BACKSLASH | \
+ PATH_CHAR_CLASS_COLON | \
+ PATH_CHAR_CLASS_OTHER_VALID \
+)
+ if (!PathIsValidCharW(*pch, VALID_SHORT_PATH_CHAR_CLASSES))
+ {
+ *pch = L'_';
+ }
+ }
}
StringCchCopyW(pszPath, MAX_PATH, szRoot);
@@ -221,16 +245,33 @@ PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir,
_In_ DWORD dw
}
else /* UNC path: Begins with double backslash */
{
-#if 0 // FIXME: IsLFNDriveW has a bug
bLFN = IsLFNDriveW(pchTemp);
-#endif
- if (!bLFN)
+ if (bLFN)
{
- /* FIXME: Support non-LFN */
+ pszPath[2] = UNICODE_NULL; /* Cut off */
+ cchPathLeft -= (2 + 1);
+ pchTemp += 2;
+ }
+ else
+ {
+ PWCHAR pchSlash = StrChrW(pszPath + 2, L'\\');
+ if (pchSlash)
+ pchSlash = StrChrW(pchSlash + 1, L'\\');
+
+ if (pchSlash)
+ {
+ *(pchSlash + 1) = UNICODE_NULL; /* Cut off */
+ pchTemp += pchSlash - pszPath;
+ cchPathLeft -= (INT)(SIZE_T)(pchSlash - pszPath) + 1;
+ }
+ else
+ {
+ bLFN = TRUE;
+ pszPath[2] = UNICODE_NULL; /* Cut off */
+ cchPathLeft -= 2;
+ pchTemp += 2;
+ }
}
- pszPath[2] = UNICODE_NULL; /* Cut off */
- cchPathLeft -= (2 + 1);
- pchTemp += 2;
}
/* Now pszPath is a root-like path or an empty string. */
@@ -280,11 +321,60 @@ PathQualifyExW(_Inout_ LPWSTR pszPath, _Inout_opt_ LPCWSTR pszDir,
_In_ DWORD dw
pchPath = &pszPath[lstrlenW(pszPath)];
- if (!bLFN)
+ if (!bLFN) /* Not LFN? */
{
- /* FIXME: Support non-LFN */
+ /* Copy MS-DOS 8.3 filename */
+ PWCHAR pchDot = NULL;
+ INT ich;
+ WCHAR szTitle[8 + 1] = L"";
+ INT cchTitle = 0;
+ WCHAR szDotExtension[1 + 3 + 1] = L"";
+ INT cchDotExtension = 0;
+
+ /* Copy the component to szTitle and szDotExtension... */
+ while (*pchTemp && *pchTemp != L'\\')
+ {
+ if (*pchTemp == L'.')
+ {
+ pchDot = pchTemp; /* Remember the last position */
+
+ /* Clear szDotExtension */
+ cchDotExtension = 0;
+ ZeroMemory(szDotExtension, sizeof(szDotExtension));
+ }
+
+ if (pchDot)
+ {
+ if (cchDotExtension < 1 + 3)
+ szDotExtension[cchDotExtension++] = *pchTemp;
+ }
+ else
+ {
+ if (cchTitle < 8)
+ szTitle[cchTitle++] = *pchTemp;
+ }
+
+ ++pchTemp;
+ }
+
+ /* Add file title 'szTitle' to pchPath */
+ for (ich = 0; szTitle[ich] && cchPathLeft > 0; ++ich)
+ {
+ *pchPath++ = szTitle[ich];
+ --cchPathLeft;
+ }
+
+ /* Add file extension 'szDotExtension' to pchPath */
+ if (pchDot)
+ {
+ for (ich = 0; szDotExtension[ich] && cchPathLeft > 0; ++ich)
+ {
+ *pchPath++ = szDotExtension[ich];
+ --cchPathLeft;
+ }
+ }
}
- else
+ else /* LFN */
{
/* Copy the component up to the next separator */
while (*pchTemp != UNICODE_NULL && *pchTemp != L'\\'
&& cchPathLeft > 0)
@@ -490,11 +580,13 @@ BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
*/
BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
{
- DWORD fnlen;
-
- if (!GetVolumeInformationA(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
- return FALSE;
- return fnlen > 12;
+ WCHAR szBuffW[MAX_PATH], *pszW = NULL;
+ if (lpszPath)
+ {
+ SHAnsiToUnicode(lpszPath, szBuffW, _countof(szBuffW));
+ pszW = szBuffW;
+ }
+ return IsLFNDriveW(pszW);
}
/*************************************************************************
@@ -502,11 +594,49 @@ BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
*/
BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath)
{
- DWORD fnlen;
+ DWORD cchMaxFileName, iDrive;
+ WCHAR szRoot[MAX_PATH];
- if (!GetVolumeInformationW(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
- return FALSE;
- return fnlen > 12;
+ if (lpszPath == NULL || lpszPath[0] == UNICODE_NULL)
+ {
+ szRoot[0] = 0;
+ GetWindowsDirectoryW(szRoot, _countof(szRoot));
+ lpszPath = szRoot;
+ }
+
+ if (PathIsUNCW(lpszPath))
+ {
+ StringCchCopyW(szRoot, _countof(szRoot), lpszPath);
+ PathStripToRootW(szRoot);
+
+ if (StrChrW(szRoot + 2, L'\\') == NULL)
+ return TRUE; /* LFN */
+
+ StringCchCatW(szRoot, _countof(szRoot), L"\\"); /* Add a backslash */
+ }
+ else
+ {
+ assert(!PathIsRelativeW(lpszPath)); /* Assuming absolute path... */
+
+ iDrive = ((lpszPath[0] - L'A') & 0x1F);
+ PathBuildRootW(szRoot, iDrive);
+
+ if (!IsRemovableDrive(iDrive))
+ {
+ /* FIXME: Cache correctly */
+ }
+ }
+
+#define MSDOS_8DOT3_LEN 12 /* MS-DOS 8.3 filename == length 12 */
+
+ /* GetVolumeInformation requires a root path */
+ if (!GetVolumeInformationW(szRoot, NULL, 0, NULL, &cchMaxFileName, NULL, NULL,
0))
+ {
+ /* Don't return FALSE when GetVolumeInformationW fails. */
+ return TRUE;
+ }
+
+ return cchMaxFileName > MSDOS_8DOT3_LEN;
}
/*************************************************************************