kernelbase: Implement PathAllocCanonicalize.
Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d381263ae5
commit
165f777c38
|
@ -1,4 +1,4 @@
|
|||
@ stub PathAllocCanonicalize
|
||||
@ stdcall PathAllocCanonicalize(wstr long ptr) kernelbase.PathAllocCanonicalize
|
||||
@ stub PathAllocCombine
|
||||
@ stdcall PathCchAddBackslash(wstr long) kernelbase.PathCchAddBackslash
|
||||
@ stdcall PathCchAddBackslashEx(wstr long ptr ptr) kernelbase.PathCchAddBackslashEx
|
||||
|
|
|
@ -1023,7 +1023,7 @@
|
|||
@ stdcall PathAddBackslashW(wstr) shlwapi.PathAddBackslashW
|
||||
@ stdcall PathAddExtensionA(str str) shlwapi.PathAddExtensionA
|
||||
@ stdcall PathAddExtensionW(wstr wstr) shlwapi.PathAddExtensionW
|
||||
# @ stub PathAllocCanonicalize
|
||||
@ stdcall PathAllocCanonicalize(wstr long ptr)
|
||||
# @ stub PathAllocCombine
|
||||
@ stdcall PathAppendA(str str) shlwapi.PathAppendA
|
||||
@ stdcall PathAppendW(wstr wstr) shlwapi.PathAppendW
|
||||
|
|
|
@ -126,6 +126,188 @@ static const WCHAR *get_root_end(const WCHAR *path)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **path_out)
|
||||
{
|
||||
WCHAR *buffer, *dst;
|
||||
const WCHAR *src;
|
||||
const WCHAR *root_end;
|
||||
SIZE_T buffer_size, length;
|
||||
|
||||
TRACE("%s %#x %p\n", debugstr_w(path_in), flags, path_out);
|
||||
|
||||
if (!path_in || !path_out
|
||||
|| ((flags & PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS) && (flags & PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS))
|
||||
|| (flags & (PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS)
|
||||
&& !(flags & PATHCCH_ALLOW_LONG_PATHS))
|
||||
|| ((flags & PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH) && (flags & PATHCCH_ALLOW_LONG_PATHS)))
|
||||
{
|
||||
if (path_out) *path_out = NULL;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
length = strlenW(path_in);
|
||||
if ((length + 1 > MAX_PATH && !(flags & (PATHCCH_ALLOW_LONG_PATHS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH)))
|
||||
|| (length + 1 > PATHCCH_MAX_CCH))
|
||||
{
|
||||
*path_out = NULL;
|
||||
return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
|
||||
}
|
||||
|
||||
/* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH implies PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
|
||||
if (flags & PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH) flags |= PATHCCH_DO_NOT_NORMALIZE_SEGMENTS;
|
||||
|
||||
/* path length + possible \\?\ addition + possible \ addition + NUL */
|
||||
buffer_size = (length + 6) * sizeof(WCHAR);
|
||||
buffer = LocalAlloc(LMEM_ZEROINIT, buffer_size);
|
||||
if (!buffer)
|
||||
{
|
||||
*path_out = NULL;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
src = path_in;
|
||||
dst = buffer;
|
||||
|
||||
root_end = get_root_end(path_in);
|
||||
if (root_end) root_end = buffer + (root_end - path_in);
|
||||
|
||||
/* Copy path root */
|
||||
if (root_end)
|
||||
{
|
||||
memcpy(dst, src, (root_end - buffer + 1) * sizeof(WCHAR));
|
||||
src += root_end - buffer + 1;
|
||||
if(PathCchStripPrefix(dst, length + 6) == S_OK)
|
||||
{
|
||||
/* Fill in \ in X:\ if the \ is missing */
|
||||
if(isalphaW(dst[0]) && dst[1] == ':' && dst[2]!= '\\')
|
||||
{
|
||||
dst[2] = '\\';
|
||||
dst[3] = 0;
|
||||
}
|
||||
dst = buffer + strlenW(buffer);
|
||||
root_end = dst;
|
||||
}
|
||||
else
|
||||
dst += root_end - buffer + 1;
|
||||
}
|
||||
|
||||
while (*src)
|
||||
{
|
||||
if (src[0] == '.')
|
||||
{
|
||||
if (src[1] == '.')
|
||||
{
|
||||
/* Keep one . after * */
|
||||
if (dst > buffer && dst[-1] == '*')
|
||||
{
|
||||
*dst++ = *src++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Keep the . if one of the following is true:
|
||||
* 1. PATHCCH_DO_NOT_NORMALIZE_SEGMENTS
|
||||
* 2. in form of a..b
|
||||
*/
|
||||
if (dst > buffer
|
||||
&& (((flags & PATHCCH_DO_NOT_NORMALIZE_SEGMENTS) && dst[-1] != '\\')
|
||||
|| (dst[-1] != '\\' && src[2] != '\\' && src[2])))
|
||||
{
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remove the \ before .. if the \ is not part of root */
|
||||
if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end))
|
||||
{
|
||||
*--dst = '\0';
|
||||
/* Remove characters until a \ is encountered */
|
||||
while (dst > buffer)
|
||||
{
|
||||
if (dst[-1] == '\\')
|
||||
{
|
||||
*--dst = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
*--dst = 0;
|
||||
}
|
||||
}
|
||||
/* Remove the extra \ after .. if the \ before .. wasn't deleted */
|
||||
else if (src[2] == '\\')
|
||||
src++;
|
||||
|
||||
src += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Keep the . if one of the following is true:
|
||||
* 1. PATHCCH_DO_NOT_NORMALIZE_SEGMENTS
|
||||
* 2. in form of a.b, which is used in domain names
|
||||
* 3. *.
|
||||
*/
|
||||
if (dst > buffer
|
||||
&& ((flags & PATHCCH_DO_NOT_NORMALIZE_SEGMENTS && dst[-1] != '\\')
|
||||
|| (dst[-1] != '\\' && src[1] != '\\' && src[1]) || (dst[-1] == '*')))
|
||||
{
|
||||
*dst++ = *src++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remove the \ before . if the \ is not part of root */
|
||||
if (dst > buffer && dst[-1] == '\\' && (!root_end || dst - 1 > root_end)) dst--;
|
||||
/* Remove the extra \ after . if the \ before . wasn't deleted */
|
||||
else if (src[1] == '\\')
|
||||
src++;
|
||||
|
||||
src++;
|
||||
}
|
||||
|
||||
/* If X:\ is not complete, then complete it */
|
||||
if (isalphaW(buffer[0]) && buffer[1] == ':' && buffer[2] != '\\')
|
||||
{
|
||||
root_end = buffer + 2;
|
||||
dst = buffer + 3;
|
||||
buffer[2] = '\\';
|
||||
/* If next character is \, use the \ to fill in */
|
||||
if (src[0] == '\\') src++;
|
||||
}
|
||||
}
|
||||
/* Copy over */
|
||||
else
|
||||
*dst++ = *src++;
|
||||
}
|
||||
/* End the path */
|
||||
*dst = 0;
|
||||
|
||||
/* If result path is empty, fill in \ */
|
||||
if (!*buffer)
|
||||
{
|
||||
buffer[0] = '\\';
|
||||
buffer[1] = 0;
|
||||
}
|
||||
|
||||
/* Extend the path if needed */
|
||||
length = strlenW(buffer);
|
||||
if (((length + 1 > MAX_PATH && isalphaW(buffer[0]) && buffer[1] == ':')
|
||||
|| (isalphaW(buffer[0]) && buffer[1] == ':' && flags & PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH))
|
||||
&& !(flags & PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS))
|
||||
{
|
||||
memmove(buffer + 4, buffer, (length + 1) * sizeof(WCHAR));
|
||||
buffer[0] = '\\';
|
||||
buffer[1] = '\\';
|
||||
buffer[2] = '?';
|
||||
buffer[3] = '\\';
|
||||
}
|
||||
|
||||
/* Add a trailing backslash to the path if needed */
|
||||
if (flags & PATHCCH_ENSURE_TRAILING_SLASH)
|
||||
PathCchAddBackslash(buffer, buffer_size);
|
||||
|
||||
*path_out = buffer;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size)
|
||||
{
|
||||
return PathCchAddBackslashEx(path, size, NULL, NULL);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "wine/test.h"
|
||||
|
||||
HRESULT (WINAPI *pPathAllocCanonicalize)(const WCHAR *path_in, DWORD flags, WCHAR **path_out);
|
||||
HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size);
|
||||
HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining);
|
||||
HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
|
||||
|
@ -46,6 +47,309 @@ HRESULT (WINAPI *pPathCchStripPrefix)(WCHAR *path, SIZE_T size);
|
|||
HRESULT (WINAPI *pPathCchStripToRoot)(WCHAR *path, SIZE_T size);
|
||||
BOOL (WINAPI *pPathIsUNCEx)(const WCHAR *path, const WCHAR **server);
|
||||
|
||||
struct alloccanonicalize_test
|
||||
{
|
||||
const CHAR *path_in;
|
||||
const CHAR *path_out;
|
||||
DWORD flags;
|
||||
HRESULT hr;
|
||||
};
|
||||
|
||||
static const struct alloccanonicalize_test alloccanonicalize_tests[] =
|
||||
{
|
||||
/* Malformed path */
|
||||
{"C:a", "C:a", 0, S_OK},
|
||||
{"\\\\?\\C:", "C:\\", 0, S_OK},
|
||||
{"\\\\?C:\\a", "\\\\?C:\\a", 0, S_OK},
|
||||
{"\\\\?UNC\\a", "\\\\?UNC\\a", 0, S_OK},
|
||||
{"\\\\?\\UNCa", "\\\\?\\UNCa", 0, S_OK},
|
||||
{"\\\\?C:a", "\\\\?C:a", 0, S_OK},
|
||||
|
||||
/* No . */
|
||||
{"", "\\", 0, S_OK},
|
||||
{"C:", "C:", 0, S_OK},
|
||||
{"C:\\", "C:\\", 0, S_OK},
|
||||
{"\\\\?\\C:\\a", "C:\\a", 0, S_OK},
|
||||
{"\\\\?\\UNC\\a", "\\\\a", 0, S_OK},
|
||||
|
||||
/* . */
|
||||
{".", "\\", 0, S_OK},
|
||||
{"..", "\\", 0, S_OK},
|
||||
{"...", "\\", 0, S_OK},
|
||||
{"*.", "*.", 0, S_OK},
|
||||
{"*..", "*.", 0, S_OK},
|
||||
{"*...", "*.", 0, S_OK},
|
||||
{"a.", "a", 0, S_OK},
|
||||
{"a.b", "a.b", 0, S_OK},
|
||||
{"a\\.", "a", 0, S_OK},
|
||||
{"a\\.\\b", "a\\b", 0, S_OK},
|
||||
{"C:.", "C:\\", 0, S_OK},
|
||||
{"C:\\.", "C:\\", 0, S_OK},
|
||||
{"C:\\.\\", "C:\\", 0, S_OK},
|
||||
{"C:\\a.", "C:\\a", 0, S_OK},
|
||||
{"C:\\a\\.", "C:\\a", 0, S_OK},
|
||||
{"C:\\a\\\\.", "C:\\a\\", 0, S_OK},
|
||||
{"C:\\a\\\\\\.", "C:\\a\\\\", 0, S_OK},
|
||||
{"\\.", "\\", 0, S_OK},
|
||||
{"\\\\.", "\\\\", 0, S_OK},
|
||||
{"\\\\.\\", "\\\\", 0, S_OK},
|
||||
{"\\\\\\.", "\\\\", 0, S_OK},
|
||||
{"\\\\.\\\\", "\\\\\\", 0, S_OK},
|
||||
{"\\\\\\\\.", "\\\\\\", 0, S_OK},
|
||||
{"\\?\\.", "\\?", 0, S_OK},
|
||||
{"\\\\?\\.", "\\\\?", 0, S_OK},
|
||||
{"\\192.168.1.1\\a", "\\192.168.1.1\\a", 0, S_OK},
|
||||
{"\\a.168.1.1\\a", "\\a.168.1.1\\a", 0, S_OK},
|
||||
{"\\\\192.168.1.1\\a", "\\\\192.168.1.1\\a", 0, S_OK},
|
||||
{"\\\\a.168.1.1\\b", "\\\\a.168.1.1\\b", 0, S_OK},
|
||||
{"\\\\?\\C:.", "C:\\", 0, S_OK},
|
||||
{"\\\\?\\C:\\.", "C:\\", 0, S_OK},
|
||||
{"\\\\?\\UNC\\.", "\\\\", 0, S_OK},
|
||||
{"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\.",
|
||||
"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, S_OK},
|
||||
|
||||
/* .. */
|
||||
{"a..", "a", 0, S_OK},
|
||||
{"a..b", "a..b", 0, S_OK},
|
||||
{"a\\..", "\\", 0, S_OK},
|
||||
{"a\\..\\", "\\", 0, S_OK},
|
||||
{"a\\..\\b", "\\b", 0, S_OK},
|
||||
{"C:..", "C:\\", 0, S_OK},
|
||||
{"C:\\..", "C:\\", 0, S_OK},
|
||||
{"C:\\\\..", "C:\\", 0, S_OK},
|
||||
{"C:\\..\\", "C:\\", 0, S_OK},
|
||||
{"C:\\a\\..", "C:\\", 0, S_OK},
|
||||
{"C:\\a\\\\..", "C:\\a", 0, S_OK},
|
||||
{"C:\\a\\\\\\..", "C:\\a\\", 0, S_OK},
|
||||
{"C:\\a\\..\\b", "C:\\b", 0, S_OK},
|
||||
{"C:\\a\\..\\\\b", "C:\\\\b", 0, S_OK},
|
||||
{"\\..", "\\", 0, S_OK},
|
||||
{"\\\\..", "\\\\", 0, S_OK},
|
||||
{"\\\\\\..", "\\", 0, S_OK},
|
||||
{"\\\\..\\", "\\\\", 0, S_OK},
|
||||
{"\\\\\\..", "\\", 0, S_OK},
|
||||
{"\\\\..\\\\", "\\\\\\", 0, S_OK},
|
||||
{"\\\\\\\\..", "\\\\", 0, S_OK},
|
||||
{"\\?\\..", "\\", 0, S_OK},
|
||||
{"\\a\\..", "\\", 0, S_OK},
|
||||
{"\\\\?\\..", "\\", 0, S_OK},
|
||||
{"\\\\a\\..", "\\", 0, S_OK},
|
||||
{"\\a\\..\\b", "\\b", 0, S_OK},
|
||||
{"\\a\\b\\..", "\\a", 0, S_OK},
|
||||
{"\\?\\UNC\\..", "\\?", 0, S_OK},
|
||||
{"\\?\\C:\\..", "\\?", 0, S_OK},
|
||||
{"\\\\?\\C:..", "C:\\", 0, S_OK},
|
||||
{"\\\\?\\C:\\..", "C:\\", 0, S_OK},
|
||||
{"\\\\?\\UNC\\..", "\\\\", 0, S_OK},
|
||||
{"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}..",
|
||||
"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", 0, S_OK},
|
||||
{"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\..",
|
||||
"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, S_OK},
|
||||
{"\\\\?\\UNC\\a\\b\\..", "\\\\a", 0, S_OK},
|
||||
{"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b\\..",
|
||||
"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 0, S_OK},
|
||||
|
||||
/* . and .. */
|
||||
{"C:\\a\\.\\b\\..\\", "C:\\a\\", 0, S_OK},
|
||||
{"\\a\\.\\b\\..\\", "\\a\\", 0, S_OK},
|
||||
{"\\?\\a\\.\\b\\..\\", "\\?\\a\\", 0, S_OK},
|
||||
{"\\\\.\\a\\.\\b\\..\\", "\\\\a\\", 0, S_OK},
|
||||
{"\\\\?\\a\\.\\b\\..\\", "\\\\?\\a\\", 0, S_OK},
|
||||
{"\\\\.\\..", "\\\\", 0, S_OK},
|
||||
|
||||
/* PATHCCH_ALLOW_LONG_PATHS */
|
||||
/* Input path with prefix \\?\ and length of MAXPATH + 1, HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) = 0x800700ce */
|
||||
{"\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", NULL, 0, 0x800700ce},
|
||||
/* Input path with prefix C:\ and length of MAXPATH + 1 */
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", NULL, 0, 0x800700ce},
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
|
||||
/* Input path with prefix C: and length of MAXPATH + 1 */
|
||||
{"C:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
|
||||
/* Input path with prefix C:\ and length of MAXPATH + 1 and with .. */
|
||||
{"C:\\..\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
|
||||
/* Input path with prefix \\?\ and length of MAXPATH + 1 */
|
||||
{"\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
|
||||
/* Input path with prefix \ and length of MAXPATH + 1 */
|
||||
{"\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
|
||||
/* Input path with length of MAXPATH with PATHCCH_ALLOW_LONG_PATHS disabled*/
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, S_OK},
|
||||
/* Input path with length of MAXPATH */
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
|
||||
|
||||
/* Flags added after Windows 10 1709 */
|
||||
/* PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS */
|
||||
/* PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS without PATHCCH_ALLOW_LONG_PATHS */
|
||||
{"", NULL, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, E_INVALIDARG},
|
||||
/* Input path with prefix C:\ and length of MAXPATH + 1 and PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS */
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, S_OK},
|
||||
|
||||
/* PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
|
||||
/* PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS without PATHCCH_ALLOW_LONG_PATHS */
|
||||
{"", NULL, PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, E_INVALIDARG},
|
||||
/* Both PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
|
||||
{"", "\\", PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS,
|
||||
E_INVALIDARG},
|
||||
/* Input path with prefix C:\ and length of MAXPATH + 1 and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, S_OK},
|
||||
/* Input path with prefix C:\ and length of MAXPATH and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
|
||||
{"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, S_OK},
|
||||
|
||||
/* PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
|
||||
/* No effect for spaces */
|
||||
{"C:\\a \\", "C:\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a\\ ", "C:\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a ", "C:\\a ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a ", "C:\\a ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a. ", "C:\\a. ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"\\a \\", "\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"\\a\\ ", "\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"\\\\a \\", "\\\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"\\\\a\\ ", "\\\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"\\\\?\\ ", "\\\\?\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
/* Keep trailing dot */
|
||||
{"*..", "*..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{".", "\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"..", "\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:.", "C:.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:..", "C:..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a\\.", "C:\\a", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a\\..", "C:\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a.", "C:\\a.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
{"C:\\a..", "C:\\a..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
|
||||
|
||||
/* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH */
|
||||
{"C:\\a\\", "\\\\?\\C:\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
|
||||
{"", NULL, PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_ALLOW_LONG_PATHS, E_INVALIDARG},
|
||||
{"\\a\\", "\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
|
||||
{"\\\\?\\C:\\a\\", "\\\\?\\C:\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
|
||||
/* Implication of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS by PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH */
|
||||
{"\\a.", "\\a.", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
|
||||
|
||||
/* PATHCCH_ENSURE_TRAILING_SLASH */
|
||||
{"\\", "\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
|
||||
{"C:\\", "C:\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
|
||||
{"C:\\a\\.", "C:\\a\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
|
||||
{"C:\\a", "C:\\a\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK}
|
||||
};
|
||||
|
||||
static void test_PathAllocCanonicalize(void)
|
||||
{
|
||||
WCHAR path_inW[1024], path_maxW[PATHCCH_MAX_CCH + 1];
|
||||
WCHAR *path_outW;
|
||||
CHAR path_outA[1024];
|
||||
BOOL skip_new_flags = TRUE;
|
||||
HRESULT hr;
|
||||
INT i;
|
||||
|
||||
if (!pPathAllocCanonicalize)
|
||||
{
|
||||
win_skip("PathAllocCanonicalize() is not available.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* No NULL check for path on Windows */
|
||||
if (0)
|
||||
{
|
||||
hr = pPathAllocCanonicalize(NULL, 0, &path_outW);
|
||||
ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
|
||||
hr = pPathAllocCanonicalize(path_inW, 0, NULL);
|
||||
ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
|
||||
|
||||
/* Test longest path */
|
||||
for (i = 0; i < ARRAY_SIZE(path_maxW) - 1; i++) path_maxW[i] = 'a';
|
||||
path_maxW[PATHCCH_MAX_CCH] = '\0';
|
||||
path_outW = (WCHAR *)0xdeadbeef;
|
||||
hr = pPathAllocCanonicalize(path_maxW, PATHCCH_ALLOW_LONG_PATHS, &path_outW);
|
||||
ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
|
||||
HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
|
||||
ok(path_outW == NULL, "expect path_outW null, got %p\n", path_outW);
|
||||
|
||||
path_maxW[PATHCCH_MAX_CCH - 1] = '\0';
|
||||
hr = pPathAllocCanonicalize(path_maxW, PATHCCH_ALLOW_LONG_PATHS, &path_outW);
|
||||
ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
|
||||
|
||||
/* Check if flags added after Windows 10 1709 are supported */
|
||||
MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
|
||||
hr = pPathAllocCanonicalize(path_inW, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, &path_outW);
|
||||
if (hr == E_INVALIDARG) skip_new_flags = FALSE;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
|
||||
{
|
||||
const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
|
||||
|
||||
if (((PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
|
||||
| PATHCCH_DO_NOT_NORMALIZE_SEGMENTS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
|
||||
| PATHCCH_ENSURE_TRAILING_SLASH)
|
||||
& t->flags)
|
||||
&& skip_new_flags)
|
||||
{
|
||||
win_skip("Skip testing new flags added after Windows 10 1709\n");
|
||||
return;
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
|
||||
hr = pPathAllocCanonicalize(path_inW, t->flags, &path_outW);
|
||||
ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
|
||||
ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
|
||||
t->path_out, path_outA);
|
||||
LocalFree(path_outW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *path1;
|
||||
|
@ -1386,6 +1690,7 @@ START_TEST(path)
|
|||
{
|
||||
HMODULE hmod = LoadLibraryA("kernelbase.dll");
|
||||
|
||||
pPathAllocCanonicalize = (void *)GetProcAddress(hmod, "PathAllocCanonicalize");
|
||||
pPathCchCombineEx = (void *)GetProcAddress(hmod, "PathCchCombineEx");
|
||||
pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash");
|
||||
pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx");
|
||||
|
@ -1402,6 +1707,7 @@ START_TEST(path)
|
|||
pPathCchStripToRoot = (void *)GetProcAddress(hmod, "PathCchStripToRoot");
|
||||
pPathIsUNCEx = (void *)GetProcAddress(hmod, "PathIsUNCEx");
|
||||
|
||||
test_PathAllocCanonicalize();
|
||||
test_PathCchCombineEx();
|
||||
test_PathCchAddBackslash();
|
||||
test_PathCchAddBackslashEx();
|
||||
|
|
|
@ -22,9 +22,11 @@
|
|||
#define PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS 0x04
|
||||
#define PATHCCH_DO_NOT_NORMALIZE_SEGMENTS 0x08
|
||||
#define PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH 0x10
|
||||
#define PATHCCH_ENSURE_TRAILING_SLASH 0x20
|
||||
|
||||
#define PATHCCH_MAX_CCH 0x8000
|
||||
|
||||
HRESULT WINAPI PathAllocCanonicalize(const WCHAR *path_in, DWORD flags, WCHAR **path_out);
|
||||
HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size);
|
||||
HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **end, SIZE_T *remaining);
|
||||
HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension);
|
||||
|
|
Loading…
Reference in New Issue