[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