From f62f6e8fe14517c7e2abc5e182bb6baa006dec8b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 24 Aug 2005 18:33:50 +0000 Subject: [PATCH] Don't cache file descriptors open on removable devices. --- dlls/ntdll/server.c | 81 +++++++++++++++++----------------- include/wine/server_protocol.h | 37 ++++++++-------- server/fd.c | 22 +++++++++ server/handle.c | 12 +---- server/handle.h | 1 + server/protocol.def | 19 ++++---- server/request.h | 4 +- server/trace.c | 30 +++++++------ 8 files changed, 112 insertions(+), 94 deletions(-) diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index f10bf2c6c56..f2514bdbafa 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -403,8 +403,7 @@ static int receive_fd( obj_handle_t *handle ) #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS fd = cmsg.fd; #endif - if (fd == -1) server_protocol_error( "no fd received for handle %d\n", *handle ); - fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ + if (fd != -1) fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ return fd; } if (!ret) break; @@ -417,41 +416,6 @@ static int receive_fd( obj_handle_t *handle ) } -/*********************************************************************** - * store_cached_fd - * - * Store the cached fd value for a given handle back into the server. - * Returns the new fd, which can be different if there was already an - * fd in the cache for that handle. - */ -inline static int store_cached_fd( int *fd, obj_handle_t handle ) -{ - int ret; - - SERVER_START_REQ( set_handle_cached_fd ) - { - req->handle = handle; - req->fd = *fd; - if (!(ret = wine_server_call( req ))) - { - if (reply->cur_fd != *fd) - { - /* someone was here before us */ - close( *fd ); - *fd = reply->cur_fd; - } - } - else - { - close( *fd ); - *fd = -1; - } - } - SERVER_END_REQ; - return ret; -} - - /*********************************************************************** * wine_server_fd_to_handle (NTDLL.@) * @@ -502,7 +466,7 @@ int wine_server_fd_to_handle( int fd, unsigned int access, int inherit, obj_hand int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd, int *flags ) { obj_handle_t fd_handle; - int ret, fd = -1; + int ret, removable = -1, fd = -1; *unix_fd = -1; for (;;) @@ -511,8 +475,12 @@ int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *uni { req->handle = handle; req->access = access; - if (!(ret = wine_server_call( req ))) fd = reply->fd; - if (flags) *flags = reply->flags; + if (!(ret = wine_server_call( req ))) + { + fd = reply->fd; + removable = reply->removable; + if (flags) *flags = reply->flags; + } } SERVER_END_REQ; if (ret) return ret; @@ -521,8 +489,39 @@ int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *uni /* it wasn't in the cache, get it from the server */ fd = receive_fd( &fd_handle ); + if (fd == -1) return STATUS_TOO_MANY_OPENED_FILES; + if (fd_handle != handle) removable = -1; + + if (removable == -1) + { + FILE_FS_DEVICE_INFORMATION info; + if (FILE_GetDeviceInfo( fd, &info ) == STATUS_SUCCESS) + removable = (info.Characteristics & FILE_REMOVABLE_MEDIA) != 0; + } + else if (removable) break; /* don't cache it */ + /* and store it back into the cache */ - ret = store_cached_fd( &fd, fd_handle ); + SERVER_START_REQ( set_handle_fd ) + { + req->handle = handle; + req->fd = fd; + req->removable = removable; + if (!(ret = wine_server_call( req ))) + { + if (reply->cur_fd != fd && reply->cur_fd != -1) + { + /* someone was here before us */ + close( fd ); + fd = reply->cur_fd; + } + } + else + { + close( fd ); + fd = -1; + } + } + SERVER_END_REQ; if (ret) return ret; if (fd_handle == handle) break; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 444e6fd663f..e18d682a025 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -538,20 +538,6 @@ struct set_handle_info_reply -struct set_handle_cached_fd_request -{ - struct request_header __header; - obj_handle_t handle; - int fd; -}; -struct set_handle_cached_fd_reply -{ - struct reply_header __header; - int cur_fd; -}; - - - struct dup_handle_request { struct request_header __header; @@ -803,6 +789,7 @@ struct get_handle_fd_reply { struct reply_header __header; int fd; + int removable; int flags; }; #define FD_FLAG_OVERLAPPED 0x01 @@ -813,6 +800,20 @@ struct get_handle_fd_reply * only handle available data (don't wait) */ +struct set_handle_fd_request +{ + struct request_header __header; + obj_handle_t handle; + int fd; + int removable; +}; +struct set_handle_fd_reply +{ + struct reply_header __header; + int cur_fd; +}; + + struct flush_file_request { @@ -3597,7 +3598,6 @@ enum request REQ_get_apc, REQ_close_handle, REQ_set_handle_info, - REQ_set_handle_cached_fd, REQ_dup_handle, REQ_open_process, REQ_open_thread, @@ -3614,6 +3614,7 @@ enum request REQ_create_file, REQ_alloc_file_handle, REQ_get_handle_fd, + REQ_set_handle_fd, REQ_flush_file, REQ_lock_file, REQ_unlock_file, @@ -3809,7 +3810,6 @@ union generic_request struct get_apc_request get_apc_request; struct close_handle_request close_handle_request; struct set_handle_info_request set_handle_info_request; - struct set_handle_cached_fd_request set_handle_cached_fd_request; struct dup_handle_request dup_handle_request; struct open_process_request open_process_request; struct open_thread_request open_thread_request; @@ -3826,6 +3826,7 @@ union generic_request struct create_file_request create_file_request; struct alloc_file_handle_request alloc_file_handle_request; struct get_handle_fd_request get_handle_fd_request; + struct set_handle_fd_request set_handle_fd_request; struct flush_file_request flush_file_request; struct lock_file_request lock_file_request; struct unlock_file_request unlock_file_request; @@ -4019,7 +4020,6 @@ union generic_reply struct get_apc_reply get_apc_reply; struct close_handle_reply close_handle_reply; struct set_handle_info_reply set_handle_info_reply; - struct set_handle_cached_fd_reply set_handle_cached_fd_reply; struct dup_handle_reply dup_handle_reply; struct open_process_reply open_process_reply; struct open_thread_reply open_thread_reply; @@ -4036,6 +4036,7 @@ union generic_reply struct create_file_reply create_file_reply; struct alloc_file_handle_reply alloc_file_handle_reply; struct get_handle_fd_reply get_handle_fd_reply; + struct set_handle_fd_reply set_handle_fd_reply; struct flush_file_reply flush_file_reply; struct lock_file_reply lock_file_reply; struct unlock_file_reply unlock_file_reply; @@ -4205,6 +4206,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 190 +#define SERVER_PROTOCOL_VERSION 191 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/fd.c b/server/fd.c index 79148867cbf..8de82162684 100644 --- a/server/fd.c +++ b/server/fd.c @@ -176,6 +176,7 @@ struct device struct object obj; /* object header */ struct list entry; /* entry in device hash list */ dev_t dev; /* device number */ + int removable; /* removable device? (or -1 if unknown) */ struct list inode_hash[INODE_HASH_SIZE]; /* inodes hash table */ }; @@ -595,6 +596,7 @@ static struct device *get_device( dev_t dev ) if ((device = alloc_object( &device_ops ))) { device->dev = dev; + device->removable = -1; for (i = 0; i < INODE_HASH_SIZE; i++) list_init( &device->inode_hash[i] ); list_add_head( &device_hash[hash], &device->entry ); } @@ -1648,11 +1650,31 @@ DECL_HANDLER(get_handle_fd) if (cached_fd != -1) reply->fd = cached_fd; else if (!get_error()) send_client_fd( current->process, unix_fd, req->handle ); } + if (fd->inode) reply->removable = fd->inode->device->removable; reply->flags = fd->fd_ops->get_file_info( fd ); release_object( fd ); } } +/* set the cached file descriptor of a handle */ +DECL_HANDLER(set_handle_fd) +{ + struct fd *fd; + + reply->cur_fd = -1; + if ((fd = get_handle_fd_obj( current->process, req->handle, 0 ))) + { + struct device *device = fd->inode ? fd->inode->device : NULL; + + if (device && device->removable == -1) device->removable = req->removable; + + /* only cache the fd on non-removable devices */ + if (!device || !device->removable) + reply->cur_fd = set_handle_unix_fd( current->process, req->handle, req->fd ); + release_object( fd ); + } +} + /* get ready to unmount a Unix device */ DECL_HANDLER(unmount_device) { diff --git a/server/handle.c b/server/handle.c index e54678370a7..bf688855e19 100644 --- a/server/handle.c +++ b/server/handle.c @@ -426,10 +426,11 @@ int get_handle_unix_fd( struct process *process, obj_handle_t handle, unsigned i } /* set the cached fd for a handle if not set already, and return the current value */ -static int set_handle_unix_fd( struct process *process, obj_handle_t handle, int fd ) +int set_handle_unix_fd( struct process *process, obj_handle_t handle, int fd ) { struct handle_entry *entry; + if (handle_is_global( handle )) return -1; /* no fd cache for global handles */ if (!(entry = get_handle( process, handle ))) return -1; /* if no current fd set it, otherwise return current fd */ if (entry->fd == -1) entry->fd = fd; @@ -556,15 +557,6 @@ DECL_HANDLER(set_handle_info) reply->old_flags = set_handle_flags( current->process, req->handle, req->mask, req->flags ); } -/* set the cached file descriptor of a handle */ -DECL_HANDLER(set_handle_cached_fd) -{ - int fd = req->fd; - - if (handle_is_global(req->handle)) fd = -1; /* no fd cache for global handles */ - reply->cur_fd = set_handle_unix_fd( current->process, req->handle, fd ); -} - /* duplicate a handle */ DECL_HANDLER(dup_handle) { diff --git a/server/handle.h b/server/handle.h index d90a47eaeb4..626064f512a 100644 --- a/server/handle.h +++ b/server/handle.h @@ -40,6 +40,7 @@ extern struct object *get_handle_obj( struct process *process, obj_handle_t hand unsigned int access, const struct object_ops *ops ); extern unsigned int get_handle_access( struct process *process, obj_handle_t handle ); extern int get_handle_unix_fd( struct process *process, obj_handle_t handle, unsigned int access ); +extern int set_handle_unix_fd( struct process *process, obj_handle_t handle, int fd ); extern obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst, unsigned int access, int inherit, int options ); extern obj_handle_t open_object( const struct namespace *namespace, const WCHAR *name, size_t len, diff --git a/server/protocol.def b/server/protocol.def index 06747cc2968..422aa001e43 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -442,15 +442,6 @@ enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO }; @END -/* Set the cached file descriptor of a handle */ -@REQ(set_handle_cached_fd) - obj_handle_t handle; /* handle we are interested in */ - int fd; /* file descriptor */ -@REPLY - int cur_fd; /* current file descriptor */ -@END - - /* Duplicate a handle */ @REQ(dup_handle) obj_handle_t src_process; /* src process handle */ @@ -621,6 +612,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; unsigned int access; /* wanted access rights */ @REPLY int fd; /* file descriptor */ + int removable; /* is device removable? (-1 if unknown) */ int flags; /* file read/write flags (see below) */ @END #define FD_FLAG_OVERLAPPED 0x01 /* fd opened in overlapped mode */ @@ -630,6 +622,15 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; #define FD_FLAG_AVAILABLE 0x10 /* in overlap read/write operation, * only handle available data (don't wait) */ +/* Set the cached file descriptor of a handle */ +@REQ(set_handle_fd) + obj_handle_t handle; /* handle we are interested in */ + int fd; /* file descriptor */ + int removable; /* is device removable? (-1 if unknown) */ +@REPLY + int cur_fd; /* current file descriptor */ +@END + /* Flush a file buffers */ @REQ(flush_file) diff --git a/server/request.h b/server/request.h index 01dc7f0051c..f6e384a7c20 100644 --- a/server/request.h +++ b/server/request.h @@ -124,7 +124,6 @@ DECL_HANDLER(queue_apc); DECL_HANDLER(get_apc); DECL_HANDLER(close_handle); DECL_HANDLER(set_handle_info); -DECL_HANDLER(set_handle_cached_fd); DECL_HANDLER(dup_handle); DECL_HANDLER(open_process); DECL_HANDLER(open_thread); @@ -141,6 +140,7 @@ DECL_HANDLER(open_semaphore); DECL_HANDLER(create_file); DECL_HANDLER(alloc_file_handle); DECL_HANDLER(get_handle_fd); +DECL_HANDLER(set_handle_fd); DECL_HANDLER(flush_file); DECL_HANDLER(lock_file); DECL_HANDLER(unlock_file); @@ -335,7 +335,6 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_apc, (req_handler)req_close_handle, (req_handler)req_set_handle_info, - (req_handler)req_set_handle_cached_fd, (req_handler)req_dup_handle, (req_handler)req_open_process, (req_handler)req_open_thread, @@ -352,6 +351,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_create_file, (req_handler)req_alloc_file_handle, (req_handler)req_get_handle_fd, + (req_handler)req_set_handle_fd, (req_handler)req_flush_file, (req_handler)req_lock_file, (req_handler)req_unlock_file, diff --git a/server/trace.c b/server/trace.c index d648cfa20ec..538732fe747 100644 --- a/server/trace.c +++ b/server/trace.c @@ -836,17 +836,6 @@ static void dump_set_handle_info_reply( const struct set_handle_info_reply *req fprintf( stderr, " old_flags=%d", req->old_flags ); } -static void dump_set_handle_cached_fd_request( const struct set_handle_cached_fd_request *req ) -{ - fprintf( stderr, " handle=%p,", req->handle ); - fprintf( stderr, " fd=%d", req->fd ); -} - -static void dump_set_handle_cached_fd_reply( const struct set_handle_cached_fd_reply *req ) -{ - fprintf( stderr, " cur_fd=%d", req->cur_fd ); -} - static void dump_dup_handle_request( const struct dup_handle_request *req ) { fprintf( stderr, " src_process=%p,", req->src_process ); @@ -1047,9 +1036,22 @@ static void dump_get_handle_fd_request( const struct get_handle_fd_request *req static void dump_get_handle_fd_reply( const struct get_handle_fd_reply *req ) { fprintf( stderr, " fd=%d,", req->fd ); + fprintf( stderr, " removable=%d,", req->removable ); fprintf( stderr, " flags=%d", req->flags ); } +static void dump_set_handle_fd_request( const struct set_handle_fd_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " fd=%d,", req->fd ); + fprintf( stderr, " removable=%d", req->removable ); +} + +static void dump_set_handle_fd_reply( const struct set_handle_fd_reply *req ) +{ + fprintf( stderr, " cur_fd=%d", req->cur_fd ); +} + static void dump_flush_file_request( const struct flush_file_request *req ) { fprintf( stderr, " handle=%p", req->handle ); @@ -3109,7 +3111,6 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_apc_request, (dump_func)dump_close_handle_request, (dump_func)dump_set_handle_info_request, - (dump_func)dump_set_handle_cached_fd_request, (dump_func)dump_dup_handle_request, (dump_func)dump_open_process_request, (dump_func)dump_open_thread_request, @@ -3126,6 +3127,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_file_request, (dump_func)dump_alloc_file_handle_request, (dump_func)dump_get_handle_fd_request, + (dump_func)dump_set_handle_fd_request, (dump_func)dump_flush_file_request, (dump_func)dump_lock_file_request, (dump_func)dump_unlock_file_request, @@ -3317,7 +3319,6 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_apc_reply, (dump_func)dump_close_handle_reply, (dump_func)dump_set_handle_info_reply, - (dump_func)dump_set_handle_cached_fd_reply, (dump_func)dump_dup_handle_reply, (dump_func)dump_open_process_reply, (dump_func)dump_open_thread_reply, @@ -3334,6 +3335,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_file_reply, (dump_func)dump_alloc_file_handle_reply, (dump_func)dump_get_handle_fd_reply, + (dump_func)dump_set_handle_fd_reply, (dump_func)dump_flush_file_reply, (dump_func)dump_lock_file_reply, (dump_func)0, @@ -3525,7 +3527,6 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_apc", "close_handle", "set_handle_info", - "set_handle_cached_fd", "dup_handle", "open_process", "open_thread", @@ -3542,6 +3543,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "create_file", "alloc_file_handle", "get_handle_fd", + "set_handle_fd", "flush_file", "lock_file", "unlock_file",