From: Matteo Bruni Subject: [PATCH 4/4] ntdll/tests: Add a test for NtQueryDirectoryFile returning partial results. Message-Id: <1440702521-3673-4-git-send-email-mbruni@codeweavers.com> Date: Thu, 27 Aug 2015 21:08:41 +0200 --- dlls/ntdll/tests/directory.c | 169 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index 5850858..c83c91e 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -374,6 +374,174 @@ done: pRtlFreeUnicodeString(&ntdirname); } +static void set_up_partial_test(const char *testdir) +{ + static const char suffix[] = ".tmp"; + char buf[MAX_PATH], i; + BOOL ret; + HANDLE h; + + ret = CreateDirectoryA(testdir, NULL); + ok(ret, "Failed to create dir '%s', error %d.\n", testdir, GetLastError()); + + for (i = 'a'; i <= 'z'; i++) + { + sprintf(buf, "%s\\%c%s", testdir, i, suffix); + h = CreateFileA(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + ok(h != INVALID_HANDLE_VALUE, "failed to create temp file %s.\n", buf); + CloseHandle(h); + } +} + +static void tear_down_partial_test(const char *testdir) +{ + static const char suffix[] = ".tmp"; + char buf[MAX_PATH], i; + int ret; + + for (i = 'a'; i <= 'z'; i++) + { + sprintf(buf, "%s\\%c%s", testdir, i, suffix); + ret = DeleteFileA(buf); + ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), + "Failed to delete %s, error %d.\n", buf, GetLastError()); + } + RemoveDirectoryA(testdir); +} + +static void test_NtQueryDirectoryFile_partial(void) +{ + static const WCHAR dotdot[] = {'.','.'}; + static WCHAR testmask[] = {'*','.','*'}; + WCHAR testsuffix[] = {'.','t','m','p'}; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING ntdirname; + char testdir[MAX_PATH]; + WCHAR testdir_w[MAX_PATH]; + HANDLE dirh; + UNICODE_STRING mask; + IO_STATUS_BLOCK io; + UINT data_size = sizeof(FILE_BOTH_DIRECTORY_INFORMATION), data_len; + BYTE data[8192]; + FILE_BOTH_DIRECTORY_INFORMATION *dir_info = (FILE_BOTH_DIRECTORY_INFORMATION *)data; + DWORD status; + WCHAR *name; + ULONG name_len; + unsigned int found[28], i, data_pos; + BOOL overflow; + + /* Clean up from prior aborted run, if any, then set up test files */ + ok(GetTempPathA(MAX_PATH, testdir), "Failed to get temp dir.\n"); + strcat(testdir, "partial.tmp"); + tear_down_partial_test(testdir); + set_up_partial_test(testdir); + + pRtlMultiByteToUnicodeN(testdir_w, sizeof(testdir_w), NULL, testdir, strlen(testdir) + 1); + if (!pRtlDosPathNameToNtPathName_U(testdir_w, &ntdirname, NULL, NULL)) + { + ok(0, "RtlDosPathNametoNtPathName_U failed.\n"); + goto done; + } + InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); + + status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); + ok(status == STATUS_SUCCESS, "Failed to open dir '%s', ret 0x%x, error %d.\n", testdir, status, GetLastError()); + if (status != STATUS_SUCCESS) + { + skip("Skipping the test.\n"); + return; + } + + mask.Buffer = testmask; + mask.Length = mask.MaximumLength = sizeof(testmask); + + for (;;) + { + memset(found, 0, sizeof(found)); + data_pos = 0; + overflow = FALSE; + + memset(data, 0xaa, sizeof(data)); + pNtQueryDirectoryFile(dirh, NULL, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, FALSE, &mask, TRUE); + ok(U(io).Status == STATUS_SUCCESS || U(io).Status == STATUS_BUFFER_OVERFLOW, + "Unexpected status %#x.\n", U(io).Status); + if (U(io).Status == STATUS_BUFFER_OVERFLOW) + { + data_size += sizeof(*dir_info); + continue; + } + + data_len = io.Information; + ok(data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "Unexpected data_len %u.\n", data_len); + for (i = data_len; i < sizeof(data); i++) + ok(data[i] == 0xaa, "Byte %u modified, value %u.\n", i, data[i]); + + for (;;) + { + dir_info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos); + + name = dir_info->FileName; + name_len = dir_info->FileNameLength / sizeof(WCHAR); + + ok(!(dir_info->NextEntryOffset & 0x7), "Entry not aligned to 8 bytes, offset %u.\n", dir_info->NextEntryOffset); + + if (name_len == 1 && !memcmp(name, dotdot, sizeof(WCHAR))) + found[26]++; + else if (name_len == 2 && !memcmp(name, dotdot, sizeof(dotdot))) + found[27]++; + else if (name_len == sizeof(testsuffix) / sizeof(WCHAR) + 1 + && name[0] >= 'a' && name[0] <= 'z' && !memcmp(name + 1, testsuffix, sizeof(testsuffix))) + found[name[0] - 'a']++; + else + ok(0, "Found unexpected file %s (name_len %u, data_size %u, data_len %u, data_pos %u).\n", + wine_dbgstr_wn(name, name_len), name_len, data_size, data_len, data_pos); + + if (!dir_info->NextEntryOffset) + { + pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, FALSE, &mask, FALSE); + if (U(io).Status == STATUS_NO_MORE_FILES) + break; + if (U(io).Status == STATUS_BUFFER_OVERFLOW) + { + overflow = TRUE; + break; + } + ok(U(io).Status == STATUS_SUCCESS, "Failed to query directory; status %x.\n", U(io).Status); + + data_len = io.Information; + ok(data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "Unexpected data_len %u.\n", data_len); + data_pos = 0; + } + else + { + data_pos += dir_info->NextEntryOffset; + } + } + + if (!overflow) + { + for (i = 0; i < 28; i++) + /* Win7 somehow skips the ".." entry when data_size == 192. */ + ok(found[i] == 1 || broken(data_size == 192 && i == 27), + "Found %u entries for file %u, data_size %u.\n", found[i], i, data_size); + } + + data_size += sizeof(*dir_info); + if (data_size > sizeof(data)) + break; + } + + pNtClose(dirh); + +done: + tear_down_partial_test(testdir); + pRtlFreeUnicodeString(&ntdirname); +} + static void test_redirection(void) { ULONG old, cur; @@ -444,5 +612,6 @@ START_TEST(directory) test_NtQueryDirectoryFile(); test_NtQueryDirectoryFile_case(); + test_NtQueryDirectoryFile_partial(); test_redirection(); } -- 2.4.6