Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntoskrnl.exe/tests/driver.c | 140 +-------------------------- dlls/ntoskrnl.exe/tests/utils.h | 160 +++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 138 deletions(-) create mode 100644 dlls/ntoskrnl.exe/tests/utils.h
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index beac9c2c25e..fa8d7b20e3e 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -35,6 +35,8 @@
#include "driver.h"
+#include "utils.h" + 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', @@ -45,17 +47,6 @@ static const WCHAR driver_link[] = {'\','D','o','s','D','e','v','i','c','e','s' static DRIVER_OBJECT *driver_obj; static DEVICE_OBJECT *lower_device, *upper_device;
-static HANDLE okfile; -static LONG successes; -static LONG failures; -static LONG skipped; -static LONG todo_successes; -static LONG todo_failures; -static int todo_level, todo_do_loop; -static int running_under_wine; -static int winetest_debug; -static int winetest_report_success; - static POBJECT_TYPE *pExEventObjectType, *pIoFileObjectType, *pPsThreadType, *pIoDriverObjectType; static PEPROCESS *pPsInitialSystemProcess; static void *create_caller_thread; @@ -64,133 +55,6 @@ static PETHREAD create_irp_thread;
NTSTATUS WINAPI ZwQueryInformationProcess(HANDLE,PROCESSINFOCLASS,void*,ULONG,ULONG*);
-static void kvprintf(const char *format, __ms_va_list ap) -{ - static char buffer[512]; - IO_STATUS_BLOCK io; - int len = vsnprintf(buffer, sizeof(buffer), format, ap); - ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL); -} - -static void WINAPIV kprintf(const char *format, ...) -{ - __ms_va_list valist; - - __ms_va_start(valist, format); - kvprintf(format, valist); - __ms_va_end(valist); -} - -static void WINAPIV vok_(const char *file, int line, int condition, const char *msg, __ms_va_list args) -{ - const char *current_file; - - if (!(current_file = drv_strrchr(file, '/')) && - !(current_file = drv_strrchr(file, '\'))) - current_file = file; - else - current_file++; - - if (todo_level) - { - if (condition) - { - kprintf("%s:%d: Test succeeded inside todo block: ", current_file, line); - kvprintf(msg, args); - InterlockedIncrement(&todo_failures); - } - else - { - if (winetest_debug > 0) - { - kprintf("%s:%d: Test marked todo: ", current_file, line); - kvprintf(msg, args); - } - InterlockedIncrement(&todo_successes); - } - } - else - { - if (!condition) - { - kprintf("%s:%d: Test failed: ", current_file, line); - kvprintf(msg, args); - InterlockedIncrement(&failures); - } - else - { - if (winetest_report_success) - kprintf("%s:%d: Test succeeded\n", current_file, line); - InterlockedIncrement(&successes); - } - } -} - -static void WINAPIV ok_(const char *file, int line, int condition, const char *msg, ...) -{ - __ms_va_list args; - __ms_va_start(args, msg); - vok_(file, line, condition, msg, args); - __ms_va_end(args); -} - -static void vskip_(const char *file, int line, const char *msg, __ms_va_list args) -{ - const char *current_file; - - if (!(current_file = drv_strrchr(file, '/')) && - !(current_file = drv_strrchr(file, '\'))) - current_file = file; - else - current_file++; - - kprintf("%s:%d: Tests skipped: ", current_file, line); - kvprintf(msg, args); - skipped++; -} - -static void WINAPIV win_skip_(const char *file, int line, const char *msg, ...) -{ - __ms_va_list args; - __ms_va_start(args, msg); - if (running_under_wine) - vok_(file, line, 0, msg, args); - else - vskip_(file, line, msg, args); - __ms_va_end(args); -} - -static void winetest_start_todo( int is_todo ) -{ - todo_level = (todo_level << 1) | (is_todo != 0); - todo_do_loop=1; -} - -static int winetest_loop_todo(void) -{ - int do_loop=todo_do_loop; - todo_do_loop=0; - return do_loop; -} - -static void winetest_end_todo(void) -{ - todo_level >>= 1; -} - -static int broken(int condition) -{ - return !running_under_wine && condition; -} - -#define ok(condition, ...) ok_(__FILE__, __LINE__, condition, __VA_ARGS__) -#define todo_if(is_todo) for (winetest_start_todo(is_todo); \ - winetest_loop_todo(); \ - winetest_end_todo()) -#define todo_wine todo_if(running_under_wine) -#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine) -#define win_skip(...) win_skip_(__FILE__, __LINE__, __VA_ARGS__) - static void *get_proc_address(const char *name) { UNICODE_STRING name_u; diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h new file mode 100644 index 00000000000..da0b02ac006 --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/utils.h @@ -0,0 +1,160 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2015 Sebastian Lackner + * Copyright 2015 Michael Müller + * Copyright 2015 Christian Costa + * Copyright 2020 Paul Gofman for Codeweavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +static HANDLE okfile; +static LONG successes; +static LONG failures; +static LONG skipped; +static LONG todo_successes; +static LONG todo_failures; +static int todo_level, todo_do_loop; +static int running_under_wine; +static int winetest_debug; +static int winetest_report_success; + +static inline void kvprintf(const char *format, __ms_va_list ap) +{ + static char buffer[512]; + IO_STATUS_BLOCK io; + int len = vsnprintf(buffer, sizeof(buffer), format, ap); + ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL); +} + +static inline void WINAPIV kprintf(const char *format, ...) +{ + __ms_va_list valist; + + __ms_va_start(valist, format); + kvprintf(format, valist); + __ms_va_end(valist); +} + +static inline void WINAPIV vok_(const char *file, int line, int condition, const char *msg, __ms_va_list args) +{ + const char *current_file; + + if (!(current_file = drv_strrchr(file, '/')) && + !(current_file = drv_strrchr(file, '\'))) + current_file = file; + else + current_file++; + + if (todo_level) + { + if (condition) + { + kprintf("%s:%d: Test succeeded inside todo block: ", current_file, line); + kvprintf(msg, args); + InterlockedIncrement(&todo_failures); + } + else + { + if (winetest_debug > 0) + { + kprintf("%s:%d: Test marked todo: ", current_file, line); + kvprintf(msg, args); + } + InterlockedIncrement(&todo_successes); + } + } + else + { + if (!condition) + { + kprintf("%s:%d: Test failed: ", current_file, line); + kvprintf(msg, args); + InterlockedIncrement(&failures); + } + else + { + if (winetest_report_success) + kprintf("%s:%d: Test succeeded\n", current_file, line); + InterlockedIncrement(&successes); + } + } +} + +static inline void WINAPIV ok_(const char *file, int line, int condition, const char *msg, ...) +{ + __ms_va_list args; + __ms_va_start(args, msg); + vok_(file, line, condition, msg, args); + __ms_va_end(args); +} + +static inline void vskip_(const char *file, int line, const char *msg, __ms_va_list args) +{ + const char *current_file; + + if (!(current_file = drv_strrchr(file, '/')) && + !(current_file = drv_strrchr(file, '\'))) + current_file = file; + else + current_file++; + + kprintf("%s:%d: Tests skipped: ", current_file, line); + kvprintf(msg, args); + skipped++; +} + +static inline void WINAPIV win_skip_(const char *file, int line, const char *msg, ...) +{ + __ms_va_list args; + __ms_va_start(args, msg); + if (running_under_wine) + vok_(file, line, 0, msg, args); + else + vskip_(file, line, msg, args); + __ms_va_end(args); +} + +static inline void winetest_start_todo( int is_todo ) +{ + todo_level = (todo_level << 1) | (is_todo != 0); + todo_do_loop=1; +} + +static inline int winetest_loop_todo(void) +{ + int do_loop=todo_do_loop; + todo_do_loop=0; + return do_loop; +} + +static inline void winetest_end_todo(void) +{ + todo_level >>= 1; +} + +static inline int broken(int condition) +{ + return !running_under_wine && condition; +} + +#define ok(condition, ...) ok_(__FILE__, __LINE__, condition, __VA_ARGS__) +#define todo_if(is_todo) for (winetest_start_todo(is_todo); \ + winetest_loop_todo(); \ + winetest_end_todo()) +#define todo_wine todo_if(running_under_wine) +#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine) +#define win_skip(...) win_skip_(__FILE__, __LINE__, __VA_ARGS__)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- include/ddk/wsk.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/ddk/wsk.h b/include/ddk/wsk.h index d19da999be8..18a7de3b2c5 100644 --- a/include/ddk/wsk.h +++ b/include/ddk/wsk.h @@ -27,6 +27,8 @@ extern "C"
struct _WSK_CLIENT; typedef struct _WSK_CLIENT WSK_CLIENT, *PWSK_CLIENT; +#define MAKE_WSK_VERSION(major, minor) ((USHORT)((major) << 8) | (USHORT)((minor) & 0xff)) + typedef struct _WSK_CLIENT_CONNECTION_DISPATCH WSK_CLIENT_CONNECTION_DISPATCH, *PWSK_CLIENT_CONNECTION_DISPATCH;
typedef struct _WSK_BUF
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- include/ddk/wsk.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/ddk/wsk.h b/include/ddk/wsk.h index 18a7de3b2c5..a46eeadcc4b 100644 --- a/include/ddk/wsk.h +++ b/include/ddk/wsk.h @@ -28,6 +28,8 @@ extern "C" struct _WSK_CLIENT; typedef struct _WSK_CLIENT WSK_CLIENT, *PWSK_CLIENT; #define MAKE_WSK_VERSION(major, minor) ((USHORT)((major) << 8) | (USHORT)((minor) & 0xff)) +#define WSK_NO_WAIT 0 +#define WSK_INFINITE_WAIT 0xffffffff
typedef struct _WSK_CLIENT_CONNECTION_DISPATCH WSK_CLIENT_CONNECTION_DISPATCH, *PWSK_CLIENT_CONNECTION_DISPATCH;
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- tools/makedep.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
diff --git a/tools/makedep.c b/tools/makedep.c index 536d2263e35..c62a662b214 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -177,8 +177,10 @@ struct makefile struct strarray programs; struct strarray scripts; struct strarray imports; + struct strarray extra_target_imports; struct strarray subdirs; struct strarray delayimports; + struct strarray extra_target_delayimports; struct strarray extradllflags; struct strarray install_lib; struct strarray install_dev; @@ -1789,6 +1791,28 @@ static struct strarray get_expanded_make_var_array( const struct makefile *make, return ret; }
+static struct strarray get_expanded_make_multiple_var_array( const struct makefile *make, const char *name_suffix ) +{ + struct strarray ret = empty_strarray; + unsigned int i, name_suffix_len; + char *value, *token; + + name_suffix_len = strlen( name_suffix ); + + for (i = 0; i < make->vars.count / 2; ++i) + { + const char *str = make->vars.str[i * 2]; + unsigned int len = strlen( str ); + + if (len > name_suffix_len && !strcmp( str + len - name_suffix_len, name_suffix ) + && (value = get_expanded_make_variable( make, str ))) + { + for (token = strtok( value, " \t" ); token; token = strtok( NULL, " \t" )) + strarray_add_uniq( &ret, token ); + } + } + return ret; +}
/******************************************************************* * get_expanded_file_local_var @@ -4271,7 +4295,11 @@ static void load_sources( struct makefile *make ) make->programs = get_expanded_make_var_array( make, "PROGRAMS" ); make->scripts = get_expanded_make_var_array( make, "SCRIPTS" ); make->imports = get_expanded_make_var_array( make, "IMPORTS" ); + make->extra_target_imports + = get_expanded_make_multiple_var_array( make, "_IMPORTS" ); make->delayimports = get_expanded_make_var_array( make, "DELAYIMPORTS" ); + make->extra_target_delayimports + = get_expanded_make_multiple_var_array( make, "_DELAYIMPORTS" ); make->extradllflags = get_expanded_make_var_array( make, "EXTRADLLFLAGS" ); make->install_lib = get_expanded_make_var_array( make, "INSTALL_LIB" ); make->install_dev = get_expanded_make_var_array( make, "INSTALL_DEV" ); @@ -4363,6 +4391,10 @@ static void load_sources( struct makefile *make ) { for (i = 0; i < make->imports.count; i++) strarray_add_uniq( &cross_import_libs, make->imports.str[i] ); + + for (i = 0; i < make->extra_target_imports.count; i++) + strarray_add_uniq( &cross_import_libs, make->extra_target_imports.str[i] ); + if (make->is_win16) strarray_add_uniq( &cross_import_libs, "kernel" ); strarray_add_uniq( &cross_import_libs, "winecrt0" ); strarray_add_uniq( &cross_import_libs, "kernel32" ); @@ -4370,8 +4402,13 @@ static void load_sources( struct makefile *make ) }
if (!*dll_ext || make->is_cross) + { + for (i = 0; i < make->extra_target_delayimports.count; i++) + strarray_add_uniq( &delay_import_libs, get_base_name( make->extra_target_delayimports.str[i] )); + for (i = 0; i < make->delayimports.count; i++) strarray_add_uniq( &delay_import_libs, get_base_name( make->delayimports.str[i] )); + } }
Test driver should import netio.sys which is available since Vista, so a new test driver is needed to preserve XP compatibility for the existing tests.
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntoskrnl.exe/tests/Makefile.in | 4 + dlls/ntoskrnl.exe/tests/driver4.c | 246 +++++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/driver4.spec | 1 + dlls/ntoskrnl.exe/tests/ntoskrnl.c | 59 ++++++- 4 files changed, 302 insertions(+), 8 deletions(-) create mode 100644 dlls/ntoskrnl.exe/tests/driver4.c create mode 100644 dlls/ntoskrnl.exe/tests/driver4.spec
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 7946b8de220..06c06671ca1 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -7,6 +7,8 @@ driver2_IMPORTS = winecrt0 ntoskrnl driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver3_IMPORTS = winecrt0 ntoskrnl driver3_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver4_IMPORTS = winecrt0 ntoskrnl netio +driver4_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
SOURCES = \ driver.c \ @@ -15,4 +17,6 @@ SOURCES = \ driver2.spec \ driver3.c \ driver3.spec \ + driver4.c \ + driver4.spec \ ntoskrnl.c diff --git a/dlls/ntoskrnl.exe/tests/driver4.c b/dlls/ntoskrnl.exe/tests/driver4.c new file mode 100644 index 00000000000..2fe6072ec58 --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver4.c @@ -0,0 +1,246 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2020 Paul Gofman for Codeweavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/ntddk.h" +#include "ddk/ntifs.h" +#include "ddk/wdm.h" +#include "ddk/wsk.h" + +#include "driver.h" + +#include "utils.h" + +static DRIVER_OBJECT *driver_obj; +static DEVICE_OBJECT *lower_device, *upper_device; + +static unsigned int create_count, close_count; + +static const WCHAR driver_link[] = L"\DosDevices\WineTestDriver4"; +static const WCHAR device_name[] = L"\Device\WineTestDriver4"; +static const WCHAR upper_name[] = L"\Device\WineTestUpper4"; + +static FILE_OBJECT *last_created_file; +static void *create_caller_thread; +static PETHREAD create_irp_thread; + +static POBJECT_TYPE *pIoDriverObjectType; + +static WSK_CLIENT_NPI client_npi; +static WSK_REGISTRATION registration; +static WSK_PROVIDER_NPI provider_npi; + +static void netio_init(void) +{ + const WSK_CLIENT_DISPATCH client_dispatch = + { + MAKE_WSK_VERSION(1, 0), 0, NULL + }; + + NTSTATUS status; + + client_npi.Dispatch = &client_dispatch; + status = WskRegister(&client_npi, ®istration); + todo_wine ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + + status = WskCaptureProviderNPI(®istration, WSK_INFINITE_WAIT, &provider_npi); + todo_wine ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); +} + +static void netio_uninit(void) +{ + WskReleaseProviderNPI(®istration); + WskDeregister(®istration); +} + +static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) +{ + ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; + void *buffer = irp->AssociatedIrp.SystemBuffer; + struct test_input *test_input = buffer; + OBJECT_ATTRIBUTES attr = {0}; + UNICODE_STRING pathU; + IO_STATUS_BLOCK io; + + if (!buffer) + return STATUS_ACCESS_VIOLATION; + if (length < sizeof(failures)) + return STATUS_BUFFER_TOO_SMALL; + + attr.Length = sizeof(attr); + RtlInitUnicodeString(&pathU, test_input->path); + running_under_wine = test_input->running_under_wine; + winetest_debug = test_input->winetest_debug; + winetest_report_success = test_input->winetest_report_success; + attr.ObjectName = &pathU; + attr.Attributes = OBJ_KERNEL_HANDLE; /* needed to be accessible from system threads */ + ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT); + + netio_init(); + + if (winetest_debug) + { + kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n", + PsGetCurrentProcessId(), successes + failures + todo_successes + todo_failures, + todo_successes, failures + todo_failures, + (failures + todo_failures != 1) ? "failures" : "failure", skipped ); + } + ZwClose(okfile); + + *((LONG *)buffer) = failures; + irp->IoStatus.Information = sizeof(failures); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_iocontrol(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + NTSTATUS status = STATUS_NOT_SUPPORTED; + + switch (stack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_WINETEST_MAIN_TEST: + status = main_test(device, irp, stack); + break; + case IOCTL_WINETEST_DETACH: + IoDetachDevice(lower_device); + status = STATUS_SUCCESS; + break; + default: + break; + } + + if (status != STATUS_PENDING) + { + irp->IoStatus.Status = status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + } + return status; +} + +static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + DWORD *context = ExAllocatePool(PagedPool, sizeof(*context)); + + last_created_file = irpsp->FileObject; + ++create_count; + if (context) + *context = create_count; + irpsp->FileObject->FsContext = context; + create_caller_thread = KeGetCurrentThread(); + create_irp_thread = irp->Tail.Overlay.Thread; + + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_close(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + + netio_uninit(); + + ++close_count; + if (stack->FileObject->FsContext) + ExFreePool(stack->FileObject->FsContext); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +static VOID WINAPI driver_unload(DRIVER_OBJECT *driver) +{ + UNICODE_STRING linkW; + + DbgPrint("Unloading driver.\n"); + + RtlInitUnicodeString(&linkW, driver_link); + IoDeleteSymbolicLink(&linkW); + + IoDeleteDevice(upper_device); + IoDeleteDevice(lower_device); +} + +NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, PUNICODE_STRING registry) +{ + static const WCHAR IoDriverObjectTypeW[] = L"IoDriverObjectType"; + static const WCHAR driver_nameW[] = L"\Driver\WineTestDriver4"; + UNICODE_STRING nameW, linkW; + NTSTATUS status; + void *obj; + + DbgPrint("Loading driver.\n"); + + driver_obj = driver; + + driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_CREATE] = driver_create; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_iocontrol; + driver->MajorFunction[IRP_MJ_CLOSE] = driver_close; + + RtlInitUnicodeString(&nameW, IoDriverObjectTypeW); + pIoDriverObjectType = MmGetSystemRoutineAddress(&nameW); + + RtlInitUnicodeString(&nameW, driver_nameW); + if ((status = ObReferenceObjectByName(&nameW, 0, NULL, 0, *pIoDriverObjectType, KernelMode, NULL, &obj))) + return status; + if (obj != driver) + { + ObDereferenceObject(obj); + return STATUS_UNSUCCESSFUL; + } + ObDereferenceObject(obj); + + RtlInitUnicodeString(&nameW, device_name); + RtlInitUnicodeString(&linkW, driver_link); + + if (!(status = IoCreateDevice(driver, 0, &nameW, FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, FALSE, &lower_device))) + { + status = IoCreateSymbolicLink(&linkW, &nameW); + lower_device->Flags &= ~DO_DEVICE_INITIALIZING; + } + + if (!status) + { + RtlInitUnicodeString(&nameW, upper_name); + + status = IoCreateDevice(driver, 0, &nameW, FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, FALSE, &upper_device); + } + + if (!status) + { + IoAttachDeviceToDeviceStack(upper_device, lower_device); + upper_device->Flags &= ~DO_DEVICE_INITIALIZING; + } + + return status; +} diff --git a/dlls/ntoskrnl.exe/tests/driver4.spec b/dlls/ntoskrnl.exe/tests/driver4.spec new file mode 100644 index 00000000000..792d6005489 --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver4.spec @@ -0,0 +1 @@ +# diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 8d2da92455a..c2afee3dfe9 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -109,17 +109,25 @@ static SC_HANDLE load_driver(char *filename, const char *resname, const char *dr return service; }
-static BOOL start_driver(HANDLE service) +static BOOL start_driver(HANDLE service, BOOL vista_plus) { SERVICE_STATUS status; BOOL ret;
SetLastError(0xdeadbeef); ret = StartServiceA(service, 0, NULL); - if (!ret && (GetLastError() == ERROR_DRIVER_BLOCKED || GetLastError() == ERROR_INVALID_IMAGE_HASH)) + if (!ret && (GetLastError() == ERROR_DRIVER_BLOCKED || GetLastError() == ERROR_INVALID_IMAGE_HASH + || (vista_plus && GetLastError() == ERROR_FILE_NOT_FOUND))) { - /* If Secure Boot is enabled or the machine is 64-bit, it will reject an unsigned driver. */ - skip("Failed to start service; probably your machine doesn't accept unsigned drivers.\n"); + if (vista_plus && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("Windows Vista or newer is required to run this service.\n"); + } + else + { + /* If Secure Boot is enabled or the machine is 64-bit, it will reject an unsigned driver. */ + skip("Failed to start service; probably your machine doesn't accept unsigned drivers.\n"); + } DeleteService(service); CloseServiceHandle(service); return FALSE; @@ -143,13 +151,14 @@ static BOOL start_driver(HANDLE service) return TRUE; }
+static ULONG64 modified_value; + static void main_test(void) { static const WCHAR dokW[] = {'d','o','k',0}; WCHAR temppathW[MAX_PATH], pathW[MAX_PATH]; struct test_input *test_input; DWORD len, written, read; - ULONG64 modified_value; UNICODE_STRING pathU; LONG new_failures; char buffer[512]; @@ -178,8 +187,6 @@ static void main_test(void) ok(res, "DeviceIoControl failed: %u\n", GetLastError()); ok(written == sizeof(new_failures), "got size %x\n", written);
- todo_wine ok(modified_value == 0xdeadbeeffeedcafe, "Got unexpected value %#I64x.\n", modified_value); - okfile = CreateFileW(pathW, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); ok(okfile != INVALID_HANDLE_VALUE, "failed to create %s: %u\n", wine_dbgstr_w(pathW), GetLastError());
@@ -506,6 +513,37 @@ static void test_driver3(void) DeleteFileA(filename); }
+void test_driver4(void) +{ + char filename[MAX_PATH]; + SC_HANDLE service; + DWORD written; + BOOL ret; + + if (!(service = load_driver(filename, "driver4.dll", "WineTestDriver4"))) + return; + + if (!start_driver(service, TRUE)) + { + DeleteFileA(filename); + return; + } + + device = CreateFileA("\\.\WineTestDriver4", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError()); + + main_test(); + + ret = DeviceIoControl(device, IOCTL_WINETEST_DETACH, NULL, 0, NULL, 0, &written, NULL); + ok(ret, "DeviceIoControl failed: %u\n", GetLastError()); + + CloseHandle(device); + + unload_driver(service); + ret = DeleteFileA(filename); + ok(ret, "DeleteFile failed: %u\n", GetLastError()); +} + START_TEST(ntoskrnl) { char filename[MAX_PATH], filename2[MAX_PATH]; @@ -523,7 +561,7 @@ START_TEST(ntoskrnl) subtest("driver"); if (!(service = load_driver(filename, "driver.dll", "WineTestDriver"))) return; - if (!start_driver(service)) + if (!start_driver(service, FALSE)) { DeleteFileA(filename); return; @@ -535,7 +573,10 @@ START_TEST(ntoskrnl)
test_basic_ioctl(); test_mismatched_status_ioctl(); + main_test(); + todo_wine ok(modified_value == 0xdeadbeeffeedcafe, "Got unexpected value %#I64x.\n", modified_value); + test_overlapped(); test_load_driver(service2); test_file_handles(); @@ -556,4 +597,6 @@ START_TEST(ntoskrnl) ok(ret, "DeleteFile failed: %u\n", GetLastError());
test_driver3(); + subtest("driver4"); + test_driver4(); }
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/netio.sys/netio.c | 118 ++++++++++++++++++++++++++++-- dlls/ntoskrnl.exe/tests/driver4.c | 8 +- 2 files changed, 118 insertions(+), 8 deletions(-)
diff --git a/dlls/netio.sys/netio.c b/dlls/netio.sys/netio.c index 839a06d30d4..fac91736ab1 100644 --- a/dlls/netio.sys/netio.c +++ b/dlls/netio.sys/netio.c @@ -32,32 +32,138 @@ #include "ddk/wsk.h" #include "wine/debug.h"
+#include "wine/heap.h" + WINE_DEFAULT_DEBUG_CHANNEL(netio);
+struct _WSK_CLIENT +{ + WSK_REGISTRATION *registration; + WSK_CLIENT_NPI *client_npi; +}; + +static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_family, USHORT socket_type, + ULONG protocol, ULONG Flags, void *socket_context, const void *dispatch, PEPROCESS owning_process, + PETHREAD owning_thread, SECURITY_DESCRIPTOR *security_descriptor, IRP *irp) +{ + FIXME("client %p, address_family %#x, socket_type %#x, protocol %#x, Flags %#x, socket_context %p, dispatch %p, " + "owning_process %p, owning_thread %p, security_descriptor %p, irp %p stub.\n", + client, address_family, socket_type, protocol, Flags, socket_context, dispatch, owning_process, + owning_thread, security_descriptor, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_socket_connect(WSK_CLIENT *client, USHORT socket_type, ULONG protocol, + SOCKADDR *local_address, SOCKADDR *remote_address, ULONG flags, void *socket_context, + const WSK_CLIENT_CONNECTION_DISPATCH *dispatch, PEPROCESS owning_process, PETHREAD owning_thread, + SECURITY_DESCRIPTOR *security_descriptor, IRP *irp) +{ + FIXME("client %p, socket_type %#x, protocol %#x, local_address %p, remote_address %p, " + "flags %#x, socket_context %p, dispatch %p, owning_process %p, owning_thread %p, " + "security_descriptor %p, irp %p stub.\n", + client, socket_type, protocol, local_address, remote_address, flags, socket_context, + dispatch, owning_process, owning_thread, security_descriptor, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_control_client(WSK_CLIENT *client, ULONG control_code, SIZE_T input_size, + void *input_buffer, SIZE_T output_size, void *output_buffer, SIZE_T *output_size_returned, + IRP *irp +) +{ + FIXME("client %p, control_code %#x, input_size %lu, input_buffer %p, output_size %lu, " + "output_buffer %p, output_size_returned %p, irp %p, stub.\n", + client, control_code, input_size, input_buffer, output_size, output_buffer, + output_size_returned, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_get_address_info(WSK_CLIENT *client, UNICODE_STRING *node_name, + UNICODE_STRING *service_name, ULONG name_space, GUID *provider, ADDRINFOEXW *hints, + ADDRINFOEXW **result, PEPROCESS owning_process, PETHREAD owning_thread, IRP *irp) +{ + FIXME("client %p, node_name %p, service_name %p, name_space %#x, provider %p, hints %p, " + "result %p, owning_process %p, owning_thread %p, irp %p stub.\n", + client, node_name, service_name, name_space, provider, hints, result, + owning_process, owning_thread, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static void WINAPI wsk_free_address_info(WSK_CLIENT *client, ADDRINFOEXW *addr_info) +{ + FIXME("client %p, addr_info %p stub.\n", client, addr_info); +} + +static NTSTATUS WINAPI wsk_get_name_info(WSK_CLIENT *client, SOCKADDR *sock_addr, ULONG sock_addr_length, + UNICODE_STRING *node_name, UNICODE_STRING *service_name, ULONG flags, PEPROCESS owning_process, + PETHREAD owning_thread, IRP *irp) +{ + FIXME("client %p, sock_addr %p, sock_addr_length %u, node_name %p, service_name %p, " + "flags %#x, owning_process %p, owning_thread %p, irp %p stub.\n", + client, sock_addr, sock_addr_length, node_name, service_name, flags, + owning_process, owning_thread, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static const WSK_PROVIDER_DISPATCH wsk_dispatch = +{ + MAKE_WSK_VERSION(1, 0), 0, + wsk_socket, + wsk_socket_connect, + wsk_control_client, + wsk_get_address_info, + wsk_free_address_info, + wsk_get_name_info, +}; + NTSTATUS WINAPI WskCaptureProviderNPI(WSK_REGISTRATION *wsk_registration, ULONG wait_timeout, WSK_PROVIDER_NPI *wsk_provider_npi) { - FIXME("wsk_registration %p, wait_timeout %u, wsk_provider_npi %p stub.\n", + WSK_CLIENT *client = wsk_registration->ReservedRegistrationContext; + + TRACE("wsk_registration %p, wait_timeout %u, wsk_provider_npi %p.\n", wsk_registration, wait_timeout, wsk_provider_npi);
- return STATUS_NOT_IMPLEMENTED; + wsk_provider_npi->Client = client; + wsk_provider_npi->Dispatch = &wsk_dispatch; + return STATUS_SUCCESS; }
void WINAPI WskReleaseProviderNPI(WSK_REGISTRATION *wsk_registration) { - FIXME("wsk_registration %p stub.\n", wsk_registration); + TRACE("wsk_registration %p.\n", wsk_registration); + }
NTSTATUS WINAPI WskRegister(WSK_CLIENT_NPI *wsk_client_npi, WSK_REGISTRATION *wsk_registration) { - FIXME("wsk_client_npi %p, wsk_registration %p stub.\n", wsk_client_npi, wsk_registration); + WSK_CLIENT *client;
- return STATUS_NOT_IMPLEMENTED; + TRACE("wsk_client_npi %p, wsk_registration %p.\n", wsk_client_npi, wsk_registration); + + if (!(client = heap_alloc(sizeof(*client)))) + { + ERR("No memory.\n"); + return STATUS_NO_MEMORY; + } + + client->registration = wsk_registration; + client->client_npi = wsk_client_npi; + wsk_registration->ReservedRegistrationContext = client; + + return STATUS_SUCCESS; }
void WINAPI WskDeregister(WSK_REGISTRATION *wsk_registration) { - FIXME("wsk_registration %p stub.\n", wsk_registration); + TRACE("wsk_registration %p.\n", wsk_registration); + + heap_free(wsk_registration->ReservedRegistrationContext); }
static void WINAPI driver_unload(DRIVER_OBJECT *driver) diff --git a/dlls/ntoskrnl.exe/tests/driver4.c b/dlls/ntoskrnl.exe/tests/driver4.c index 2fe6072ec58..d863d748369 100644 --- a/dlls/ntoskrnl.exe/tests/driver4.c +++ b/dlls/ntoskrnl.exe/tests/driver4.c @@ -66,10 +66,14 @@ static void netio_init(void)
client_npi.Dispatch = &client_dispatch; status = WskRegister(&client_npi, ®istration); - todo_wine ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
status = WskCaptureProviderNPI(®istration, WSK_INFINITE_WAIT, &provider_npi); - todo_wine ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + + ok(provider_npi.Dispatch->Version >= MAKE_WSK_VERSION(1, 0), "Got unexpected version %#x.\n", + provider_npi.Dispatch->Version); + ok(!!provider_npi.Client, "Got null WSK_CLIENT.\n"); }
static void netio_uninit(void)