[prev in list] [next in list] [prev in thread] [next in thread]
List: wine-devel
Subject: [PATCH v2 1/2] ntoskrnl.exe/tests: Add some tests for file names.
From: Zebediah Figura <z.figura12 () gmail ! com>
Date: 2020-07-30 23:04:20
Message-ID: 20200730230421.266634-1-z.figura12 () gmail ! com
[Download RAW message or body]
Signed-off-by: Zebediah Figura <z.figura12@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
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic