kernel32: Implement GetFinalPathNameByHandle.

Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Michael Müller 2016-04-07 10:28:52 -05:00 committed by Alexandre Julliard
parent f5ca9b9104
commit 6e12aba9c7
7 changed files with 261 additions and 10 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 = 0;
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;
}

View File

@ -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)

View File

@ -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", lstrlenA(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", lstrlenA(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);

View File

@ -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