kernel32: Implement GetFinalPathNameByHandle.
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f5ca9b9104
commit
6e12aba9c7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue