From: Andrew Eikum Subject: [PATCH] kernel32: Implement GetFinalPathNameByHandle Message-Id: <20150319152220.GX2076@foghorn.codeweavers.com> Date: Thu, 19 Mar 2015 10:22:20 -0500 --- dlls/kernel32/kernel32.spec | 4 +- dlls/kernel32/path.c | 97 +++++++++++++++++++++++++++++++++++++++++++++ dlls/kernel32/tests/file.c | 88 ++++++++++++++++++++++++++++++++++++++++ include/winbase.h | 2 + 4 files changed, 189 insertions(+), 2 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index c95c446..26c7657 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/path.c b/dlls/kernel32/path.c index c2833b1..ffbd486 100644 --- a/dlls/kernel32/path.c +++ b/dlls/kernel32/path.c @@ -1994,3 +1994,100 @@ BOOL WINAPI CreateHardLinkTransactedW(LPCWSTR link, LPCWSTR target, LPSECURITY_A SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } + +/************************************************************************* + * GetFinalPathNameByHandleA (KERNEL32.@) + */ +DWORD WINAPI GetFinalPathNameByHandleA(HANDLE handle, char *outstr, DWORD len, + DWORD flags) +{ + WCHAR *wstr; + DWORD dw; + + if (len > 0) + { + wstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if (!wstr) + { + SetLastError( ERROR_OUTOFMEMORY ); + return 0; + } + } + else + wstr = NULL; + + dw = GetFinalPathNameByHandleW( handle, wstr, len, flags ); + + if (dw > 0 && dw < len) + { + /* success */ + + dw = WideCharToMultiByte( CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL ); + if (dw > len) + { + /* buffer too small */ + HeapFree( GetProcessHeap(), 0, wstr ); + return dw; + } + + dw = WideCharToMultiByte( CP_ACP, 0, wstr, -1, outstr, len, NULL, NULL ); + if (!dw) + { + HeapFree( GetProcessHeap(), 0, wstr ); + return 0; + } + + /* don't report NUL */ + dw = dw - 1; + } + + HeapFree( GetProcessHeap(), 0, wstr ); + + return dw; +} + +/************************************************************************* + * GetFinalPathNameByHandleW (KERNEL32.@) + */ +DWORD WINAPI GetFinalPathNameByHandleW(HANDLE handle, WCHAR *outstr, DWORD len, + DWORD flags) +{ + FILE_NAME_INFORMATION *info; + char data[MAX_PATH * sizeof(WCHAR) + sizeof(info->FileNameLength)]; + UNICODE_STRING nt_name; + BOOL br; + DWORD name_wchars; + + TRACE( "%p %p %u 0x%x\n", handle, outstr, len, flags ); + + if (flags) + FIXME( "Unimplemented flags: 0x%x\n", flags ); + + info = (FILE_NAME_INFORMATION*)data; + + br = GetFileInformationByHandleEx( handle, FileNameInfo, data, sizeof(data) ); + if (!br) + return 0; + + info->FileName[info->FileNameLength / sizeof(WCHAR)] = 0; + if (!RtlDosPathNameToNtPathName_U( info->FileName, &nt_name, NULL, NULL )) + { + SetLastError( ERROR_PATH_NOT_FOUND ); + return 0; + } + + name_wchars = nt_name.Length / sizeof(WCHAR); + if (name_wchars + 1 > len) + { + RtlFreeUnicodeString( &nt_name ); + return name_wchars + 1; + } + + memcpy( outstr, nt_name.Buffer, nt_name.Length ); + outstr[name_wchars] = 0; + outstr[1] = '\\'; /* convert \??\ to \\?\ */ + + RtlFreeUnicodeString( &nt_name ); + + return name_wchars; +} diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 8849eb3..424b035 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -46,6 +46,8 @@ static HANDLE (WINAPI *pOpenFileById)(HANDLE, LPFILE_ID_DESCRIPTOR, DWORD, DWORD static BOOL (WINAPI *pSetFileValidData)(HANDLE, LONGLONG); static HRESULT (WINAPI *pCopyFile2)(PCWSTR,PCWSTR,COPYFILE2_EXTENDED_PARAMETERS*); static HANDLE (WINAPI *pCreateFile2)(LPCWSTR, DWORD, DWORD, DWORD, CREATEFILE2_EXTENDED_PARAMETERS*); +static DWORD (WINAPI *pGetFinalPathNameByHandleW)(HANDLE, WCHAR *, DWORD, DWORD); +static DWORD (WINAPI *pGetFinalPathNameByHandleA)(HANDLE, char *, DWORD, DWORD); static const char filename[] = "testfile.xxx"; static const char sillytext[] = @@ -83,6 +85,8 @@ static void InitFunctionPointers(void) pSetFileValidData = (void *) GetProcAddress(hkernel32, "SetFileValidData"); pCopyFile2 = (void *) GetProcAddress(hkernel32, "CopyFile2"); pCreateFile2 = (void *) GetProcAddress(hkernel32, "CreateFile2"); + pGetFinalPathNameByHandleW = (void *) GetProcAddress(hkernel32, "GetFinalPathNameByHandleW"); + pGetFinalPathNameByHandleA = (void *) GetProcAddress(hkernel32, "GetFinalPathNameByHandleA"); } static void test__hread( void ) @@ -3755,6 +3759,89 @@ static void test_GetFileInformationByHandleEx(void) DeleteFileA(tempFileName); } +static void test_GetFinalPathNameByHandle(void) +{ + char tempPath[MAX_PATH], tempFileName[MAX_PATH], bufferA[MAX_PATH]; + WCHAR buffer[MAX_PATH]; + DWORD ret, len; + HANDLE tmpfile, h2; + + if (!pGetFinalPathNameByHandleW) + { + win_skip("GetFinalPathNameByHandle is missing.\n"); + return; + } + + SetLastError(0); + ret = pGetFinalPathNameByHandleW(NULL, NULL, 0, 0); + ok(ret == 0, "GetFinalPathNameByHandle should have failed\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Got wrong error: %u\n", GetLastError()); + + SetLastError(0); + ret = pGetFinalPathNameByHandleW(INVALID_HANDLE_VALUE, NULL, 0, 0); + ok(ret == 0, "GetFinalPathNameByHandle should have failed\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Got wrong error: %u\n", GetLastError()); + + ret = GetTempPathA(sizeof(tempPath), tempPath); + ok(ret, "GetTempPathA failed, got error %u.\n", GetLastError()); + + /* ensure the existence of a file in the temp folder */ + ret = GetTempFileNameA(tempPath, "abc", 0, tempFileName); + ok(ret, "GetTempFileNameA failed, got error %u.\n", GetLastError()); + ret = GetFileAttributesA(tempFileName); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA failed to find the temp file, got error %u.\n", GetLastError()); + + /* open file exclusively */ + tmpfile = CreateFileA(tempFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(tmpfile != INVALID_HANDLE_VALUE, "CreateFile failed\n"); + + /* return value seems broken */ + len = pGetFinalPathNameByHandleW(tmpfile, NULL, 0, 0); + ok(len > 0, "GetFinalPathNameByHandle didn't give buffer size\n"); + + ret = pGetFinalPathNameByHandleW(tmpfile, buffer, 0, 0); + ok(len == ret, "Got wrong filename length: %u != %u\n", ret, len); + + memset(buffer, 0, sizeof(buffer)); + ret = pGetFinalPathNameByHandleW(tmpfile, buffer, 1, 0); + ok(ret == len - 1 || ret == len, "Got wrong filename length: %u != %u or %u\n", ret, len, len - 1); + ok(buffer[0] == 0, "Got a string?\n"); + + memset(buffer, 0, sizeof(buffer)); + ret = pGetFinalPathNameByHandleW(tmpfile, buffer, len - 2, 0); + ok(ret == len - 1 || ret == len, "Got wrong filename length: %u != %u or %u\n", ret, len, len - 1); + ok(buffer[0] == 0, "Got a string?\n"); + + memset(buffer, 0, sizeof(buffer)); + ret = pGetFinalPathNameByHandleW(tmpfile, buffer, len - 1, 0); + ok((ret == len - 2 && buffer[0] != 0) || + (ret == len && buffer[0] == 0), "Got unexpected return value: %u\n", ret); + + memset(buffer, 0, sizeof(buffer)); + ret = pGetFinalPathNameByHandleW(tmpfile, buffer, len, 0); + ok(ret == len - 2 || ret == len - 1, "Got wrong filename length: %u != %u or %u\n", ret, len - 2, len - 1); + ok(buffer[0] != 0, "Got empty string?\n"); + + memset(bufferA, 0, sizeof(bufferA)); + ret = pGetFinalPathNameByHandleA(tmpfile, bufferA, len, 0); + ok(ret == len - 2 || ret == len - 1, "Got wrong filename length: %u != %u or %u\n", ret, len - 2, len - 1); + ok(bufferA[0] != 0, "Got empty string?\n"); + + /* try to open the same file, should fail */ + h2 = CreateFileW(buffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(h2 == INVALID_HANDLE_VALUE, "CreateFile should have failed\n"); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "Got wrong lasterror: %u (%s)\n", GetLastError(), wine_dbgstr_w(buffer)); + + CloseHandle(tmpfile); + DeleteFileA(tempFileName); + + ret = pGetFinalPathNameByHandleW(tmpfile, buffer, sizeof(buffer) / sizeof(WCHAR), 0); + ok(ret == 0, "Invalid HANDLE should have failed\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Got wrong error: %u\n", GetLastError()); +} + static void test_OpenFileById(void) { char tempPath[MAX_PATH], tempFileName[MAX_PATH], buffer[256], tickCount[256]; @@ -4230,6 +4317,7 @@ START_TEST(file) test_ReplaceFileA(); test_ReplaceFileW(); test_GetFileInformationByHandleEx(); + test_GetFinalPathNameByHandle(); test_OpenFileById(); test_SetFileValidData(); test_WriteFileGather(); diff --git a/include/winbase.h b/include/winbase.h index 1eb49b3..860a8e8 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1923,6 +1923,8 @@ WINBASEAPI DWORD WINAPI GetFileSize(HANDLE,LPDWORD); WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE,PLARGE_INTEGER); WINBASEAPI BOOL WINAPI GetFileTime(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME); WINBASEAPI DWORD WINAPI GetFileType(HANDLE); +WINBASEAPI DWORD WINAPI GetFinalPathNameByHandleA(HANDLE,LPSTR,DWORD,DWORD); +WINBASEAPI DWORD WINAPI GetFinalPathNameByHandleW(HANDLE,LPWSTR,DWORD,DWORD); #define GetFreeSpace(w) (__MSABI_LONG(0x100000)) WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR,DWORD,LPSTR,LPSTR*); WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR,DWORD,LPWSTR,LPWSTR*); -- 2.3.3