https://git.reactos.org/?p=reactos.git;a=commitdiff;h=11a71418d50f48ff0e10d2dbbe243afaf34c4368

commit 11a71418d50f48ff0e10d2dbbe243afaf34c4368
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Thu Nov 10 23:18:04 2022 +0900
Commit:     GitHub <[email protected]>
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;
 }
 
 /*************************************************************************

Reply via email to