From 13499a3d115998ced8aaacb62900766174e99af2 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 8 Jul 2015 18:56:01 +0900 Subject: [PATCH] ntoskrnl: Implement creation and destruction of file objects. --- dlls/ntoskrnl.exe/ntoskrnl.c | 100 +++++++++++++++++++++++++++++++-- include/wine/server_protocol.h | 7 ++- server/device.c | 26 ++++++++- server/protocol.def | 3 +- server/request.h | 5 +- server/trace.c | 3 +- 6 files changed, 130 insertions(+), 14 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 53739c62c72..ccd2d3ad0e6 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -151,6 +151,94 @@ static NTSTATUS dispatch_irp( DEVICE_OBJECT *device, IRP *irp ) return STATUS_SUCCESS; } +/* process a create request for a given file */ +static NTSTATUS dispatch_create( const irp_params_t *params, void *in_buff, ULONG in_size, + ULONG out_size, HANDLE irp_handle ) +{ + IRP *irp; + IO_STACK_LOCATION *irpsp; + FILE_OBJECT *file; + DEVICE_OBJECT *device = wine_server_get_ptr( params->create.device ); + + if (!(file = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*file) ))) return STATUS_NO_MEMORY; + + TRACE( "device %p -> file %p\n", device, file ); + + file->Type = 5; /* MSDN */ + file->Size = sizeof(*file); + file->DeviceObject = device; + + if (!(irp = IoAllocateIrp( device->StackSize, FALSE ))) + { + HeapFree( GetProcessHeap(), 0, file ); + return STATUS_NO_MEMORY; + } + + irpsp = IoGetNextIrpStackLocation( irp ); + irpsp->MajorFunction = IRP_MJ_CREATE; + irpsp->DeviceObject = device; + irpsp->CompletionRoutine = NULL; + irpsp->Parameters.Create.SecurityContext = NULL; /* FIXME */ + irpsp->Parameters.Create.Options = params->create.options; + irpsp->Parameters.Create.ShareAccess = params->create.sharing; + irpsp->Parameters.Create.FileAttributes = 0; + irpsp->Parameters.Create.EaLength = 0; + + irp->Tail.Overlay.OriginalFileObject = file; + irp->AssociatedIrp.SystemBuffer = NULL; + irp->UserBuffer = NULL; + irp->UserIosb = irp_handle; /* note: we abuse UserIosb to store the server irp handle */ + irp->UserEvent = NULL; + + irp->IoStatus.u.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +/* process a close request for a given file */ +static NTSTATUS dispatch_close( const irp_params_t *params, void *in_buff, ULONG in_size, + ULONG out_size, HANDLE irp_handle ) +{ + IRP *irp; + IO_STACK_LOCATION *irpsp; + DEVICE_OBJECT *device; + FILE_OBJECT *file = wine_server_get_ptr( params->close.file ); + + if (!file) return STATUS_INVALID_HANDLE; + + device = file->DeviceObject; + + TRACE( "device %p file %p\n", device, file ); + + if (!(irp = IoAllocateIrp( device->StackSize, FALSE ))) + { + HeapFree( GetProcessHeap(), 0, file ); + return STATUS_NO_MEMORY; + } + + irpsp = IoGetNextIrpStackLocation( irp ); + irpsp->MajorFunction = IRP_MJ_CLOSE; + irpsp->DeviceObject = device; + irpsp->CompletionRoutine = NULL; + irpsp->Parameters.Create.SecurityContext = NULL; /* FIXME */ + irpsp->Parameters.Create.Options = params->create.options; + irpsp->Parameters.Create.ShareAccess = params->create.sharing; + irpsp->Parameters.Create.FileAttributes = 0; + irpsp->Parameters.Create.EaLength = 0; + + irp->Tail.Overlay.OriginalFileObject = file; + irp->AssociatedIrp.SystemBuffer = NULL; + irp->UserBuffer = NULL; + irp->UserIosb = irp_handle; /* note: we abuse UserIosb to store the server irp handle */ + irp->UserEvent = NULL; + + irp->IoStatus.u.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + + HeapFree( GetProcessHeap(), 0, file ); /* FIXME: async close processing not supported */ + return STATUS_SUCCESS; +} + /* process a read request for a given device */ static NTSTATUS dispatch_read( const irp_params_t *params, void *in_buff, ULONG in_size, ULONG out_size, HANDLE irp_handle ) @@ -268,9 +356,9 @@ typedef NTSTATUS (*dispatch_func)( const irp_params_t *params, void *in_buff, UL static const dispatch_func dispatch_funcs[IRP_MJ_MAXIMUM_FUNCTION + 1] = { - NULL, /* IRP_MJ_CREATE */ + dispatch_create, /* IRP_MJ_CREATE */ NULL, /* IRP_MJ_CREATE_NAMED_PIPE */ - NULL, /* IRP_MJ_CLOSE */ + dispatch_close, /* IRP_MJ_CLOSE */ dispatch_read, /* IRP_MJ_READ */ dispatch_write, /* IRP_MJ_WRITE */ NULL, /* IRP_MJ_QUERY_INFORMATION */ @@ -1149,12 +1237,14 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost ) { HANDLE manager = get_device_manager(); void *out_buff = irp->UserBuffer; + FILE_OBJECT *file = irp->Tail.Overlay.OriginalFileObject; SERVER_START_REQ( set_irp_result ) { - req->manager = wine_server_obj_handle( manager ); - req->handle = wine_server_obj_handle( handle ); - req->status = irp->IoStatus.u.Status; + req->manager = wine_server_obj_handle( manager ); + req->handle = wine_server_obj_handle( handle ); + req->status = irp->IoStatus.u.Status; + req->file_ptr = wine_server_client_ptr( file ); if (irp->IoStatus.u.Status >= 0) { req->size = irp->IoStatus.Information; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 9807dcc9960..eefeea56c0d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -646,7 +646,7 @@ typedef union { unsigned int major; int __pad; - client_ptr_t device; + client_ptr_t file; } close; struct { @@ -3216,9 +3216,10 @@ struct set_irp_result_request obj_handle_t manager; obj_handle_t handle; unsigned int status; + client_ptr_t file_ptr; data_size_t size; /* VARARG(data,bytes); */ - char __pad_28[4]; + char __pad_36[4]; }; struct set_irp_result_reply { @@ -6095,6 +6096,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 479 +#define SERVER_PROTOCOL_VERSION 480 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/device.c b/server/device.c index 2bdf82a0a61..50c6d3b64bc 100644 --- a/server/device.c +++ b/server/device.c @@ -164,6 +164,7 @@ struct device_file struct object obj; /* object header */ struct device *device; /* device for this file */ struct fd *fd; /* file descriptor for irp */ + client_ptr_t user_ptr; /* opaque ptr for client side */ struct list entry; /* entry in device list */ struct list requests; /* list of pending irp requests */ }; @@ -358,6 +359,7 @@ static struct object *device_open_file( struct object *obj, unsigned int access, if (!(file = alloc_object( &device_file_ops ))) return NULL; file->device = (struct device *)grab_object( device ); + file->user_ptr = 0; list_init( &file->requests ); list_add_tail( &device->files, &file->entry ); if (device->unix_path) @@ -419,8 +421,8 @@ static int device_file_close_handle( struct object *obj, struct process *process struct irp_call *irp; irp_params_t params; - params.close.major = IRP_MJ_CLOSE; - params.close.device = file->device->user_ptr; + params.close.major = IRP_MJ_CLOSE; + params.close.file = file->user_ptr; if ((irp = create_irp( file, ¶ms, NULL, 0, 0 ))) { @@ -458,6 +460,25 @@ static struct irp_call *find_irp_call( struct device_file *file, struct thread * return NULL; } +static void set_file_user_ptr( struct device_file *file, client_ptr_t ptr ) +{ + struct irp_call *irp; + + if (file->user_ptr == ptr) return; /* nothing to do */ + + file->user_ptr = ptr; + + /* update already queued irps */ + + LIST_FOR_EACH_ENTRY( irp, &file->requests, struct irp_call, dev_entry ) + { + switch (irp->params.major) + { + case IRP_MJ_CLOSE: irp->params.close.file = ptr; break; + } + } +} + /* queue an irp to the device */ static obj_handle_t queue_irp( struct device_file *file, struct irp_call *irp, const async_data_t *async_data, int blocking ) @@ -780,6 +801,7 @@ DECL_HANDLER(set_irp_result) if ((irp = (struct irp_call *)get_handle_obj( current->process, req->handle, 0, &irp_call_ops ))) { + if (irp->file) set_file_user_ptr( irp->file, req->file_ptr ); set_irp_result( irp, req->status, get_req_data(), get_req_data_size(), req->size ); close_handle( current->process, req->handle ); /* avoid an extra round-trip for close */ release_object( irp ); diff --git a/server/protocol.def b/server/protocol.def index 1578345cd79..2d06344245a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -662,7 +662,7 @@ typedef union { unsigned int major; /* IRP_MJ_CLOSE */ int __pad; - client_ptr_t device; /* opaque ptr for the device */ + client_ptr_t file; /* opaque ptr for the file object */ } close; struct { @@ -2338,6 +2338,7 @@ enum message_type obj_handle_t manager; /* handle to the device manager */ obj_handle_t handle; /* handle to the irp */ unsigned int status; /* status of the irp */ + client_ptr_t file_ptr; /* opaque pointer to the file object */ data_size_t size; /* result size (input or output depending on the operation) */ VARARG(data,bytes); /* output data of the irp */ @END diff --git a/server/request.h b/server/request.h index 845547fa2b7..760466ce44b 100644 --- a/server/request.h +++ b/server/request.h @@ -1555,8 +1555,9 @@ C_ASSERT( sizeof(struct ioctl_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_irp_result_request, manager) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_irp_result_request, handle) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_irp_result_request, status) == 20 ); -C_ASSERT( FIELD_OFFSET(struct set_irp_result_request, size) == 24 ); -C_ASSERT( sizeof(struct set_irp_result_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct set_irp_result_request, file_ptr) == 24 ); +C_ASSERT( FIELD_OFFSET(struct set_irp_result_request, size) == 32 ); +C_ASSERT( sizeof(struct set_irp_result_request) == 40 ); C_ASSERT( FIELD_OFFSET(struct get_irp_result_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_irp_result_request, user_arg) == 16 ); C_ASSERT( sizeof(struct get_irp_result_request) == 24 ); diff --git a/server/trace.c b/server/trace.c index f24c3689bc7..e43c0c7d8de 100644 --- a/server/trace.c +++ b/server/trace.c @@ -324,7 +324,7 @@ static void dump_irp_params( const char *prefix, const irp_params_t *data ) break; case IRP_MJ_CLOSE: fprintf( stderr, "%s{major=CLOSE", prefix ); - dump_uint64( ",device=", &data->close.device ); + dump_uint64( ",file=", &data->close.file ); fputc( '}', stderr ); break; case IRP_MJ_READ: @@ -2826,6 +2826,7 @@ static void dump_set_irp_result_request( const struct set_irp_result_request *re fprintf( stderr, " manager=%04x", req->manager ); fprintf( stderr, ", handle=%04x", req->handle ); fprintf( stderr, ", status=%08x", req->status ); + dump_uint64( ", file_ptr=", &req->file_ptr ); fprintf( stderr, ", size=%u", req->size ); dump_varargs_bytes( ", data=", cur_size ); }