[PATCH] kernel32: Implement GetFinalPathNameByHandle.

Andrew Eikum aeikum at codeweavers.com
Thu Apr 7 10:28:52 CDT 2016


From: Michael Müller <michael at fds-team.de>

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 .../api-ms-win-core-file-l1-1-0.spec               |   4 +-
 .../api-ms-win-core-file-l1-2-0.spec               |   4 +-
 .../api-ms-win-core-file-l1-2-1.spec               |   4 +-
 dlls/kernel32/file.c                               | 211 +++++++++++++++++++++
 dlls/kernel32/kernel32.spec                        |   4 +-
 dlls/kernel32/tests/file.c                         |  40 ++++
 dlls/kernelbase/kernelbase.spec                    |   4 +-
 7 files changed, 261 insertions(+), 10 deletions(-)

diff --git a/dlls/api-ms-win-core-file-l1-1-0/api-ms-win-core-file-l1-1-0.spec b/dlls/api-ms-win-core-file-l1-1-0/api-ms-win-core-file-l1-1-0.spec
index 9e5b809..61e8038 100644
--- a/dlls/api-ms-win-core-file-l1-1-0/api-ms-win-core-file-l1-1-0.spec
+++ b/dlls/api-ms-win-core-file-l1-1-0/api-ms-win-core-file-l1-1-0.spec
@@ -39,8 +39,8 @@
 @ stdcall GetFileSizeEx(long ptr) kernel32.GetFileSizeEx
 @ stdcall GetFileTime(long ptr ptr ptr) kernel32.GetFileTime
 @ stdcall GetFileType(long) kernel32.GetFileType
-@ stub GetFinalPathNameByHandleA
-@ stub GetFinalPathNameByHandleW
+@ stdcall GetFinalPathNameByHandleA(long ptr long long) kernel32.GetFinalPathNameByHandleA
+@ stdcall GetFinalPathNameByHandleW(long ptr long long) kernel32.GetFinalPathNameByHandleW
 @ stdcall GetFullPathNameA(str long ptr ptr) kernel32.GetFullPathNameA
 @ stdcall GetFullPathNameW(wstr long ptr ptr) kernel32.GetFullPathNameW
 @ stdcall GetLogicalDriveStringsW(long ptr) kernel32.GetLogicalDriveStringsW
diff --git a/dlls/api-ms-win-core-file-l1-2-0/api-ms-win-core-file-l1-2-0.spec b/dlls/api-ms-win-core-file-l1-2-0/api-ms-win-core-file-l1-2-0.spec
index ebfd52e..cddf112 100644
--- a/dlls/api-ms-win-core-file-l1-2-0/api-ms-win-core-file-l1-2-0.spec
+++ b/dlls/api-ms-win-core-file-l1-2-0/api-ms-win-core-file-l1-2-0.spec
@@ -39,8 +39,8 @@
 @ stdcall GetFileSizeEx(long ptr) kernel32.GetFileSizeEx
 @ stdcall GetFileTime(long ptr ptr ptr) kernel32.GetFileTime
 @ stdcall GetFileType(long) kernel32.GetFileType
-@ stub GetFinalPathNameByHandleA
-@ stub GetFinalPathNameByHandleW
+@ stdcall GetFinalPathNameByHandleA(long ptr long long) kernel32.GetFinalPathNameByHandleA
+@ stdcall GetFinalPathNameByHandleW(long ptr long long) kernel32.GetFinalPathNameByHandleW
 @ stdcall GetFullPathNameA(str long ptr ptr) kernel32.GetFullPathNameA
 @ stdcall GetFullPathNameW(wstr long ptr ptr) kernel32.GetFullPathNameW
 @ stdcall GetLogicalDriveStringsW(long ptr) kernel32.GetLogicalDriveStringsW
diff --git a/dlls/api-ms-win-core-file-l1-2-1/api-ms-win-core-file-l1-2-1.spec b/dlls/api-ms-win-core-file-l1-2-1/api-ms-win-core-file-l1-2-1.spec
index c7691a4..a9acd8d 100644
--- a/dlls/api-ms-win-core-file-l1-2-1/api-ms-win-core-file-l1-2-1.spec
+++ b/dlls/api-ms-win-core-file-l1-2-1/api-ms-win-core-file-l1-2-1.spec
@@ -41,8 +41,8 @@
 @ stdcall GetFileSizeEx(long ptr) kernel32.GetFileSizeEx
 @ stdcall GetFileTime(long ptr ptr ptr) kernel32.GetFileTime
 @ stdcall GetFileType(long) kernel32.GetFileType
-@ stub GetFinalPathNameByHandleA
-@ stub GetFinalPathNameByHandleW
+@ stdcall GetFinalPathNameByHandleA(long ptr long long) kernel32.GetFinalPathNameByHandleA
+@ stdcall GetFinalPathNameByHandleW(long ptr long long) kernel32.GetFinalPathNameByHandleW
 @ stdcall GetFullPathNameA(str long ptr ptr) kernel32.GetFullPathNameA
 @ stdcall GetFullPathNameW(wstr long ptr ptr) kernel32.GetFullPathNameW
 @ stdcall GetLogicalDriveStringsW(long ptr) kernel32.GetLogicalDriveStringsW
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index e262e2f..e1be825 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -2912,3 +2912,214 @@ DWORD WINAPI K32GetDeviceDriverFileNameW(void *image_base, LPWSTR file_name, DWO
 
     return 0;
 }
+
+/***********************************************************************
+ *           GetFinalPathNameByHandleW (KERNEL32.@)
+ */
+DWORD WINAPI GetFinalPathNameByHandleW(HANDLE file, LPWSTR path, DWORD charcount, DWORD flags)
+{
+    WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1];
+    OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer;
+    WCHAR drive_part[MAX_PATH];
+    DWORD drive_part_len;
+    NTSTATUS status;
+    DWORD result = 0;
+    ULONG dummy;
+    WCHAR *ptr;
+
+    TRACE( "(%p,%p,%d,%x)\n", file, path, charcount, flags );
+
+    if (flags & ~(FILE_NAME_OPENED | VOLUME_NAME_GUID | VOLUME_NAME_NONE | VOLUME_NAME_NT))
+    {
+        WARN("Unknown flags: %x\n", flags);
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return 0;
+    }
+
+    /* get object name */
+    status = NtQueryObject( file, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy );
+    if (status != STATUS_SUCCESS)
+    {
+        SetLastError( RtlNtStatusToDosError( status ) );
+        return 0;
+    }
+    if (!info->Name.Buffer)
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return 0;
+    }
+    if (info->Name.Length < 4 * sizeof(WCHAR) || info->Name.Buffer[0] != '\\' ||
+             info->Name.Buffer[1] != '?' || info->Name.Buffer[2] != '?' || info->Name.Buffer[3] != '\\' )
+    {
+        FIXME("Unexpected object name: %s\n", debugstr_wn(info->Name.Buffer, info->Name.Length / sizeof(WCHAR)));
+        SetLastError( ERROR_GEN_FAILURE );
+        return 0;
+    }
+
+    /* add terminating null character, remove "\\??\\" */
+    info->Name.Buffer[info->Name.Length / sizeof(WCHAR)] = 0;
+    info->Name.Length -= 4 * sizeof(WCHAR);
+    info->Name.Buffer += 4;
+
+    /* FILE_NAME_OPENED is not supported yet, and would require Wineserver changes */
+    if (flags & FILE_NAME_OPENED)
+    {
+        FIXME("FILE_NAME_OPENED not supported\n");
+        flags &= ~FILE_NAME_OPENED;
+    }
+
+    /* Get information required for VOLUME_NAME_NONE, VOLUME_NAME_GUID and VOLUME_NAME_NT */
+    if (flags == VOLUME_NAME_NONE || flags == VOLUME_NAME_GUID || flags == VOLUME_NAME_NT)
+    {
+        if (!GetVolumePathNameW( info->Name.Buffer, drive_part, MAX_PATH ))
+            return 0;
+
+        drive_part_len = strlenW(drive_part);
+        if (!drive_part_len || drive_part_len > strlenW(info->Name.Buffer) ||
+                drive_part[drive_part_len-1] != '\\' ||
+                strncmpiW( info->Name.Buffer, drive_part, drive_part_len ))
+        {
+            FIXME("Path %s returned by GetVolumePathNameW does not match file path %s\n",
+                debugstr_w(drive_part), debugstr_w(info->Name.Buffer));
+            SetLastError( ERROR_GEN_FAILURE );
+            return 0;
+        }
+    }
+
+    if (flags == VOLUME_NAME_NONE)
+    {
+        ptr    = info->Name.Buffer + drive_part_len - 1;
+        result = strlenW(ptr);
+        if (result < charcount)
+            memcpy(path, ptr, (result + 1) * sizeof(WCHAR));
+        else result++;
+    }
+    else if (flags == VOLUME_NAME_GUID)
+    {
+        WCHAR volume_prefix[51];
+
+        /* GetVolumeNameForVolumeMountPointW sets error code on failure */
+        if (!GetVolumeNameForVolumeMountPointW( drive_part, volume_prefix, 50 ))
+            return 0;
+
+        ptr    = info->Name.Buffer + drive_part_len;
+        result = strlenW(volume_prefix) + strlenW(ptr);
+        if (result < charcount)
+        {
+            path[0] = 0;
+            strcatW(path, volume_prefix);
+            strcatW(path, ptr);
+        }
+        else
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            result++;
+        }
+    }
+    else if (flags == VOLUME_NAME_NT)
+    {
+        WCHAR nt_prefix[MAX_PATH];
+
+        /* QueryDosDeviceW sets error code on failure */
+        drive_part[drive_part_len - 1] = 0;
+        if (!QueryDosDeviceW( drive_part, nt_prefix, MAX_PATH ))
+            return 0;
+
+        ptr    = info->Name.Buffer + drive_part_len - 1;
+        result = strlenW(nt_prefix) + strlenW(ptr);
+        if (result < charcount)
+        {
+            path[0] = 0;
+            strcatW(path, nt_prefix);
+            strcatW(path, ptr);
+        }
+        else
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            result++;
+        }
+    }
+    else if (flags == VOLUME_NAME_DOS)
+    {
+        static const WCHAR dos_prefix[] = {'\\','\\','?','\\', '\0'};
+
+        result = strlenW(dos_prefix) + strlenW(info->Name.Buffer);
+        if (result < charcount)
+        {
+            path[0] = 0;
+            strcatW(path, dos_prefix);
+            strcatW(path, info->Name.Buffer);
+        }
+        else
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            result++;
+        }
+    }
+    else
+    {
+        /* Windows crashes here, but we prefer returning ERROR_INVALID_PARAMETER */
+        WARN("Invalid combination of flags: %x\n", flags);
+        SetLastError( ERROR_INVALID_PARAMETER );
+    }
+
+    return result;
+}
+
+/***********************************************************************
+ *           GetFinalPathNameByHandleA (KERNEL32.@)
+ */
+DWORD WINAPI GetFinalPathNameByHandleA(HANDLE file, LPSTR path, DWORD charcount, DWORD flags)
+{
+    WCHAR *str;
+    DWORD result, len, cp;
+
+    TRACE( "(%p,%p,%d,%x)\n", file, path, charcount, flags);
+
+    len = GetFinalPathNameByHandleW(file, NULL, 0, flags);
+    if (len == 0)
+        return 0;
+
+    str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!str)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
+    }
+
+    result = GetFinalPathNameByHandleW(file, str, len, flags);
+    if (result != len - 1)
+    {
+        HeapFree(GetProcessHeap(), 0, str);
+        WARN("GetFinalPathNameByHandleW failed unexpectedly: %u\n", result);
+        return 0;
+    }
+
+    cp = oem_file_apis ? CP_OEMCP : CP_ACP;
+
+    len = WideCharToMultiByte(cp, 0, str, -1, NULL, 0, NULL, NULL);
+    if (!len)
+    {
+        HeapFree(GetProcessHeap(), 0, str);
+        WARN("Failed to get multibyte length\n");
+        return 0;
+    }
+
+    if (charcount < len)
+    {
+        HeapFree(GetProcessHeap(), 0, str);
+        return len - 1;
+    }
+
+    len = WideCharToMultiByte(cp, 0, str, -1, path, charcount, NULL, NULL);
+    if (!len)
+    {
+        HeapFree(GetProcessHeap(), 0, str);
+        WARN("WideCharToMultiByte failed\n");
+        return 0;
+    }
+
+    HeapFree(GetProcessHeap(), 0, str);
+
+    return len - 1;
+}
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 3452360..73f2e88 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -682,8 +682,8 @@
 @ stdcall GetFileSizeEx(long ptr)
 @ stdcall GetFileTime(long ptr ptr ptr)
 @ stdcall GetFileType(long)
-# @ stub GetFinalPathNameByHandleA
-# @ stub GetFinalPathNameByHandleW
+@ stdcall GetFinalPathNameByHandleA(long ptr long long)
+@ stdcall GetFinalPathNameByHandleW(long ptr long long)
 @ stdcall GetFirmwareEnvironmentVariableA(str str ptr long)
 @ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long)
 @ stdcall GetFullPathNameA(str long ptr ptr)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index a066692..3ab16d3 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -4453,10 +4453,29 @@ static void test_GetFinalPathNameByHandleA(void)
     strcpy(dos_path, dos_prefix);
     strcat(dos_path, long_path);
 
+    count = pGetFinalPathNameByHandleA(INVALID_HANDLE_VALUE, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    ok(count == 0, "Expected length 0, got %u\n", count);
+    ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError());
+
     file = CreateFileA(test_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                        CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0);
     ok(file != INVALID_HANDLE_VALUE, "CreateFileA error %u\n", GetLastError());
 
+    if (0) {
+        /* Windows crashes on NULL path */
+        count = pGetFinalPathNameByHandleA(file, NULL, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+        ok(count == 0, "Expected length 0, got %u\n", count);
+        ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError());
+    }
+
+    /* Test 0-length path */
+    count = pGetFinalPathNameByHandleA(file, result_path, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    ok(count == strlen(dos_path), "Expected length %u, got %u\n", strlen(dos_path), count);
+
+    /* Test 0 and NULL path */
+    count = pGetFinalPathNameByHandleA(file, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    ok(count == strlen(dos_path), "Expected length %u, got %u\n", strlen(dos_path), count);
+
     /* Test VOLUME_NAME_DOS with sufficient buffer size */
     memset(result_path, 0x11, sizeof(result_path));
     count = pGetFinalPathNameByHandleA(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
@@ -4518,6 +4537,10 @@ static void test_GetFinalPathNameByHandleW(void)
     ok(count == 0, "Expected length 0, got %u\n", count);
     ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError());
 
+    count = pGetFinalPathNameByHandleW(INVALID_HANDLE_VALUE, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    ok(count == 0, "Expected length 0, got %u\n", count);
+    ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError());
+
     count = GetTempPathW(MAX_PATH, temp_path);
     ok(count, "Failed to get temp path, error %u\n", GetLastError());
     ret = GetTempFileNameW(temp_path, prefix, 0, test_path);
@@ -4531,6 +4554,23 @@ static void test_GetFinalPathNameByHandleW(void)
                        CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0);
     ok(file != INVALID_HANDLE_VALUE, "CreateFileW error %u\n", GetLastError());
 
+    if (0) {
+        /* Windows crashes on NULL path */
+        count = pGetFinalPathNameByHandleW(file, NULL, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+        ok(count == 0, "Expected length 0, got %u\n", count);
+        ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError());
+    }
+
+    /* Test 0-length path */
+    count = pGetFinalPathNameByHandleW(file, result_path, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    ok(count == lstrlenW(dos_path) + 1 ||
+            broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count);
+
+    /* Test 0 and NULL path */
+    count = pGetFinalPathNameByHandleW(file, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    ok(count == lstrlenW(dos_path) + 1 ||
+            broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count);
+
     /* Test VOLUME_NAME_DOS with sufficient buffer size */
     memset(result_path, 0x11, sizeof(result_path));
     count = pGetFinalPathNameByHandleW(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index c06ecd9..b9e95ca 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -235,8 +235,8 @@
 @ stdcall GetFileSizeEx(long ptr) kernel32.GetFileSizeEx
 @ stdcall GetFileTime(long ptr ptr ptr) kernel32.GetFileTime
 @ stdcall GetFileType(long) kernel32.GetFileType
-@ stub GetFinalPathNameByHandleA
-@ stub GetFinalPathNameByHandleW
+@ stdcall GetFinalPathNameByHandleA(long ptr long long) kernel32.GetFinalPathNameByHandleA
+@ stdcall GetFinalPathNameByHandleW(long ptr long long) kernel32.GetFinalPathNameByHandleW
 @ stdcall GetFullPathNameA(str long ptr ptr) kernel32.GetFullPathNameA
 @ stdcall GetFullPathNameW(wstr long ptr ptr) kernel32.GetFullPathNameW
 @ stdcall GetHandleInformation(long ptr) kernel32.GetHandleInformation
-- 
2.8.0




More information about the wine-patches mailing list