[PATCH 4/4] ntdll/tests: Add a test for NtQueryDirectoryFile returning partial results.

Matteo Bruni mbruni at codeweavers.com
Thu Aug 27 14:08:41 CDT 2015


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




More information about the wine-patches mailing list