ntoskrnl/tests: Add more tests for IRP status handling.
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a5b1d51594
commit
8d37962b43
|
@ -2395,22 +2395,64 @@ static NTSTATUS get_fscontext(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *inf
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS return_status(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
|
static NTSTATUS return_status(IRP *irp, IO_STACK_LOCATION *stack, ULONG code)
|
||||||
{
|
{
|
||||||
char *buffer = irp->AssociatedIrp.SystemBuffer;
|
ULONG input_length = stack->Parameters.DeviceIoControl.InputBufferLength;
|
||||||
NTSTATUS ret;
|
ULONG output_length = stack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||||
|
const struct return_status_params *input_buffer;
|
||||||
|
struct return_status_params params;
|
||||||
|
void *output_buffer;
|
||||||
|
|
||||||
if (!buffer)
|
if (code == IOCTL_WINETEST_RETURN_STATUS_NEITHER)
|
||||||
|
{
|
||||||
|
input_buffer = stack->Parameters.DeviceIoControl.Type3InputBuffer;
|
||||||
|
output_buffer = irp->UserBuffer;
|
||||||
|
}
|
||||||
|
else if (code == IOCTL_WINETEST_RETURN_STATUS_DIRECT)
|
||||||
|
{
|
||||||
|
input_buffer = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
output_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input_buffer = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
output_buffer = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input_buffer || !output_buffer)
|
||||||
|
{
|
||||||
|
irp->IoStatus.Status = STATUS_ACCESS_VIOLATION;
|
||||||
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||||
return STATUS_ACCESS_VIOLATION;
|
return STATUS_ACCESS_VIOLATION;
|
||||||
|
}
|
||||||
|
|
||||||
if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DWORD)
|
if (input_length < sizeof(params) || output_length < 6)
|
||||||
|| stack->Parameters.DeviceIoControl.OutputBufferLength < 3)
|
{
|
||||||
|
irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||||
return STATUS_BUFFER_TOO_SMALL;
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = *(DWORD *)irp->AssociatedIrp.SystemBuffer;
|
params = *input_buffer;
|
||||||
memcpy(buffer, "ghi", 3);
|
|
||||||
*info = 3;
|
if (params.ret_status == STATUS_PENDING && !params.pending)
|
||||||
return ret;
|
{
|
||||||
|
/* this causes kernel hangs under certain conditions */
|
||||||
|
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||||||
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.pending)
|
||||||
|
IoMarkIrpPending(irp);
|
||||||
|
|
||||||
|
/* intentionally report the wrong information (and status) */
|
||||||
|
memcpy(output_buffer, "ghijkl", 6);
|
||||||
|
irp->IoStatus.Information = 3;
|
||||||
|
irp->IoStatus.Status = params.iosb_status;
|
||||||
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||||
|
|
||||||
|
return params.ret_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
|
static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
|
||||||
|
@ -2430,34 +2472,6 @@ static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG
|
||||||
return ZwUnloadDriver(&name);
|
return ZwUnloadDriver(&name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS test_mismatched_status_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
|
|
||||||
{
|
|
||||||
ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
||||||
char *buffer = irp->UserBuffer;
|
|
||||||
|
|
||||||
if (!buffer)
|
|
||||||
{
|
|
||||||
irp->IoStatus.Status = STATUS_ACCESS_VIOLATION;
|
|
||||||
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
||||||
return STATUS_ACCESS_VIOLATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length < sizeof(teststr))
|
|
||||||
{
|
|
||||||
irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
|
|
||||||
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
||||||
return STATUS_BUFFER_TOO_SMALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer, teststr, sizeof(teststr));
|
|
||||||
|
|
||||||
/* This is deliberate; some broken drivers do this */
|
|
||||||
*info = 0;
|
|
||||||
irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
||||||
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS completion_ioctl(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack)
|
static NTSTATUS completion_ioctl(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack)
|
||||||
{
|
{
|
||||||
if (device == upper_device)
|
if (device == upper_device)
|
||||||
|
@ -2564,15 +2578,14 @@ static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp)
|
||||||
case IOCTL_WINETEST_GET_FSCONTEXT:
|
case IOCTL_WINETEST_GET_FSCONTEXT:
|
||||||
status = get_fscontext(irp, stack, &irp->IoStatus.Information);
|
status = get_fscontext(irp, stack, &irp->IoStatus.Information);
|
||||||
break;
|
break;
|
||||||
case IOCTL_WINETEST_RETURN_STATUS:
|
case IOCTL_WINETEST_RETURN_STATUS_BUFFERED:
|
||||||
status = return_status(irp, stack, &irp->IoStatus.Information);
|
case IOCTL_WINETEST_RETURN_STATUS_DIRECT:
|
||||||
break;
|
case IOCTL_WINETEST_RETURN_STATUS_NEITHER:
|
||||||
|
return return_status(irp, stack, stack->Parameters.DeviceIoControl.IoControlCode);
|
||||||
case IOCTL_WINETEST_DETACH:
|
case IOCTL_WINETEST_DETACH:
|
||||||
IoDetachDevice(lower_device);
|
IoDetachDevice(lower_device);
|
||||||
status = STATUS_SUCCESS;
|
status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
case IOCTL_WINETEST_MISMATCHED_STATUS:
|
|
||||||
return test_mismatched_status_ioctl(irp, stack, &irp->IoStatus.Information);
|
|
||||||
case IOCTL_WINETEST_COMPLETION:
|
case IOCTL_WINETEST_COMPLETION:
|
||||||
return completion_ioctl(device, irp, stack);
|
return completion_ioctl(device, irp, stack);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -32,11 +32,10 @@
|
||||||
#define IOCTL_WINETEST_GET_CREATE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_GET_CREATE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_GET_CLOSE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_GET_CLOSE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_GET_FSCONTEXT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_GET_FSCONTEXT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_RETURN_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_RETURN_STATUS_BUFFERED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_MISMATCHED_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80b, METHOD_NEITHER, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_RETURN_STATUS_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||||
|
#define IOCTL_WINETEST_RETURN_STATUS_NEITHER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_COMPLETION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_NEITHER, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_COMPLETION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_MARK_PENDING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_NEITHER, FILE_ANY_ACCESS)
|
|
||||||
#define IOCTL_WINETEST_CHECK_REMOVED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80e, METHOD_NEITHER, FILE_ANY_ACCESS)
|
|
||||||
|
|
||||||
#define IOCTL_WINETEST_BUS_MAIN CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_BUS_MAIN CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_WINETEST_BUS_REGISTER_IFACE CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_BUS_REGISTER_IFACE CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
|
@ -46,6 +45,8 @@
|
||||||
#define IOCTL_WINETEST_BUS_REMOVE_CHILD CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_BUS_REMOVE_CHILD CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
|
|
||||||
#define IOCTL_WINETEST_CHILD_GET_ID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
#define IOCTL_WINETEST_CHILD_GET_ID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
|
#define IOCTL_WINETEST_CHILD_MARK_PENDING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
#define IOCTL_WINETEST_CHILD_CHECK_REMOVED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
|
||||||
static const char teststr[] = "Wine is not an emulator";
|
static const char teststr[] = "Wine is not an emulator";
|
||||||
|
|
||||||
|
@ -65,6 +66,13 @@ struct main_test_input
|
||||||
ULONG64 *modified_value;
|
ULONG64 *modified_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct return_status_params
|
||||||
|
{
|
||||||
|
NTSTATUS ret_status;
|
||||||
|
NTSTATUS iosb_status;
|
||||||
|
BOOL pending;
|
||||||
|
};
|
||||||
|
|
||||||
static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}};
|
static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}};
|
||||||
|
|
||||||
#define SERVER_LISTEN_PORT 9374
|
#define SERVER_LISTEN_PORT 9374
|
||||||
|
|
|
@ -276,7 +276,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
|
||||||
}
|
}
|
||||||
|
|
||||||
case IRP_MN_REMOVE_DEVICE:
|
case IRP_MN_REMOVE_DEVICE:
|
||||||
/* should've been checked and reset by IOCTL_WINETEST_CHECK_REMOVED */
|
/* should've been checked and reset by IOCTL_WINETEST_CHILD_CHECK_REMOVED */
|
||||||
ok(remove_device_count == 0, "expected no IRP_MN_REMOVE_DEVICE\n");
|
ok(remove_device_count == 0, "expected no IRP_MN_REMOVE_DEVICE\n");
|
||||||
todo_wine ok(surprise_removal_count == 0, "expected no IRP_MN_SURPRISE_REMOVAL\n");
|
todo_wine ok(surprise_removal_count == 0, "expected no IRP_MN_SURPRISE_REMOVAL\n");
|
||||||
ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n");
|
ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n");
|
||||||
|
@ -665,12 +665,12 @@ static NTSTATUS pdo_ioctl(DEVICE_OBJECT *device_obj, IRP *irp, IO_STACK_LOCATION
|
||||||
irp->IoStatus.Information = sizeof(device->id);
|
irp->IoStatus.Information = sizeof(device->id);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
case IOCTL_WINETEST_MARK_PENDING:
|
case IOCTL_WINETEST_CHILD_MARK_PENDING:
|
||||||
IoMarkIrpPending(irp);
|
IoMarkIrpPending(irp);
|
||||||
irp_queue_push(&device->irp_queue, irp);
|
irp_queue_push(&device->irp_queue, irp);
|
||||||
return STATUS_PENDING;
|
return STATUS_PENDING;
|
||||||
|
|
||||||
case IOCTL_WINETEST_CHECK_REMOVED:
|
case IOCTL_WINETEST_CHILD_CHECK_REMOVED:
|
||||||
ok(remove_device_count == 0, "expected IRP_MN_REMOVE_DEVICE\n");
|
ok(remove_device_count == 0, "expected IRP_MN_REMOVE_DEVICE\n");
|
||||||
ok(surprise_removal_count == 1, "expected IRP_MN_SURPRISE_REMOVAL\n");
|
ok(surprise_removal_count == 1, "expected IRP_MN_SURPRISE_REMOVAL\n");
|
||||||
ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n");
|
ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n");
|
||||||
|
|
|
@ -430,18 +430,6 @@ static void test_basic_ioctl(void)
|
||||||
ok(!strcmp(buf, "Wine is no"), "got '%s'\n", buf);
|
ok(!strcmp(buf, "Wine is no"), "got '%s'\n", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mismatched_status_ioctl(void)
|
|
||||||
{
|
|
||||||
DWORD written;
|
|
||||||
char buf[32];
|
|
||||||
BOOL res;
|
|
||||||
|
|
||||||
res = DeviceIoControl(device, IOCTL_WINETEST_MISMATCHED_STATUS, NULL, 0, buf,
|
|
||||||
sizeof(buf), &written, NULL);
|
|
||||||
todo_wine ok(res, "DeviceIoControl failed: %u\n", GetLastError());
|
|
||||||
todo_wine ok(!strcmp(buf, teststr), "got '%s'\n", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_overlapped(void)
|
static void test_overlapped(void)
|
||||||
{
|
{
|
||||||
OVERLAPPED overlapped, overlapped2, *o;
|
OVERLAPPED overlapped, overlapped2, *o;
|
||||||
|
@ -631,72 +619,376 @@ static void test_file_handles(void)
|
||||||
ok(count == 3, "got %u\n", count);
|
ok(count == 3, "got %u\n", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_return_status(void)
|
static unsigned int got_return_status_apc;
|
||||||
|
|
||||||
|
static void WINAPI return_status_apc(void *apc_user, IO_STATUS_BLOCK *io, ULONG reserved)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
++got_return_status_apc;
|
||||||
|
ok(apc_user == (void *)456, "got %p\n", apc_user);
|
||||||
|
ok(!reserved, "got reserved %#x\n", reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
||||||
|
{
|
||||||
|
const char *expect_buffer;
|
||||||
|
LARGE_INTEGER zero = {{0}};
|
||||||
|
HANDLE file, port, event;
|
||||||
|
NTSTATUS expect_status;
|
||||||
|
ULONG_PTR key, value;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
char buffer[7];
|
char buffer[7];
|
||||||
DWORD ret_size;
|
DWORD size;
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
|
|
||||||
strcpy(buffer, "abcdef");
|
if (params->ret_status == STATUS_PENDING && !params->pending)
|
||||||
status = STATUS_SUCCESS;
|
{
|
||||||
SetLastError(0xdeadbeef);
|
/* this causes kernel hangs under certain conditions */
|
||||||
ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status,
|
return;
|
||||||
sizeof(status), buffer, sizeof(buffer), &ret_size, NULL);
|
}
|
||||||
ok(ret, "ioctl failed\n");
|
|
||||||
ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError());
|
event = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||||
ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer);
|
|
||||||
ok(ret_size == 3, "got size %u\n", ret_size);
|
if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
expect_buffer = "ghijkl";
|
||||||
|
else if (NT_ERROR(params->iosb_status))
|
||||||
|
expect_buffer = "abcdef";
|
||||||
|
else
|
||||||
|
expect_buffer = "ghidef";
|
||||||
|
|
||||||
|
/* Test the non-overlapped case. */
|
||||||
|
|
||||||
|
expect_status = (params->ret_status == STATUS_PENDING ? params->iosb_status : params->ret_status);
|
||||||
|
|
||||||
strcpy(buffer, "abcdef");
|
strcpy(buffer, "abcdef");
|
||||||
status = STATUS_TIMEOUT;
|
size = 0xdeadf00d;
|
||||||
SetLastError(0xdeadbeef);
|
SetLastError(0xdeadf00d);
|
||||||
ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status,
|
ret = DeviceIoControl(device, ioctl, params, sizeof(*params), buffer, sizeof(buffer), &size, NULL);
|
||||||
sizeof(status), buffer, sizeof(buffer), &ret_size, NULL);
|
todo_wine_if (NT_SUCCESS(expect_status) != !params->iosb_status)
|
||||||
todo_wine ok(ret, "ioctl failed\n");
|
ok(ret == NT_SUCCESS(expect_status), "got %d\n", ret);
|
||||||
todo_wine ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError());
|
if (NT_SUCCESS(expect_status))
|
||||||
ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer);
|
{
|
||||||
ok(ret_size == 3, "got size %u\n", ret_size);
|
todo_wine_if (params->iosb_status)
|
||||||
|
ok(GetLastError() == 0xdeadf00d, "got error %u\n", GetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (RtlNtStatusToDosError(expect_status) != RtlNtStatusToDosError(params->iosb_status)
|
||||||
|
|| params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(GetLastError() == RtlNtStatusToDosError(expect_status), "got error %u\n", GetLastError());
|
||||||
|
}
|
||||||
|
if (NT_ERROR(expect_status))
|
||||||
|
todo_wine ok(size == 0xdeadf00d, "got size %u\n", size);
|
||||||
|
else if (!NT_ERROR(params->iosb_status))
|
||||||
|
ok(size == 3, "got size %u\n", size);
|
||||||
|
/* size is garbage if !NT_ERROR(expect_status) && NT_ERROR(iosb_status) */
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
strcpy(buffer, "abcdef");
|
strcpy(buffer, "abcdef");
|
||||||
status = 0x0eadbeef;
|
io.Status = 0xdeadf00d;
|
||||||
SetLastError(0xdeadbeef);
|
io.Information = 0xdeadf00d;
|
||||||
ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status,
|
ret = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io,
|
||||||
sizeof(status), buffer, sizeof(buffer), &ret_size, NULL);
|
ioctl, params, sizeof(*params), buffer, sizeof(buffer));
|
||||||
todo_wine ok(ret, "ioctl failed\n");
|
todo_wine_if ((params->ret_status != params->iosb_status && params->ret_status != STATUS_PENDING)
|
||||||
todo_wine ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError());
|
|| params->iosb_status == STATUS_PENDING)
|
||||||
ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer);
|
ok(ret == expect_status, "got %#x\n", ret);
|
||||||
ok(ret_size == 3, "got size %u\n", ret_size);
|
if (NT_ERROR(params->iosb_status))
|
||||||
|
{
|
||||||
|
todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status);
|
||||||
|
todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got size %Iu\n", io.Information);
|
||||||
|
}
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
|
/* Test the overlapped case. */
|
||||||
|
|
||||||
|
file = CreateFileA("\\\\.\\WineTestDriver", FILE_ALL_ACCESS,
|
||||||
|
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||||
|
ok(file != INVALID_HANDLE_VALUE, "failed to open device, error %u\n", GetLastError());
|
||||||
|
port = CreateIoCompletionPort(file, NULL, 123, 0);
|
||||||
|
ok(port != NULL, "failed to create port, error %u\n", GetLastError());
|
||||||
|
|
||||||
|
ret = WaitForSingleObject(file, 0);
|
||||||
|
todo_wine ok(!ret, "got %d\n", ret);
|
||||||
|
|
||||||
|
ResetEvent(event);
|
||||||
|
strcpy(buffer, "abcdef");
|
||||||
|
io.Status = 0xdeadf00d;
|
||||||
|
io.Information = 0xdeadf00d;
|
||||||
|
ret = NtDeviceIoControlFile(file, event, NULL, (void *)456, &io,
|
||||||
|
ioctl, params, sizeof(*params), buffer, sizeof(buffer));
|
||||||
|
todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING)
|
||||||
|
ok(ret == params->ret_status
|
||||||
|
|| broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */
|
||||||
|
"got %#x\n", ret);
|
||||||
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
|
{
|
||||||
|
todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status);
|
||||||
|
todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(event, 0);
|
||||||
|
todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(event, 0);
|
||||||
|
ok(!ret, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
|
ret = WaitForSingleObject(file, 0);
|
||||||
|
ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||||
|
|
||||||
|
key = 0xdeadf00d;
|
||||||
|
value = 0xdeadf00d;
|
||||||
|
memset(&io, 0xcc, sizeof(io));
|
||||||
|
ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero);
|
||||||
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
|
{
|
||||||
|
todo_wine ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(!ret, "got %#x\n", ret);
|
||||||
|
ok(key == 123, "got key %Iu\n", key);
|
||||||
|
ok(value == 456, "got value %Iu\n", value);
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got information %Iu\n", io.Information);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As above, but set the event first, to show that the event is always
|
||||||
|
* reset. */
|
||||||
|
ResetEvent(event);
|
||||||
|
strcpy(buffer, "abcdef");
|
||||||
|
io.Status = 0xdeadf00d;
|
||||||
|
io.Information = 0xdeadf00d;
|
||||||
|
ret = NtDeviceIoControlFile(file, event, NULL, NULL, &io,
|
||||||
|
ioctl, params, sizeof(*params), buffer, sizeof(buffer));
|
||||||
|
todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING)
|
||||||
|
ok(ret == params->ret_status
|
||||||
|
|| broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */
|
||||||
|
"got %#x\n", ret);
|
||||||
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
|
{
|
||||||
|
todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status);
|
||||||
|
todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(event, 0);
|
||||||
|
todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(event, 0);
|
||||||
|
ok(!ret, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
|
/* As above, but use the file handle instead of an event. */
|
||||||
|
ret = WaitForSingleObject(file, 0);
|
||||||
|
ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||||
|
|
||||||
strcpy(buffer, "abcdef");
|
strcpy(buffer, "abcdef");
|
||||||
status = 0x4eadbeef;
|
io.Status = 0xdeadf00d;
|
||||||
SetLastError(0xdeadbeef);
|
io.Information = 0xdeadf00d;
|
||||||
ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status,
|
ret = NtDeviceIoControlFile(file, NULL, NULL, NULL, &io,
|
||||||
sizeof(status), buffer, sizeof(buffer), &ret_size, NULL);
|
ioctl, params, sizeof(*params), buffer, sizeof(buffer));
|
||||||
todo_wine ok(ret, "ioctl failed\n");
|
todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING)
|
||||||
todo_wine ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError());
|
ok(ret == params->ret_status
|
||||||
ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer);
|
|| broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */
|
||||||
ok(ret_size == 3, "got size %u\n", ret_size);
|
"got %#x\n", ret);
|
||||||
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
|
{
|
||||||
|
todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status);
|
||||||
|
todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(file, 0);
|
||||||
|
todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(file, 0);
|
||||||
|
ok(!ret, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
|
/* Test FILE_SKIP_COMPLETION_PORT_ON_SUCCESS. */
|
||||||
|
|
||||||
|
if (pSetFileCompletionNotificationModes)
|
||||||
|
{
|
||||||
|
ret = pSetFileCompletionNotificationModes(file, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
|
||||||
|
ok(ret, "got error %u\n", GetLastError());
|
||||||
|
|
||||||
|
SetEvent(event);
|
||||||
|
strcpy(buffer, "abcdef");
|
||||||
|
io.Status = 0xdeadf00d;
|
||||||
|
io.Information = 0xdeadf00d;
|
||||||
|
ret = NtDeviceIoControlFile(file, event, NULL, (void *)456, &io,
|
||||||
|
ioctl, params, sizeof(*params), buffer, sizeof(buffer));
|
||||||
|
todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING)
|
||||||
|
ok(ret == params->ret_status
|
||||||
|
|| broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */
|
||||||
|
"got %#x\n", ret);
|
||||||
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
|
{
|
||||||
|
todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status);
|
||||||
|
todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(event, 0);
|
||||||
|
todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got size %Iu\n", io.Information);
|
||||||
|
ret = WaitForSingleObject(event, 0);
|
||||||
|
ok(!ret, "got %d\n", ret);
|
||||||
|
}
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
|
key = 0xdeadf00d;
|
||||||
|
value = 0xdeadf00d;
|
||||||
|
memset(&io, 0xcc, sizeof(io));
|
||||||
|
ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero);
|
||||||
|
if (!params->pending)
|
||||||
|
{
|
||||||
|
/* Completion is skipped on non-pending NT_ERROR regardless of file
|
||||||
|
* options. Windows < 8 interprets
|
||||||
|
* FILE_SKIP_COMPLETION_PORT_ON_SUCCESS to mean that !NT_ERROR
|
||||||
|
* should also be skipped. Windows >= 8 restricts this to
|
||||||
|
* NT_SUCCESS, which has the weird effect that non-pending
|
||||||
|
* NT_WARNING does *not* skip completion. It's not clear whether
|
||||||
|
* this is a bug or not—it looks like one, but on the other hand it
|
||||||
|
* arguably follows the letter of the documentation more closely. */
|
||||||
|
ok(ret == STATUS_TIMEOUT || (NT_WARNING(params->iosb_status) && !ret), "got %#x\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine ok(!ret, "got %#x\n", ret);
|
||||||
|
}
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
ok(key == 123, "got key %Iu\n", key);
|
||||||
|
ok(value == 456, "got value %Iu\n", value);
|
||||||
|
ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got information %Iu\n", io.Information);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = CloseHandle(file);
|
||||||
|
ok(ret, "failed to close file, error %u\n", GetLastError());
|
||||||
|
ret = CloseHandle(port);
|
||||||
|
ok(ret, "failed to close port, error %u\n", GetLastError());
|
||||||
|
|
||||||
|
/* Test with an APC. */
|
||||||
|
|
||||||
|
got_return_status_apc = 0;
|
||||||
|
|
||||||
|
file = CreateFileA("\\\\.\\WineTestDriver", FILE_ALL_ACCESS,
|
||||||
|
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||||
|
ok(file != INVALID_HANDLE_VALUE, "failed to open device, error %u\n", GetLastError());
|
||||||
|
|
||||||
strcpy(buffer, "abcdef");
|
strcpy(buffer, "abcdef");
|
||||||
status = 0x8eadbeef;
|
io.Status = 0xdeadf00d;
|
||||||
SetLastError(0xdeadbeef);
|
io.Information = 0xdeadf00d;
|
||||||
ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status,
|
ret = NtDeviceIoControlFile(file, NULL, return_status_apc, (void *)456, &io,
|
||||||
sizeof(status), buffer, sizeof(buffer), &ret_size, NULL);
|
ioctl, params, sizeof(*params), buffer, sizeof(buffer));
|
||||||
ok(!ret, "ioctl succeeded\n");
|
todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING)
|
||||||
ok(GetLastError() == ERROR_MR_MID_NOT_FOUND, "got error %u\n", GetLastError());
|
ok(ret == params->ret_status, "got %#x\n", ret);
|
||||||
ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer);
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
ok(ret_size == 3, "got size %u\n", ret_size);
|
{
|
||||||
|
todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status);
|
||||||
|
todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
todo_wine_if (params->iosb_status == STATUS_PENDING)
|
||||||
|
ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
|
||||||
|
ok(io.Information == 3, "got size %Iu\n", io.Information);
|
||||||
|
}
|
||||||
|
todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED)
|
||||||
|
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||||
|
|
||||||
strcpy(buffer, "abcdef");
|
ret = SleepEx(0, TRUE);
|
||||||
status = 0xceadbeef;
|
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||||
SetLastError(0xdeadbeef);
|
{
|
||||||
ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status,
|
todo_wine ok(!ret, "got %d\n", ret);
|
||||||
sizeof(status), buffer, sizeof(buffer), &ret_size, NULL);
|
todo_wine ok(!got_return_status_apc, "got %u APC calls\n", got_return_status_apc);
|
||||||
ok(!ret, "ioctl succeeded\n");
|
}
|
||||||
ok(GetLastError() == ERROR_MR_MID_NOT_FOUND, "got error %u\n", GetLastError());
|
else
|
||||||
ok(!strcmp(buffer, "abcdef"), "got buffer %s\n", buffer);
|
{
|
||||||
ok(ret_size == 3, "got size %u\n", ret_size);
|
ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret);
|
||||||
|
ok(got_return_status_apc == 1, "got %u APC calls\n", got_return_status_apc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = CloseHandle(file);
|
||||||
|
ok(ret, "failed to close file, error %u\n", GetLastError());
|
||||||
|
|
||||||
|
CloseHandle(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_return_status(void)
|
||||||
|
{
|
||||||
|
struct return_status_params params;
|
||||||
|
unsigned int i, j, k;
|
||||||
|
|
||||||
|
static const ULONG method_tests[] =
|
||||||
|
{
|
||||||
|
IOCTL_WINETEST_RETURN_STATUS_BUFFERED,
|
||||||
|
IOCTL_WINETEST_RETURN_STATUS_DIRECT,
|
||||||
|
IOCTL_WINETEST_RETURN_STATUS_NEITHER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NTSTATUS status_tests[] =
|
||||||
|
{
|
||||||
|
STATUS_SUCCESS,
|
||||||
|
STATUS_PENDING,
|
||||||
|
STATUS_TIMEOUT,
|
||||||
|
0x0eadbeef,
|
||||||
|
0x4eadbeef,
|
||||||
|
STATUS_BUFFER_OVERFLOW,
|
||||||
|
0x8eadbeef,
|
||||||
|
STATUS_NOT_IMPLEMENTED,
|
||||||
|
0xceadbeef,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(status_tests); ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < ARRAY_SIZE(status_tests); ++j)
|
||||||
|
{
|
||||||
|
for (params.pending = 0; params.pending <= 1; ++params.pending)
|
||||||
|
{
|
||||||
|
for (k = 0; k < ARRAY_SIZE(method_tests); ++k)
|
||||||
|
{
|
||||||
|
params.ret_status = status_tests[i];
|
||||||
|
params.iosb_status = status_tests[j];
|
||||||
|
|
||||||
|
winetest_push_context("return 0x%08x, iosb 0x%08x, pending %d, method %u",
|
||||||
|
params.ret_status, params.iosb_status, params.pending, method_tests[k] & 3);
|
||||||
|
|
||||||
|
do_return_status(method_tests[k], ¶ms);
|
||||||
|
|
||||||
|
winetest_pop_context();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL compare_unicode_string(const WCHAR *buffer, ULONG len, const WCHAR *expect)
|
static BOOL compare_unicode_string(const WCHAR *buffer, ULONG len, const WCHAR *expect)
|
||||||
|
@ -765,13 +1057,25 @@ static void test_object_info(void)
|
||||||
ok(compare_unicode_string(file_info->FileName, file_info->FileNameLength, L"\\subfile"),
|
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)));
|
"wrong name %s\n", debugstr_wn(file_info->FileName, file_info->FileNameLength / sizeof(WCHAR)));
|
||||||
|
|
||||||
|
io.Status = 0xdeadf00d;
|
||||||
|
io.Information = 0xdeadf00d;
|
||||||
status = NtQueryVolumeInformationFile(file, &io, buffer, sizeof(buffer), FileFsVolumeInformation);
|
status = NtQueryVolumeInformationFile(file, &io, buffer, sizeof(buffer), FileFsVolumeInformation);
|
||||||
ok(!status, "got %#x\n", status);
|
ok(!status, "got %#x\n", status);
|
||||||
|
ok(!io.Status, "got status %#x\n", io.Status);
|
||||||
|
size = offsetof(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + volume_info->VolumeLabelLength;
|
||||||
|
ok(io.Information == size, "expected information %Iu, got %Iu\n", size, io.Information);
|
||||||
ok(volume_info->VolumeSerialNumber == 0xdeadbeef,
|
ok(volume_info->VolumeSerialNumber == 0xdeadbeef,
|
||||||
"wrong serial number 0x%08x\n", volume_info->VolumeSerialNumber);
|
"wrong serial number 0x%08x\n", volume_info->VolumeSerialNumber);
|
||||||
ok(compare_unicode_string(volume_info->VolumeLabel, volume_info->VolumeLabelLength, L"WineTestDriver"),
|
ok(compare_unicode_string(volume_info->VolumeLabel, volume_info->VolumeLabelLength, L"WineTestDriver"),
|
||||||
"wrong name %s\n", debugstr_wn(volume_info->VolumeLabel, volume_info->VolumeLabelLength / sizeof(WCHAR)));
|
"wrong name %s\n", debugstr_wn(volume_info->VolumeLabel, volume_info->VolumeLabelLength / sizeof(WCHAR)));
|
||||||
|
|
||||||
|
io.Status = 0xdeadf00d;
|
||||||
|
io.Information = 0xdeadf00d;
|
||||||
|
status = NtQueryVolumeInformationFile(file, &io, buffer, sizeof(buffer), FileFsAttributeInformation);
|
||||||
|
ok(status == STATUS_NOT_IMPLEMENTED, "got %#x\n", status);
|
||||||
|
ok(io.Status == 0xdeadf00d, "got status %#x\n", io.Status);
|
||||||
|
ok(io.Information == 0xdeadf00d, "got information %Iu\n", io.Information);
|
||||||
|
|
||||||
CloseHandle(file);
|
CloseHandle(file);
|
||||||
|
|
||||||
file = CreateFileA("\\\\.\\WineTestDriver\\notimpl", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
file = CreateFileA("\\\\.\\WineTestDriver\\notimpl", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
@ -1354,7 +1658,7 @@ static void test_pnp_devices(void)
|
||||||
ret = NtOpenFile(&child, SYNCHRONIZE, &attr, &io, 0, 0);
|
ret = NtOpenFile(&child, SYNCHRONIZE, &attr, &io, 0, 0);
|
||||||
ok(!ret, "failed to open child: %#x\n", ret);
|
ok(!ret, "failed to open child: %#x\n", ret);
|
||||||
|
|
||||||
ret = DeviceIoControl(child, IOCTL_WINETEST_MARK_PENDING, NULL, 0, NULL, 0, &size, &ovl);
|
ret = DeviceIoControl(child, IOCTL_WINETEST_CHILD_MARK_PENDING, NULL, 0, NULL, 0, &size, &ovl);
|
||||||
ok(!ret, "DeviceIoControl succeeded\n");
|
ok(!ret, "DeviceIoControl succeeded\n");
|
||||||
ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError());
|
ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError());
|
||||||
ok(size == 0, "got size %u\n", size);
|
ok(size == 0, "got size %u\n", size);
|
||||||
|
@ -1367,7 +1671,7 @@ static void test_pnp_devices(void)
|
||||||
ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival);
|
ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival);
|
||||||
ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal);
|
ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal);
|
||||||
|
|
||||||
ret = DeviceIoControl(child, IOCTL_WINETEST_CHECK_REMOVED, NULL, 0, NULL, 0, &size, NULL);
|
ret = DeviceIoControl(child, IOCTL_WINETEST_CHILD_CHECK_REMOVED, NULL, 0, NULL, 0, &size, NULL);
|
||||||
todo_wine ok(ret, "got error %u\n", GetLastError());
|
todo_wine ok(ret, "got error %u\n", GetLastError());
|
||||||
|
|
||||||
ret = NtOpenFile(&tmp, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT);
|
ret = NtOpenFile(&tmp, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
@ -3162,7 +3466,6 @@ START_TEST(ntoskrnl)
|
||||||
ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError());
|
ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError());
|
||||||
|
|
||||||
test_basic_ioctl();
|
test_basic_ioctl();
|
||||||
test_mismatched_status_ioctl();
|
|
||||||
|
|
||||||
main_test();
|
main_test();
|
||||||
todo_wine ok(modified_value == 0xdeadbeeffeedcafe, "Got unexpected value %#I64x.\n", modified_value);
|
todo_wine ok(modified_value == 0xdeadbeeffeedcafe, "Got unexpected value %#I64x.\n", modified_value);
|
||||||
|
|
Loading…
Reference in New Issue