[PATCH v2 1/2] ntoskrnl.exe/tests: Add some tests for file names.
Zebediah Figura
z.figura12 at gmail.com
Thu Jul 30 18:04:20 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