Author: pschweitzer
Date: Tue Oct  3 06:19:12 2017
New Revision: 76031

URL: http://svn.reactos.org/svn/reactos?rev=76031&view=rev
Log:
[KERNEL32]
Reimplement GetVolumePathNameW(). This fixes a lot of failing Wine tests.
Note that three of them are not fixed, which is a good thing as these also fail 
in the WHS bot!

Modified:
    trunk/reactos/dll/win32/kernel32/client/file/volume.c
    trunk/reactos/dll/win32/kernel32/include/kernel32.h

Modified: trunk/reactos/dll/win32/kernel32/client/file/volume.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/file/volume.c?rev=76031&r1=76030&r2=76031&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/file/volume.c       [iso-8859-1] 
(original)
+++ trunk/reactos/dll/win32/kernel32/client/file/volume.c       [iso-8859-1] 
Tue Oct  3 06:19:12 2017
@@ -748,22 +748,59 @@
                    IN LPSTR lpszVolumePathName,
                    IN DWORD cchBufferLength)
 {
-    PWCHAR FileNameW = NULL;
-    WCHAR VolumePathName[MAX_PATH];
-    BOOL Result;
-
-    if (lpszFileName)
-    {
-        if (!(FileNameW = FilenameA2W(lpszFileName, FALSE)))
-            return FALSE;
-    }
-
-    Result = GetVolumePathNameW(FileNameW, VolumePathName, cchBufferLength);
-
-    if (Result)
-        FilenameW2A_N(lpszVolumePathName, MAX_PATH, VolumePathName, -1);
-
-    return Result;
+    BOOL Ret;
+    PUNICODE_STRING FileNameU;
+    ANSI_STRING VolumePathName;
+    UNICODE_STRING VolumePathNameU;
+
+    /* Convert file name to unicode */
+    FileNameU = Basep8BitStringToStaticUnicodeString(lpszFileName);
+    if (FileNameU == NULL)
+    {
+        return FALSE;
+    }
+
+    /* Initialize all the strings we'll need */
+    VolumePathName.Buffer = lpszVolumePathName;
+    VolumePathName.Length = 0;
+    VolumePathName.MaximumLength = cchBufferLength - 1;
+
+    VolumePathNameU.Length = 0;
+    VolumePathNameU.MaximumLength = (cchBufferLength - 1) * sizeof(WCHAR) + 
sizeof(UNICODE_NULL);
+    /* Allocate a buffer for calling the -W */
+    VolumePathNameU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, 
VolumePathNameU.MaximumLength);
+    if (VolumePathNameU.Buffer == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    /* Call the -W implementation */
+    Ret = GetVolumePathNameW(FileNameU->Buffer, VolumePathNameU.Buffer, 
cchBufferLength);
+    /* If it succeed */
+    if (Ret)
+    {
+        NTSTATUS Status;
+
+        /* Convert back to ANSI */
+        RtlInitUnicodeString(&VolumePathNameU, VolumePathNameU.Buffer);
+        Status = RtlUnicodeStringToAnsiString(&VolumePathName, 
&VolumePathNameU, FALSE);
+        /* If conversion failed, just set error code and fail the rest */
+        if (!NT_SUCCESS(Status))
+        {
+            BaseSetLastNTError(Status);
+            Ret = FALSE;
+        }
+        /* Otherwise, null terminate the string (it's OK, we computed -1) */
+        else
+        {
+            VolumePathName.Buffer[VolumePathName.Length] = ANSI_NULL;
+        }
+    }
+
+    /* Free the buffer allocated for -W call */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNameU.Buffer);
+    return Ret;
 }
 
 /*
@@ -775,112 +812,235 @@
                    IN LPWSTR lpszVolumePathName,
                    IN DWORD cchBufferLength)
 {
-    DWORD PathLength;
-    UNICODE_STRING UnicodeFilePath;
-    LPWSTR FilePart;
-    PWSTR FullFilePath, FilePathName;
-    ULONG PathSize;
-    WCHAR VolumeName[MAX_PATH];
-    DWORD ErrorCode;
-    BOOL Result = FALSE;
-
-    if (!lpszFileName || !lpszVolumePathName || !cchBufferLength)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-    
-    if (!(PathLength = GetFullPathNameW(lpszFileName, 0, NULL, NULL)))
-    {
-        return Result;
-    }
-    else
-    {
-        PathLength = PathLength + 10;
-        PathSize = PathLength * sizeof(WCHAR);
-
-        if (!(FullFilePath = RtlAllocateHeap(RtlGetProcessHeap(), 0, 
PathSize)))
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return Result;
-        }
-
-        if (!GetFullPathNameW(lpszFileName, PathLength, FullFilePath, 
&FilePart))
-        {
-            RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
-            return Result;
-        }
-
-        RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
-
-        if (UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] 
!= '\\')
-        {
-            UnicodeFilePath.Length += sizeof(WCHAR);
-            UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] 
= '\\';
-            UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = 
'\0';
-        }
-
-        if (!(FilePathName = RtlAllocateHeap(RtlGetProcessHeap(), 0, 
PathSize)))
-        {
-            RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return Result;
-        }
-
-        while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath.Buffer,
-                                                  VolumeName,
-                                                  MAX_PATH))
-        {
-            if (((UnicodeFilePath.Length == 4) && (UnicodeFilePath.Buffer[0] 
== '\\') &&
-                (UnicodeFilePath.Buffer[1] == '\\')) || 
((UnicodeFilePath.Length == 6) &&
-                (UnicodeFilePath.Buffer[1] == ':')))
+    BOOL MountPoint;
+    DWORD FullPathLen;
+    WCHAR OldFilePart;
+    UNICODE_STRING FullPath;
+    PWSTR FullPathBuf, FilePart, VolumeNameBuf;
+
+    /* Probe for full path len */
+    FullPathLen = GetFullPathNameW(lpszFileName, 0, NULL, NULL);
+    if (FullPathLen == 0)
+    {
+        return FALSE;
+    }
+
+    /* Allocate a big enough buffer to receive it */
+    FullPathBuf = RtlAllocateHeap(RtlGetProcessHeap(), 0, (FullPathLen + 10) * 
sizeof(WCHAR));
+    if (FullPathBuf == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    /* And get full path name */
+    if (GetFullPathNameW(lpszFileName, FullPathLen + 10, FullPathBuf, 
&FilePart) == 0)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
+        return FALSE;
+    }
+
+    /* Make a string out of it */
+    RtlInitUnicodeString(&FullPath, FullPathBuf);
+    /* We will finish our string with '\', for ease of the parsing after */
+    if (FullPath.Buffer[(FullPath.Length / sizeof(WCHAR)) - 1] != L'\\')
+    {
+        FullPath.Length += sizeof(WCHAR);
+        FullPath.Buffer[(FullPath.Length / sizeof(WCHAR)) - 1] = L'\\';
+        FullPath.Buffer[FullPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
+    }
+
+    /* Allocate a buffer big enough to receive our volume name */
+    VolumeNameBuf = RtlAllocateHeap(RtlGetProcessHeap(), 0, 0x2000 * 
sizeof(WCHAR));
+    if (VolumeNameBuf == NULL)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    /* We don't care about file part: we added an extra backslash, so there's 
no
+     * file, we're back at the dir level.
+     * We'll recompute file part afterwards
+     */
+    FilePart = NULL;
+    /* Keep track of the letter we could drop to shorten the string */
+    OldFilePart = UNICODE_NULL;
+    /* As long as querying volume name fails, keep looping */
+    while (!BasepGetVolumeNameForVolumeMountPoint(FullPath.Buffer, 
VolumeNameBuf, 0x2000u, &MountPoint))
+    {
+        USHORT LastSlash;
+
+        /* Not a mount point, but opening returning access denied? Assume it's 
one, just not
+         * a reparse backed one (classic mount point, a device)!
+         */
+        if (!MountPoint && GetLastError() == ERROR_ACCESS_DENIED)
+        {
+            MountPoint = TRUE;
+        }
+
+        /* BasepGetVolumeNameForVolumeMountPoint failed, but returned a volume 
name.
+         * This can happen when we are given a reparse point where MountMgr 
could find associated
+         * volume name which is not a valid DOS volume
+         * A valid DOS name always starts with \\
+         */
+        if (VolumeNameBuf[0] != UNICODE_NULL && (FullPath.Buffer[0] != L'\\' 
|| FullPath.Buffer[1] != L'\\'))
+        {
+            CHAR RootPathName[4];
+
+            /* Construct a simple <letter>:\ string to get drive type */
+            RootPathName[0] = FullPath.Buffer[0];
+            RootPathName[1] = ':';
+            RootPathName[2] = '\\';
+            RootPathName[3] = ANSI_NULL;
+
+            /* If we weren't given a drive letter actually, or if that's not a 
remote drive
+             * Note: in this code path, we're recursive and stop fail loop
+             */
+            if (FullPath.Buffer[1] != L':' || GetDriveTypeA(RootPathName) != 
DRIVE_REMOTE)
             {
-                break;
+                BOOL Ret;
+
+                /* We won't need the full path, we'll now work with the 
returned volume name */
+                RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
+                /* If it wasn't an NT name which was returned */
+                if ((VolumeNameBuf[0] != L'\\') || (VolumeNameBuf[1] != L'?') 
||
+                    (VolumeNameBuf[2] != L'?') || (VolumeNameBuf[3] != L'\\'))
+                {
+                    PWSTR GlobalPath;
+                    UNICODE_STRING GlobalRoot;
+
+                    /* Create a new name in the NT namespace (from Win32) */
+                    RtlInitUnicodeString(&FullPath, VolumeNameBuf);
+                    RtlInitUnicodeString(&GlobalRoot, L"\\\\?\\GLOBALROOT");
+
+                    /* We allocate a buffer than can contain both the 
namespace and the volume name */
+                    GlobalPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, 
FullPath.Length + GlobalRoot.Length);
+                    if (GlobalPath == NULL)
+                    {
+                        RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
+                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                        return FALSE;
+                    }
+
+                    /* Fill in the new query name */
+                    RtlCopyMemory(GlobalPath, GlobalRoot.Buffer, 
GlobalRoot.Length);
+                    RtlCopyMemory((PVOID)((ULONG_PTR)GlobalPath + 
GlobalRoot.Length), FullPath.Buffer, FullPath.Length);
+                    GlobalPath[(FullPath.Length + GlobalRoot.Length) / 
sizeof(WCHAR)] = UNICODE_NULL;
+
+                    /* Give it another try */
+                    Ret = GetVolumePathNameW(GlobalPath, lpszVolumePathName, 
cchBufferLength);
+
+                    RtlFreeHeap(RtlGetProcessHeap(), 0, GlobalPath);
+                }
+                else
+                {
+                    /* If we don't have a drive letter in the Win32 name space 
\\.\<letter>: */
+                    if ((VolumeNameBuf[4] != UNICODE_NULL) && 
(VolumeNameBuf[5] != L':'))
+                    {
+                        /* Shit our starting \\ */
+                        RtlInitUnicodeString(&FullPath, VolumeNameBuf);
+                        RtlMoveMemory(VolumeNameBuf, 
(PVOID)((ULONG_PTR)VolumeNameBuf + (2 * sizeof(WCHAR))), FullPath.Length - (3 * 
sizeof(WCHAR)));
+                    }
+                    /* Otherwise, just make sure we're double \ at the being 
to query again with the
+                     * proper namespace
+                     */
+                    else
+                    {
+                        VolumeNameBuf[1] = L'\\';
+                    }
+
+                    /* Give it another try */
+                    Ret = GetVolumePathNameW(VolumeNameBuf, 
lpszVolumePathName, cchBufferLength);
+                }
+
+                /* And done! */
+                RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
+                return Ret;
             }
-
-            UnicodeFilePath.Length -= sizeof(WCHAR);
-            UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = 
'\0';
-
-            memcpy(FilePathName, UnicodeFilePath.Buffer, 
UnicodeFilePath.Length);
-            FilePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
-
-            if (!GetFullPathNameW(FilePathName, PathLength, FullFilePath, 
&FilePart))
+        }
+
+        /* No mount point but with a file part? Restore filepart and exit */
+        if (!MountPoint && FilePart != NULL)
+        {
+            FilePart[0] = OldFilePart;
+            RtlInitUnicodeString(&FullPath, FullPathBuf);
+            break;
+        }
+
+        /* We cannot go down the path any longer, too small */
+        if (FullPath.Length <= sizeof(WCHAR))
+        {
+            break;
+        }
+
+        /* Prepare the next split */
+        LastSlash = (FullPath.Length / sizeof(WCHAR)) - 2;
+        if (FullPath.Length / sizeof(WCHAR) != 2)
+        {
+            do
             {
-                goto Cleanup2;
-            }
-
-            if (!FilePart)
-            {
-                RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
-                UnicodeFilePath.Length += sizeof(WCHAR);
-                UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) 
- 1] = '\\';
-                UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] 
= '\0';
-                break;
-            }
-
-            FilePart[0] = '\0';
-            RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
-        }
-    }
-
-    if (UnicodeFilePath.Length > (cchBufferLength * sizeof(WCHAR)) - 
sizeof(WCHAR))
-    {
-        ErrorCode = ERROR_FILENAME_EXCED_RANGE;
-        goto Cleanup1;
-    }
-
-    memcpy(lpszVolumePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
-    lpszVolumePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
-
-    Result = TRUE;
-    goto Cleanup2;
-
-Cleanup1:
-    SetLastError(ErrorCode);
-Cleanup2:
-    RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
-    RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName);
-    return Result;
+                if (FullPath.Buffer[LastSlash] == L'\\')
+                {
+                    break;
+                }
+
+                --LastSlash;
+            } while (LastSlash != 0);
+        }
+
+        /* We couldn't split path, quit */
+        if (LastSlash == 0)
+        {
+            break;
+        }
+
+        /* If that's a mount point, keep track of the directory name */
+        if (MountPoint)
+        {
+            FilePart = &FullPath.Buffer[LastSlash + 1];
+            OldFilePart = FilePart[0];
+            /* And null terminate the string */
+            FilePart[0] = UNICODE_NULL;
+        }
+        /* Otherwise, just null terminate the string */
+        else
+        {
+            FullPath.Buffer[LastSlash + 1] = UNICODE_NULL;
+        }
+
+        /* We went down a bit in the path, fix the string and retry */
+        RtlInitUnicodeString(&FullPath, FullPathBuf);
+    }
+
+    /* Once here, we'll return something from the full path buffer, so release
+     * output buffer
+     */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
+
+    /* Not a mount point, bail out */
+    if (!MountPoint && FilePart == NULL)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
+        return FALSE;
+    }
+
+    /* Make sure we have enough room to copy our volume */
+    if ((cchBufferLength * sizeof(WCHAR)) < FullPath.Length + 
sizeof(UNICODE_NULL))
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
+        SetLastError(ERROR_FILENAME_EXCED_RANGE);
+        return FALSE;
+    }
+
+    /* Copy and null terminate */
+    RtlCopyMemory(lpszVolumePathName, FullPath.Buffer, FullPath.Length);
+    lpszVolumePathName[FullPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+    RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
+
+    /* Done! */
+    return TRUE;
 }
 
 /*

Modified: trunk/reactos/dll/win32/kernel32/include/kernel32.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/include/kernel32.h?rev=76031&r1=76030&r2=76031&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/include/kernel32.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/include/kernel32.h [iso-8859-1] Tue Oct  3 
06:19:12 2017
@@ -440,6 +440,14 @@
     OUT LPHANDLE lpNewHandle
 );
 
+BOOL
+BasepGetVolumeNameForVolumeMountPoint(
+    IN LPCWSTR lpszMountPoint,
+    OUT LPWSTR lpszVolumeName,
+    IN DWORD cchBufferLength,
+    OUT LPBOOL IsAMountPoint
+);
+
 /* FIXME: This is EXPORTED! It should go in an external kernel32.h header */
 VOID
 WINAPI


Reply via email to