[PATCH] kernel32: Implement GetFinalPathNameByHandle

Andrew Eikum aeikum at codeweavers.com
Thu Mar 19 10:22:20 CDT 2015


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




More information about the wine-patches mailing list