From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/tests/path.c | 287 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+)
diff --git a/dlls/dbghelp/tests/path.c b/dlls/dbghelp/tests/path.c index 781df3dd771..791064d05bb 100644 --- a/dlls/dbghelp/tests/path.c +++ b/dlls/dbghelp/tests/path.c @@ -926,6 +926,292 @@ static void test_srvgetindexes_dbg(void) } }
+static void make_path(WCHAR file[MAX_PATH], const WCHAR* topdir, const WCHAR* subdir, const WCHAR* base) +{ + wcscpy(file, topdir); + if (subdir) + { + if (file[wcslen(file) - 1] != '\') wcscat(file, L"\"); + wcscat(file, subdir); + } + if (base) + { + if (file[wcslen(file) - 1] != '\') wcscat(file, L"\"); + wcscat(file, base); + } +} + +struct path_validate +{ + DWORD timestamp; + DWORD size_of_image; + unsigned cb_count; +}; + +static BOOL CALLBACK path_cb(PCWSTR filename, void* _usr) +{ + struct path_validate* pv = _usr; + SYMSRV_INDEX_INFOW ssii; + BOOL ret; + + pv->cb_count++; + /* wine returns paths in relative form, but relative to search path... + * fail (== continue search) until it's fixed + */ + todo_wine_if(!filename[0] || filename[1] != ':') + ok(filename[0] && filename[1] == ':', "Expecting full path, but got %ls\n", filename); + if (!filename[0] || filename[1] != ':') return TRUE; + + memset(&ssii, 0, sizeof(ssii)); + ssii.sizeofstruct = sizeof(ssii); + ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0); + ok(ret, "SymSrvGetFileIndexInfo failed: %lu %ls\n", GetLastError(), filename); + return !(ret && ssii.timestamp == pv->timestamp && ssii.size == pv->size_of_image); +} + +static unsigned char2index(char ch) +{ + unsigned val; + if (ch >= '0' && ch <= '9') + val = ch - '0'; + else if (ch >= 'a' && ch <= 'z') + val = 10 + ch - 'a'; + else val = ~0u; + return val; +} + +/* Despite what MS documentation states, option EXACT_SYMBOLS doesn't always work + * (it looks like it's only enabled when symsrv.dll is loaded). + * So, we don't test with EXACT_SYMBOLS set, nor with a NULL callback, and defer + * to our own custom callback the testing. + * (We always end when a full matched is found). + */ +static void test_find_in_path_pe(void) +{ + HANDLE proc = (HANDLE)(DWORD_PTR)0x666002; + WCHAR topdir[MAX_PATH]; + WCHAR search[MAX_PATH]; + WCHAR file[MAX_PATH]; + WCHAR found[MAX_PATH]; + struct path_validate pv; + DWORD len; + BOOL ret; + int i; + union nt_header hdr; + + static const struct file_tests + { + unsigned bitness; /* 32 or 64 */ + DWORD timestamp; + DWORD size_of_image; + const WCHAR* module_path; + } + file_tests[] = + { + /* 0 */ { 64, 0x12345678, 0x0030cafe, L"foobar.dll" }, + /* 1 */ { 64, 0x12345678, 0x0030cafe, L"A\foobar.dll" }, + /* 2 */ { 64, 0x12345678, 0x0030cafe, L"B\foobar.dll" }, + /* 3 */ { 64, 0x56781234, 0x0010f00d, L"foobar.dll" }, + /* 4 */ { 64, 0x56781234, 0x0010f00d, L"A\foobar.dll" }, + /* 5 */ { 64, 0x56781234, 0x0010f00d, L"B\foobar.dll" }, + /* 6 */ { 32, 0x12345678, 0x0030cafe, L"foobar.dll" }, + /* 7 */ { 32, 0x12345678, 0x0030cafe, L"A\foobar.dll" }, + /* 8 */ { 32, 0x12345678, 0x0030cafe, L"B\foobar.dll" }, + /* 9 */ { 32, 0x56781234, 0x0010f00d, L"foobar.dll" }, + /* a */ { 32, 0x56781234, 0x0010f00d, L"A\foobar.dll" }, + /* b */ { 32, 0x56781234, 0x0010f00d, L"B\foobar.dll" }, + }; + static const struct image_tests + { + /* files to generate */ + const char* files; + /* parameters for lookup */ + DWORD lookup_timestamp; + DWORD lookup_size_of_image; + const char* search; /* several of ., A, B to link to directories */ + const WCHAR* module; + /* expected results */ + const WCHAR* found_subdir; + DWORD expected_cb_count; + } + image_tests[] = + { + /* all files 64 bit */ + /* the passed timestamp & size are not checked before calling the callback! */ + /* 0 */ { "0", 0x00000000, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 1 */ { "0", 0x12345678, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 2 */ { "0", 0x00000000, 0x0030cafe, ".", L"foobar.dll", NULL, 1}, + /* 3 */ { "0", 0x12345678, 0x0030cafe, ".", L"foobar.dll", L"", 1}, + /* no recursion into subdirectories */ + /* 4 */ { "1", 0x12345678, 0x0030cafe, ".", L"foobar.dll", NULL, 0}, + /* directories are searched in order */ + /* 5 */ { "15", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 6 */ { "15", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\", 2}, + /* 7 */ { "12", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 8 */ { "12", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\", 1}, + + /* all files 32 bit */ + /* the passed timestamp & size is not checked ! */ + /* 9 */ { "6", 0x00000000, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 10 */ { "6", 0x12345678, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 11 */ { "6", 0x00000000, 0x0030cafe, ".", L"foobar.dll", NULL, 1}, + /* 12 */ { "6", 0x12345678, 0x0030cafe, ".", L"foobar.dll", L"", 1}, + /* no recursion into subdirectories */ + /* 13 */ { "7", 0x12345678, 0x0030cafe, ".", L"foobar.dll", NULL, 0}, + /* directories are searched in order */ + /* 14 */ { "7b", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 15 */ { "7b", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\", 2}, + /* 16 */ { "78", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 17 */ { "78", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\", 1}, + + /* machine and bitness is not used */ + /* 18 */ { "1b", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 19 */ { "1b", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\", 2}, + /* 20 */ { "18", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 21 */ { "18", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\", 1}, + /* 22 */ { "75", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 23 */ { "75", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\", 2}, + /* 24 */ { "72", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\", 1}, + /* 25 */ { "72", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\", 1}, + + /* specifying a full path to module isn't taken into account */ + /* 26 */ { "0", 0x12345678, 0x0030cafe, "AB", L"@foobar.dll", NULL, 0}, + /* 27 */ { "6", 0x12345678, 0x0030cafe, "AB", L"@foobar.dll", NULL, 0}, + + }; + static const WCHAR* list_directories[] = {L"A", L"B", L"dll", L"symbols", L"symbols\dll", L"acm", L"symbols\acm"}; + + ret = SymInitializeW(proc, NULL, FALSE); + ok(ret, "Couldn't init dbghelp\n"); + + len = GetTempPathW(ARRAY_SIZE(topdir), topdir); + ok(len && len < ARRAY_SIZE(topdir), "Unexpected length\n"); + wcscat(topdir, L"dh.tmp\"); + ret = CreateDirectoryW(topdir, NULL); + ok(ret, "Couldn't create directory\n"); + for (i = 0; i < ARRAY_SIZE(list_directories); i++) + { + make_path(file, topdir, list_directories[i], NULL); + ret = CreateDirectoryW(file, NULL); + ok(ret, "Couldn't create directory %u %ls\n", i, list_directories[i]); + } + + for (i = 0; i < ARRAY_SIZE(image_tests); ++i) + { + const char* ptr; + winetest_push_context("%u", i); + + for (ptr = image_tests[i].files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(file_tests)) + { + const struct file_tests* ft = &file_tests[val]; + struct debug_directory_blob* ds_blob; + + make_path(file, topdir, NULL, ft->module_path); + /* all modules created with ds pdb reference so that SymSrvGetFileInfoInfo() succeeds */ + ds_blob = make_pdb_ds_blob(ft->timestamp, &guid1, 124, "pdbds.pdb"); + if (ft->bitness == 64) + { + init_headers64(&hdr.nt_header64, ft->timestamp, ft->size_of_image, 0); + create_test_dll(&hdr, sizeof(hdr.nt_header64), &ds_blob, 1, file); + } + else + { + init_headers32(&hdr.nt_header32, ft->timestamp, ft->size_of_image, 0); + create_test_dll(&hdr, sizeof(hdr.nt_header32), &ds_blob, 1, file); + } + free(ds_blob); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + search[0] = L'\0'; + for (ptr = image_tests[i].search; *ptr; ptr++) + { + if (*search) wcscat(search, L";"); + wcscat(search, topdir); + if (*ptr == '.') + ; + else if (*ptr == 'A') + wcscat(search, L"A"); + else if (*ptr == 'B') + wcscat(search, L"B"); + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + if (image_tests[i].module[0] == L'@') + make_path(file, topdir, NULL, &image_tests[i].module[1]); + else + wcscpy(file, image_tests[i].module); + + pv.timestamp = image_tests[i].lookup_timestamp; + pv.size_of_image = image_tests[i].lookup_size_of_image; + pv.cb_count = 0; + memset(found, 0, sizeof(found)); + + ret = SymFindFileInPathW(proc, search, file, + (void*)&image_tests[i].lookup_timestamp, + image_tests[i].lookup_size_of_image, 0, + SSRVOPT_DWORDPTR, found, path_cb, &pv); + + todo_wine + ok(pv.cb_count == image_tests[i].expected_cb_count, + "Mismatch in cb count, got %u (expected %lu)\n", + pv.cb_count, image_tests[i].expected_cb_count); + if (image_tests[i].found_subdir) + { + size_t l1, l2, l3; + + ok(ret, "Couldn't find file: %ls %lu\n", search, GetLastError()); + + l1 = wcslen(topdir); + l2 = wcslen(image_tests[i].found_subdir); + l3 = wcslen(image_tests[i].module); + + ok(l1 + l2 + l3 == wcslen(found) && + !memcmp(found, topdir, l1 * sizeof(WCHAR)) && + !memcmp(&found[l1], image_tests[i].found_subdir, l2 * sizeof(WCHAR)) && + !memcmp(&found[l1 + l2], image_tests[i].module, l3 * sizeof(WCHAR)), + "Mismatch in found file %ls (expecting %ls)\n", + found, image_tests[i].found_subdir); + } + else + { + todo_wine_if(i == 26 || i == 27) + ok(!ret, "File reported found, while failure is expected\n"); + todo_wine_if(i == 26 || i == 27 || (GetLastError() != ERROR_FILE_NOT_FOUND)) + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Unexpected error %lu\n", GetLastError()); + } + for (ptr = image_tests[i].files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(file_tests)) + { + const struct file_tests* ft = &file_tests[val]; + make_path(file, topdir, NULL, ft->module_path); + ret = DeleteFileW(file); + ok(ret, "Couldn't delete file %c %ls\n", *ptr, file); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + winetest_pop_context(); + } + + SymCleanup(proc); + + for (i = ARRAY_SIZE(list_directories) - 1; i >= 0; i--) + { + make_path(file, topdir, list_directories[i], NULL); + ret = RemoveDirectoryW(file); + ok(ret, "Couldn't remove directory %u %ls\n", i, list_directories[i]); + } + + ret = RemoveDirectoryW(topdir); + ok(ret, "Couldn't remove directory\n"); +} + START_TEST(path) { /* cleanup env variables that affect dbghelp's behavior */ @@ -935,4 +1221,5 @@ START_TEST(path) test_srvgetindexes_pe(); test_srvgetindexes_pdb(); test_srvgetindexes_dbg(); + test_find_in_path_pe(); }