Hi, I have written a patch to add basic UNC pathname support which tries to handle UNC pathnames according to the MSDN spec.
The patch satisfies some of the UNC pathname tests for GetLongPathNameA, but is actually intended to fix GetLongPathNameW. I am not entirely satisfied with the patch, and would appreciate some comments. Some issues: 1) Paths prefixed by '\\?\' require GetLongPathName to handle strings of length 32767. I don't like the fact that the patch creates two such large strings on the local stack, should the memory be dynamically allocated only when needed? 2) The handling of shares \\hostname\C$ is implemented, but no other shares are handled. And even in this case, only the host on which wine is executed is handled, no other hosts are handled. I have read that Windows 7 disables this share by default. So should wine be handling this particular URL, or should more general sharing be implemented? The patch is included as an attachment to this message. Kind regards Alexandre -- -------------------------------------------------- Alexandre Hardy http://www.ahardy.za.net
From b013419f366c83248704f444cbbb6976df740fc9 Mon Sep 17 00:00:00 2001 From: Alexandre Hardy <alexandre.ha...@gmail.com> Date: Fri, 11 Dec 2009 09:49:59 +0200 Subject: Add partial UNC pathname support --- dlls/kernel32/path.c | 54 +++++++++++++++++++++++++++++++++++++++++-- dlls/kernel32/tests/path.c | 4 --- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c index e9463bb..54d9403 100644 --- a/dlls/kernel32/path.c +++ b/dlls/kernel32/path.c @@ -44,6 +44,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(file); #define MAX_PATHNAME_LEN 1024 +#define MAX_LONGPATHNAME_LEN 32767 /* check if a file name is for an executable file (.exe or .com) */ @@ -290,19 +291,29 @@ DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, */ DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) { - WCHAR tmplongpath[MAX_PATHNAME_LEN]; + WCHAR tmplongpath[MAX_LONGPATHNAME_LEN]; + WCHAR sharename[MAX_LONGPATHNAME_LEN]; LPCWSTR p; DWORD sp = 0, lp = 0; DWORD tmplen; + DWORD hostlen; BOOL unixabsolute; WIN32_FIND_DATAW wfd; HANDLE goit; + WCHAR cdollar[4] = { '\\', 'C', '$', 0 }; + WCHAR c_colon[3] = { 'C', ':', 0 }; + BOOL ret; if (!shortpath) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } + if (!longpath && longlen) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } if (!shortpath[0]) { SetLastError(ERROR_PATH_NOT_FOUND); @@ -314,8 +325,45 @@ DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen if (shortpath[0] == '\\' && shortpath[1] == '\\') { ERR("UNC pathname %s\n", debugstr_w(shortpath)); - lstrcpynW( longpath, shortpath, longlen ); - return strlenW(longpath); + + /* Handle extended length path */ + if (shortpath[2] == '?' && shortpath[3] == '\\') { + tmplen = GetLongPathNameW(shortpath + 4, tmplongpath, MAX_LONGPATHNAME_LEN); + if (tmplen + 5 <= longlen) { + lstrcpynW(longpath, shortpath, 5); + lstrcatW(longpath, tmplongpath); + return tmplen + 4; + } else + return tmplen + 5; + } + + /* Handle only our host name\C$ for network shares*/ + hostlen = MAX_COMPUTERNAME_LENGTH + 1; + ret = GetComputerNameW(sharename, &hostlen); + if (ret) { + lstrcatW(sharename, cdollar); + if (strncmpW(sharename, shortpath + 2, hostlen + 3) == 0) { + lstrcpyW(sharename, c_colon); + lstrcatW(sharename, shortpath + 5 + hostlen); + tmplen = GetLongPathNameW(sharename, tmplongpath, MAX_LONGPATHNAME_LEN); + if (tmplen + hostlen + 4 <= longlen) { + lstrcpynW(longpath, shortpath, hostlen + 4); + lstrcatW(longpath, tmplongpath); + longpath[hostlen + 4] = '$'; + return tmplen + hostlen + 2; + } else + return tmplen + hostlen + 3; + } + } + + /* Can't handle shares at the moment, just copy the filename + * But only if there is enough space in the buffer */ + tmplen = strlenW(shortpath); + if (longlen >= tmplen + 1) { + lstrcpynW( longpath, shortpath, longlen ); + return tmplen; + } + return tmplen + 1; } unixabsolute = (shortpath[0] == '/'); diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c index 104a48c..86207ce 100644 --- a/dlls/kernel32/tests/path.c +++ b/dlls/kernel32/tests/path.c @@ -1036,17 +1036,14 @@ static void test_GetLongPathNameA(void) return; } explength = lstrlenA(longpath) + 1; - todo_wine ok(length == explength, "Wrong length %d, expected %d\n", length, explength); length = pGetLongPathNameA(unc_short, NULL, MAX_PATH); - todo_wine ok(length == explength, "Wrong length %d, expected %d\n", length, explength); memset(unc_long, 0, MAX_PATH); length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short)); /* length will include terminating '0' on failure */ - todo_wine ok(length == explength, "Wrong length %d, expected %d\n", length, explength); ok(unc_long[0] == 0, "Buffer should not have been touched\n"); @@ -1054,7 +1051,6 @@ static void test_GetLongPathNameA(void) length = pGetLongPathNameA(unc_short, unc_long, length); /* length doesn't include terminating '0' on success */ explength--; - todo_wine { ok(length == explength, "Wrong length %d, expected %d\n", length, explength); ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long); -- 1.6.2.1