[PATCH 1/2] ntoskrnl.exe/tests: Add some tests for file names.

Zebediah Figura z.figura12 at gmail.com
Thu Jul 30 11:20:17 CDT 2020


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
I know of no application yet that requires this behaviour, or in fact even tries
to query file/object information from a device file. These tests are rather
meant to illustrate how ObjectNameInformation is implemented for files, which in
turn may help to inform our implementation for server-based objects such as
regular files and named pipes.

 dlls/ntoskrnl.exe/tests/driver.c   | 120 +++++++++++++++++++++++++++--
 dlls/ntoskrnl.exe/tests/ntoskrnl.c | 114 +++++++++++++++++++++++++++
 2 files changed, 226 insertions(+), 8 deletions(-)

diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 0671a56efc7..d3f62879a40 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -37,6 +37,19 @@
 
 #include "utils.h"
 
+/* memcmp() isn't exported from ntoskrnl on i386 */
+static int kmemcmp( const void *ptr1, const void *ptr2, size_t n )
+{
+    const unsigned char *p1, *p2;
+
+    for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++)
+    {
+        if (*p1 < *p2) return -1;
+        if (*p1 > *p2) return 1;
+    }
+    return 0;
+}
+
 static const WCHAR device_name[] = {'\\','D','e','v','i','c','e',
                                     '\\','W','i','n','e','T','e','s','t','D','r','i','v','e','r',0};
 static const WCHAR upper_name[] = {'\\','D','e','v','i','c','e',
@@ -55,6 +68,13 @@ static PETHREAD create_irp_thread;
 
 NTSTATUS WINAPI ZwQueryInformationProcess(HANDLE,PROCESSINFOCLASS,void*,ULONG,ULONG*);
 
+struct file_context
+{
+    DWORD id;
+    ULONG namelen;
+    WCHAR name[10];
+};
+
 static void *get_proc_address(const char *name)
 {
     UNICODE_STRING name_u;
@@ -2175,15 +2195,15 @@ static NTSTATUS get_fscontext(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *inf
 {
     ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
     char *buffer = irp->AssociatedIrp.SystemBuffer;
-    DWORD *context = stack->FileObject->FsContext;
+    struct file_context *context = stack->FileObject->FsContext;
 
-    if (!buffer || !context)
+    if (!buffer)
         return STATUS_ACCESS_VIOLATION;
 
     if (length < sizeof(DWORD))
         return STATUS_BUFFER_TOO_SMALL;
 
-    *(DWORD*)buffer = *context;
+    *(DWORD*)buffer = context->id;
     *info = sizeof(DWORD);
     return STATUS_SUCCESS;
 }
@@ -2271,13 +2291,21 @@ static NTSTATUS test_completion_ioctl(DEVICE_OBJECT *device, IRP *irp)
 static NTSTATUS WINAPI driver_Create(DEVICE_OBJECT *device, IRP *irp)
 {
     IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
-    DWORD *context = ExAllocatePool(PagedPool, sizeof(*context));
+    struct file_context *context = ExAllocatePool(PagedPool, sizeof(*context));
 
-    last_created_file = irpsp->FileObject;
-    ++create_count;
-    if (context)
-        *context = create_count;
+    if (!context)
+    {
+        irp->IoStatus.Status = STATUS_NO_MEMORY;
+        IoCompleteRequest(irp, IO_NO_INCREMENT);
+        return STATUS_NO_MEMORY;
+    }
+
+    context->id = ++create_count;
+    context->namelen = min(irpsp->FileObject->FileName.Length, sizeof(context->name));
+    memcpy(context->name, irpsp->FileObject->FileName.Buffer, context->namelen);
     irpsp->FileObject->FsContext = context;
+
+    last_created_file = irpsp->FileObject;
     create_caller_thread = KeGetCurrentThread();
     create_irp_thread = irp->Tail.Overlay.Thread;
 
@@ -2356,6 +2384,81 @@ static NTSTATUS WINAPI driver_FlushBuffers(DEVICE_OBJECT *device, IRP *irp)
     return STATUS_PENDING;
 }
 
+static BOOL compare_file_name(const struct file_context *context, const WCHAR *expect)
+{
+    return context->namelen == wcslen(expect) * sizeof(WCHAR)
+            && !kmemcmp(context->name, expect, context->namelen);
+}
+
+static NTSTATUS WINAPI driver_QueryInformation(DEVICE_OBJECT *device, IRP *irp)
+{
+    IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
+    NTSTATUS ret;
+
+    switch (stack->Parameters.QueryFile.FileInformationClass)
+    {
+    case FileNameInformation:
+    {
+        const struct file_context *context = stack->FileObject->FsContext;
+        FILE_NAME_INFORMATION *info = irp->AssociatedIrp.SystemBuffer;
+        ULONG len;
+
+        if (stack->Parameters.QueryFile.Length < sizeof(*info))
+        {
+            ret = STATUS_INFO_LENGTH_MISMATCH;
+            break;
+        }
+
+        if (compare_file_name(context, L"\\notimpl"))
+        {
+            ret = STATUS_NOT_IMPLEMENTED;
+            break;
+        }
+        else if (compare_file_name(context, L""))
+        {
+            ret = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+        }
+        else if (compare_file_name(context, L"\\badparam"))
+        {
+            ret = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        else if (compare_file_name(context, L"\\genfail"))
+        {
+            ret = STATUS_UNSUCCESSFUL;
+            break;
+        }
+        else if (compare_file_name(context, L"\\badtype"))
+        {
+            ret = STATUS_OBJECT_TYPE_MISMATCH;
+            break;
+        }
+
+        len = stack->Parameters.QueryFile.Length - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
+        if (len < context->namelen)
+            ret = STATUS_BUFFER_OVERFLOW;
+        else
+        {
+            len = context->namelen;
+            ret = STATUS_SUCCESS;
+        }
+        irp->IoStatus.Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + len;
+        info->FileNameLength = context->namelen;
+        memcpy(info->FileName, context->name, len);
+        break;
+    }
+
+    default:
+        ret = STATUS_NOT_IMPLEMENTED;
+        break;
+    }
+
+    irp->IoStatus.Status = ret;
+    IoCompleteRequest(irp, IO_NO_INCREMENT);
+    return ret;
+}
+
 static NTSTATUS WINAPI driver_Close(DEVICE_OBJECT *device, IRP *irp)
 {
     IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
@@ -2400,6 +2503,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, PUNICODE_STRING registry)
     driver->MajorFunction[IRP_MJ_CREATE]            = driver_Create;
     driver->MajorFunction[IRP_MJ_DEVICE_CONTROL]    = driver_IoControl;
     driver->MajorFunction[IRP_MJ_FLUSH_BUFFERS]     = driver_FlushBuffers;
+    driver->MajorFunction[IRP_MJ_QUERY_INFORMATION] = driver_QueryInformation;
     driver->MajorFunction[IRP_MJ_CLOSE]             = driver_Close;
 
     RtlInitUnicodeString(&nameW, IoDriverObjectTypeW);
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index b4ef9d0dcb7..61b1e401c56 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -493,6 +493,119 @@ static void test_return_status(void)
     ok(ret_size == 3, "got size %u\n", ret_size);
 }
 
+static BOOL compare_unicode_string(const WCHAR *buffer, ULONG len, const WCHAR *expect)
+{
+    return len == wcslen(expect) * sizeof(WCHAR) && !memcmp(buffer, expect, len);
+}
+
+static void test_object_info(void)
+{
+    char buffer[200];
+    OBJECT_NAME_INFORMATION *name_info = (OBJECT_NAME_INFORMATION *)buffer;
+    OBJECT_TYPE_INFORMATION *type_info = (OBJECT_TYPE_INFORMATION *)buffer;
+    FILE_NAME_INFORMATION *file_info = (FILE_NAME_INFORMATION *)buffer;
+    HANDLE file;
+    NTSTATUS status;
+    IO_STATUS_BLOCK io;
+    ULONG size;
+
+    status = NtQueryObject(device, ObjectNameInformation, buffer, sizeof(buffer), NULL);
+    ok(!status, "got %#x\n", status);
+    todo_wine ok(compare_unicode_string(name_info->Name.Buffer, name_info->Name.Length, L"\\Device\\WineTestDriver"),
+            "wrong name %s\n", debugstr_w(name_info->Name.Buffer));
+
+    status = NtQueryObject(device, ObjectTypeInformation, buffer, sizeof(buffer), NULL);
+    ok(!status, "got %#x\n", status);
+    ok(compare_unicode_string(type_info->TypeName.Buffer, type_info->TypeName.Length, L"File"),
+            "wrong name %s\n", debugstr_wn(type_info->TypeName.Buffer, type_info->TypeName.Length / sizeof(WCHAR)));
+
+    status = NtQueryInformationFile(device, &io, buffer, sizeof(buffer), FileNameInformation);
+    todo_wine ok(status == STATUS_INVALID_DEVICE_REQUEST, "got %#x\n", status);
+
+    file = CreateFileA("\\\\.\\WineTestDriver\\subfile", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+    todo_wine ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError());
+    if (file == INVALID_HANDLE_VALUE) return;
+
+    memset(buffer, 0xcc, sizeof(buffer));
+    status = NtQueryObject(file, ObjectNameInformation, buffer, sizeof(buffer), &size);
+    ok(!status, "got %#x\n", status);
+    ok(size == sizeof(*name_info) + sizeof(L"\\Device\\WineTestDriver\\subfile"), "wrong size %u\n", size);
+    ok(compare_unicode_string(name_info->Name.Buffer, name_info->Name.Length, L"\\Device\\WineTestDriver\\subfile"),
+            "wrong name %s\n", debugstr_w(name_info->Name.Buffer));
+
+    memset(buffer, 0xcc, sizeof(buffer));
+    status = NtQueryObject(file, ObjectNameInformation, buffer, size - 2, &size);
+    ok(status == STATUS_BUFFER_OVERFLOW, "got %#x\n", status);
+    ok(size == sizeof(*name_info) + sizeof(L"\\Device\\WineTestDriver\\subfile"), "wrong size %u\n", size);
+    ok(compare_unicode_string(name_info->Name.Buffer, name_info->Name.Length, L"\\Device\\WineTestDriver\\subfil"),
+            "wrong name %s\n", debugstr_w(name_info->Name.Buffer));
+
+    memset(buffer, 0xcc, sizeof(buffer));
+    status = NtQueryObject(file, ObjectNameInformation, buffer, sizeof(*name_info), &size);
+    ok(status == STATUS_BUFFER_OVERFLOW, "got %#x\n", status);
+    ok(size == sizeof(*name_info) + sizeof(L"\\Device\\WineTestDriver\\subfile"), "wrong size %u\n", size);
+
+    status = NtQueryObject(file, ObjectTypeInformation, buffer, sizeof(buffer), NULL);
+    ok(!status, "got %#x\n", status);
+    ok(compare_unicode_string(type_info->TypeName.Buffer, type_info->TypeName.Length, L"File"),
+            "wrong name %s\n", debugstr_wn(type_info->TypeName.Buffer, type_info->TypeName.Length / sizeof(WCHAR)));
+
+    status = NtQueryInformationFile(file, &io, buffer, sizeof(buffer), FileNameInformation);
+    ok(!status, "got %#x\n", status);
+    ok(compare_unicode_string(file_info->FileName, file_info->FileNameLength, L"\\subfile"),
+            "wrong name %s\n", debugstr_wn(file_info->FileName, file_info->FileNameLength / sizeof(WCHAR)));
+
+    CloseHandle(file);
+
+    file = CreateFileA("\\\\.\\WineTestDriver\\notimpl", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError());
+
+    status = NtQueryObject(file, ObjectNameInformation, buffer, sizeof(buffer), NULL);
+    ok(!status, "got %#x\n", status);
+    ok(compare_unicode_string(name_info->Name.Buffer, name_info->Name.Length, L"\\Device\\WineTestDriver"),
+            "wrong name %s\n", debugstr_w(name_info->Name.Buffer));
+
+    status = NtQueryInformationFile(file, &io, buffer, sizeof(buffer), FileNameInformation);
+    ok(status == STATUS_NOT_IMPLEMENTED, "got %#x\n", status);
+
+    CloseHandle(file);
+
+    file = CreateFileA("\\\\.\\WineTestDriver\\badparam", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError());
+
+    status = NtQueryObject(file, ObjectNameInformation, buffer, sizeof(buffer), NULL);
+    ok(!status, "got %#x\n", status);
+    ok(compare_unicode_string(name_info->Name.Buffer, name_info->Name.Length, L"\\Device\\WineTestDriver"),
+            "wrong name %s\n", debugstr_w(name_info->Name.Buffer));
+
+    status = NtQueryInformationFile(file, &io, buffer, sizeof(buffer), FileNameInformation);
+    ok(status == STATUS_INVALID_PARAMETER, "got %#x\n", status);
+
+    CloseHandle(file);
+
+    file = CreateFileA("\\\\.\\WineTestDriver\\genfail", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError());
+
+    status = NtQueryObject(file, ObjectNameInformation, buffer, sizeof(buffer), NULL);
+    ok(status == STATUS_UNSUCCESSFUL, "got %#x\n", status);
+
+    status = NtQueryInformationFile(file, &io, buffer, sizeof(buffer), FileNameInformation);
+    ok(status == STATUS_UNSUCCESSFUL, "got %#x\n", status);
+
+    CloseHandle(file);
+
+    file = CreateFileA("\\\\.\\WineTestDriver\\badtype", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError());
+
+    status = NtQueryObject(file, ObjectNameInformation, buffer, sizeof(buffer), NULL);
+    ok(status == STATUS_OBJECT_TYPE_MISMATCH, "got %#x\n", status);
+
+    status = NtQueryInformationFile(file, &io, buffer, sizeof(buffer), FileNameInformation);
+    ok(status == STATUS_OBJECT_TYPE_MISMATCH, "got %#x\n", status);
+
+    CloseHandle(file);
+}
+
 static void test_driver3(void)
 {
     char filename[MAX_PATH];
@@ -644,6 +757,7 @@ START_TEST(ntoskrnl)
     test_load_driver(service2);
     test_file_handles();
     test_return_status();
+    test_object_info();
 
     /* We need a separate ioctl to call IoDetachDevice(); calling it in the
      * driver unload routine causes a live-lock. */
-- 
2.27.0




More information about the wine-devel mailing list