ntoskrnl: Always copy the output buffer for non-buffered ioctls.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30155 Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5af74129bd
commit
7c0f642005
|
@ -440,15 +440,43 @@ static void free_dispatch_irp( struct irp_data *irp_data )
|
|||
free( irp_data );
|
||||
}
|
||||
|
||||
static ULONG get_irp_output_size( IRP *irp )
|
||||
{
|
||||
IO_STACK_LOCATION *stack = IoGetNextIrpStackLocation( irp );
|
||||
|
||||
if (!irp->UserBuffer || (irp->Flags & IRP_WRITE_OPERATION))
|
||||
return 0;
|
||||
|
||||
/* For IRPs not using buffered I/O, the driver is supposed to have direct
|
||||
* access to the user's output buffer, either via an MDL (direct I/O) or
|
||||
* with the raw user VA (neither). We can't fully support this, but we
|
||||
* should at least copy the entire buffer back to the caller. */
|
||||
switch (stack->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
||||
if ((stack->Parameters.DeviceIoControl.IoControlCode & 3) != METHOD_BUFFERED)
|
||||
return stack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
/* FIXME: Handle non-buffered reads. */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (NT_ERROR(irp->IoStatus.u.Status))
|
||||
return 0;
|
||||
return irp->IoStatus.Information;
|
||||
}
|
||||
|
||||
/* transfer result of IRP back to wineserver */
|
||||
static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
|
||||
{
|
||||
struct irp_data *irp_data = context;
|
||||
void *out_buff = irp->UserBuffer;
|
||||
NTSTATUS status;
|
||||
|
||||
if (irp->Flags & IRP_WRITE_OPERATION)
|
||||
out_buff = NULL; /* do not transfer back input buffer */
|
||||
ULONG out_size;
|
||||
|
||||
EnterCriticalSection( &irp_completion_cs );
|
||||
|
||||
|
@ -460,15 +488,14 @@ static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp,
|
|||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
out_size = get_irp_output_size( irp );
|
||||
|
||||
SERVER_START_REQ( set_irp_result )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( irp_data->handle );
|
||||
req->status = irp->IoStatus.u.Status;
|
||||
req->size = irp->IoStatus.Information;
|
||||
if (!NT_ERROR(irp->IoStatus.u.Status))
|
||||
{
|
||||
if (out_buff) wine_server_add_data( req, out_buff, irp->IoStatus.Information );
|
||||
}
|
||||
if (out_size) wine_server_add_data( req, irp->UserBuffer, out_size );
|
||||
status = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
@ -943,17 +970,13 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
|
|||
if (context.irp_data->complete)
|
||||
{
|
||||
/* IRP completed even before we got here; we can report completion now */
|
||||
void *out_buff = irp->UserBuffer;
|
||||
|
||||
if (irp->Flags & IRP_WRITE_OPERATION)
|
||||
out_buff = NULL; /* do not transfer back input buffer */
|
||||
unsigned int out_size = get_irp_output_size( irp );
|
||||
|
||||
req->prev = wine_server_obj_handle( context.irp_data->handle );
|
||||
req->pending = irp->PendingReturned;
|
||||
req->iosb_status = irp->IoStatus.u.Status;
|
||||
req->result = irp->IoStatus.Information;
|
||||
if (!NT_ERROR(irp->IoStatus.u.Status) && out_buff)
|
||||
wine_server_add_data( req, out_buff, irp->IoStatus.Information );
|
||||
if (out_size) wine_server_add_data( req, irp->UserBuffer, out_size );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -679,8 +679,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
else if (!NT_ERROR(params->iosb_status))
|
||||
todo_wine_if (params->iosb_status == STATUS_PENDING) 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);
|
||||
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||
|
||||
strcpy(buffer, "abcdef");
|
||||
io.Status = 0xdeadf00d;
|
||||
|
@ -701,8 +700,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
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);
|
||||
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||
|
||||
/* Test the overlapped case. */
|
||||
|
||||
|
@ -741,8 +739,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
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);
|
||||
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||
|
||||
ret = WaitForSingleObject(file, 0);
|
||||
ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
|
||||
|
@ -793,8 +790,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
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);
|
||||
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);
|
||||
|
@ -825,8 +821,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
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);
|
||||
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||
|
||||
/* Test FILE_SKIP_COMPLETION_PORT_ON_SUCCESS. */
|
||||
|
||||
|
@ -861,8 +856,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
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);
|
||||
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||
|
||||
key = 0xdeadf00d;
|
||||
value = 0xdeadf00d;
|
||||
|
@ -926,8 +920,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
|
|||
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);
|
||||
ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
|
||||
|
||||
ret = SleepEx(0, TRUE);
|
||||
if (!params->pending && NT_ERROR(params->iosb_status))
|
||||
|
|
Loading…
Reference in New Issue