Alexandre Julliard : ntdll: Fallback to server calls for read and write on objects without a file descriptor.
Alexandre Julliard
julliard at wine.codeweavers.com
Wed May 6 09:29:04 CDT 2015
Module: wine
Branch: master
Commit: c07a0561dbaba98305aa2bf8744d5c65a2043094
URL: http://source.winehq.org/git/wine.git/?a=commit;h=c07a0561dbaba98305aa2bf8744d5c65a2043094
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue May 5 13:35:57 2015 +0900
ntdll: Fallback to server calls for read and write on objects without a file descriptor.
---
dlls/ntdll/file.c | 179 ++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 140 insertions(+), 39 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index d25c792..e43ef41 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -353,6 +353,14 @@ struct async_fileio_write
unsigned int count;
};
+struct async_irp
+{
+ struct async_fileio io;
+ HANDLE event; /* async event */
+ void *buffer; /* buffer for output */
+ ULONG size; /* size of buffer */
+};
+
static struct async_fileio *fileio_freelist;
static void release_fileio( struct async_fileio *io )
@@ -387,6 +395,33 @@ static struct async_fileio *alloc_fileio( DWORD size, HANDLE handle, PIO_APC_ROU
return io;
}
+/* callback for irp async I/O completion */
+static NTSTATUS irp_completion( void *user, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc, void **arg )
+{
+ struct async_irp *async = user;
+
+ if (status == STATUS_ALERTED)
+ {
+ SERVER_START_REQ( get_irp_result )
+ {
+ req->handle = wine_server_obj_handle( async->io.handle );
+ req->user_arg = wine_server_client_ptr( async );
+ wine_server_set_reply( req, async->buffer, async->size );
+ status = wine_server_call( req );
+ if (status != STATUS_PENDING) io->Information = reply->size;
+ }
+ SERVER_END_REQ;
+ }
+ if (status != STATUS_PENDING)
+ {
+ io->u.Status = status;
+ *apc = async->io.apc;
+ *arg = async->io.apc_arg;
+ release_fileio( &async->io );
+ }
+ return status;
+}
+
/***********************************************************************
* FILE_GetNtStatus(void)
*
@@ -499,6 +534,102 @@ static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb,
return status;
}
+/* do a read call through the server */
+static NTSTATUS server_read_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
+ IO_STATUS_BLOCK *io, void *buffer, ULONG size,
+ LARGE_INTEGER *offset, ULONG *key )
+{
+ struct async_irp *async;
+ NTSTATUS status;
+ HANDLE wait_handle;
+ ULONG options;
+ ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
+
+ if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
+ return STATUS_NO_MEMORY;
+
+ async->event = event;
+ async->buffer = buffer;
+ async->size = size;
+
+ SERVER_START_REQ( read )
+ {
+ req->blocking = !apc && !event && !cvalue;
+ req->async.handle = wine_server_obj_handle( handle );
+ req->async.callback = wine_server_client_ptr( irp_completion );
+ req->async.iosb = wine_server_client_ptr( io );
+ req->async.arg = wine_server_client_ptr( async );
+ req->async.event = wine_server_obj_handle( event );
+ req->async.cvalue = cvalue;
+ req->pos = offset ? offset->QuadPart : 0;
+ wine_server_set_reply( req, buffer, size );
+ status = wine_server_call( req );
+ wait_handle = wine_server_ptr_handle( reply->wait );
+ options = reply->options;
+ if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
+ }
+ SERVER_END_REQ;
+
+ if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
+
+ if (wait_handle)
+ {
+ NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
+ status = io->u.Status;
+ NtClose( wait_handle );
+ }
+
+ return status;
+}
+
+/* do a write call through the server */
+static NTSTATUS server_write_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
+ IO_STATUS_BLOCK *io, const void *buffer, ULONG size,
+ LARGE_INTEGER *offset, ULONG *key )
+{
+ struct async_irp *async;
+ NTSTATUS status;
+ HANDLE wait_handle;
+ ULONG options;
+ ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
+
+ if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
+ return STATUS_NO_MEMORY;
+
+ async->event = event;
+ async->buffer = NULL;
+ async->size = 0;
+
+ SERVER_START_REQ( write )
+ {
+ req->blocking = !apc && !event && !cvalue;
+ req->async.handle = wine_server_obj_handle( handle );
+ req->async.callback = wine_server_client_ptr( irp_completion );
+ req->async.iosb = wine_server_client_ptr( io );
+ req->async.arg = wine_server_client_ptr( async );
+ req->async.event = wine_server_obj_handle( event );
+ req->async.cvalue = cvalue;
+ req->pos = offset ? offset->QuadPart : 0;
+ wine_server_add_data( req, buffer, size );
+ status = wine_server_call( req );
+ wait_handle = wine_server_ptr_handle( reply->wait );
+ options = reply->options;
+ if (status != STATUS_PENDING) io->Information = reply->size;
+ }
+ SERVER_END_REQ;
+
+ if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
+
+ if (wait_handle)
+ {
+ NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL );
+ status = io->u.Status;
+ NtClose( wait_handle );
+ }
+
+ return status;
+}
+
struct io_timeouts
{
int interval; /* max interval between two bytes */
@@ -675,6 +806,9 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options );
+ if (status == STATUS_BAD_DEVICE_TYPE)
+ return server_read_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
+
if (status) return status;
async_read = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
@@ -1056,6 +1190,9 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options );
+ if (status == STATUS_BAD_DEVICE_TYPE)
+ return server_write_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
+
if (status == STATUS_ACCESS_DENIED)
{
status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
@@ -1352,42 +1489,6 @@ NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
}
-struct async_ioctl
-{
- struct async_fileio io;
- HANDLE event; /* async event */
- void *buffer; /* buffer for output */
- ULONG size; /* size of buffer */
-};
-
-/* callback for ioctl async I/O completion */
-static NTSTATUS ioctl_completion( void *user, IO_STATUS_BLOCK *io,
- NTSTATUS status, void **apc, void **arg )
-{
- struct async_ioctl *async = user;
-
- if (status == STATUS_ALERTED)
- {
- SERVER_START_REQ( get_irp_result )
- {
- req->handle = wine_server_obj_handle( async->io.handle );
- req->user_arg = wine_server_client_ptr( async );
- wine_server_set_reply( req, async->buffer, async->size );
- status = wine_server_call( req );
- if (status != STATUS_PENDING) io->Information = wine_server_reply_size( reply );
- }
- SERVER_END_REQ;
- }
- if (status != STATUS_PENDING)
- {
- io->u.Status = status;
- *apc = async->io.apc;
- *arg = async->io.apc_arg;
- release_fileio( &async->io );
- }
- return status;
-}
-
/* do an ioctl call through the server */
static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
PIO_APC_ROUTINE apc, PVOID apc_context,
@@ -1395,13 +1496,13 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
const void *in_buffer, ULONG in_size,
PVOID out_buffer, ULONG out_size )
{
- struct async_ioctl *async;
+ struct async_irp *async;
NTSTATUS status;
HANDLE wait_handle;
ULONG options;
ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context;
- if (!(async = (struct async_ioctl *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
+ if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), handle, apc, apc_context )))
return STATUS_NO_MEMORY;
async->event = event;
async->buffer = out_buffer;
@@ -1412,7 +1513,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
req->code = code;
req->blocking = !apc && !event && !cvalue;
req->async.handle = wine_server_obj_handle( handle );
- req->async.callback = wine_server_client_ptr( ioctl_completion );
+ req->async.callback = wine_server_client_ptr( irp_completion );
req->async.iosb = wine_server_client_ptr( io );
req->async.arg = wine_server_client_ptr( async );
req->async.event = wine_server_obj_handle( event );
More information about the wine-cvs
mailing list