diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index c12110ea93e..217b67845ec 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -3212,8 +3212,21 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io struct stat st; static int once; - if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS) + io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ); + if (io->u.Status == STATUS_BAD_DEVICE_TYPE) + { + SERVER_START_REQ( get_volume_info ) + { + req->handle = wine_server_obj_handle( handle ); + req->info_class = info_class; + wine_server_set_reply( req, buffer, length ); + io->u.Status = wine_server_call( req ); + if (!io->u.Status) io->Information = wine_server_reply_size( reply ); + } + SERVER_END_REQ; return io->u.Status; + } + else if (io->u.Status) return io->u.Status; io->u.Status = STATUS_NOT_IMPLEMENTED; io->Information = 0; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 71137f84f43..2bc277901ef 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1536,6 +1536,19 @@ struct flush_reply }; +struct get_volume_info_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int info_class; + char __pad_20[4]; +}; +struct get_volume_info_reply +{ + struct reply_header __header; + /* VARARG(data,bytes); */ +}; + struct lock_file_request { @@ -5632,6 +5645,7 @@ enum request REQ_get_handle_fd, REQ_get_directory_cache_entry, REQ_flush, + REQ_get_volume_info, REQ_lock_file, REQ_unlock_file, REQ_create_socket, @@ -5926,6 +5940,7 @@ union generic_request struct get_handle_fd_request get_handle_fd_request; struct get_directory_cache_entry_request get_directory_cache_entry_request; struct flush_request flush_request; + struct get_volume_info_request get_volume_info_request; struct lock_file_request lock_file_request; struct unlock_file_request unlock_file_request; struct create_socket_request create_socket_request; @@ -6218,6 +6233,7 @@ union generic_reply struct get_handle_fd_reply get_handle_fd_reply; struct get_directory_cache_entry_reply get_directory_cache_entry_reply; struct flush_reply flush_reply; + struct get_volume_info_reply get_volume_info_reply; struct lock_file_reply lock_file_reply; struct unlock_file_reply unlock_file_reply; struct create_socket_reply create_socket_reply; @@ -6459,6 +6475,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 542 +#define SERVER_PROTOCOL_VERSION 543 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/change.c b/server/change.c index 4dd7933f3ee..c5c88da58dd 100644 --- a/server/change.c +++ b/server/change.c @@ -187,6 +187,7 @@ static const struct fd_ops dir_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/console.c b/server/console.c index 5b69e769a61..cb6410b7741 100644 --- a/server/console.c +++ b/server/console.c @@ -191,6 +191,7 @@ static const struct fd_ops console_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/device.c b/server/device.c index 192395dcc7f..90a4b6e8eec 100644 --- a/server/device.c +++ b/server/device.c @@ -209,6 +209,7 @@ static const struct fd_ops device_file_fd_ops = device_file_read, /* read */ device_file_write, /* write */ device_file_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ device_file_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/fd.c b/server/fd.c index 9322e2c1c15..fa2b18a46b1 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2175,6 +2175,12 @@ int no_fd_flush( struct fd *fd, struct async *async ) return 0; } +/* default get_volume_info() routine */ +void no_fd_get_volume_info( struct fd *fd, unsigned int info_class ) +{ + set_error( STATUS_OBJECT_TYPE_MISMATCH ); +} + /* default ioctl() routine */ int no_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) { @@ -2378,6 +2384,18 @@ DECL_HANDLER(flush) release_object( fd ); } +/* query volume info */ +DECL_HANDLER(get_volume_info) +{ + struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); + + if (fd) + { + fd->fd_ops->get_volume_info( fd, req->info_class ); + release_object( fd ); + } +} + /* open a file object */ DECL_HANDLER(open_file_object) { diff --git a/server/file.c b/server/file.c index 39c8150cb28..6c036acb641 100644 --- a/server/file.c +++ b/server/file.c @@ -107,6 +107,7 @@ static const struct fd_ops file_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ file_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/file.h b/server/file.h index 15b60b78767..403da6526fb 100644 --- a/server/file.h +++ b/server/file.h @@ -62,6 +62,8 @@ struct fd_ops int (*write)(struct fd *, struct async *, file_pos_t ); /* flush the object buffers */ int (*flush)(struct fd *, struct async *); + /* query volume info */ + void (*get_volume_info)( struct fd *, unsigned int ); /* perform an ioctl on the file */ int (*ioctl)(struct fd *fd, ioctl_code_t code, struct async *async ); /* queue an async operation */ @@ -108,6 +110,7 @@ extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); extern int no_fd_read( struct fd *fd, struct async *async, file_pos_t pos ); extern int no_fd_write( struct fd *fd, struct async *async, file_pos_t pos ); extern int no_fd_flush( struct fd *fd, struct async *async ); +extern void no_fd_get_volume_info( struct fd *fd, unsigned int info_class ); extern int no_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); extern int default_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); extern void no_fd_queue_async( struct fd *fd, struct async *async, int type, int count ); diff --git a/server/mailslot.c b/server/mailslot.c index d7affa514bf..9fafedbd204 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -104,6 +104,7 @@ static const struct fd_ops mailslot_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ mailslot_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ @@ -157,6 +158,7 @@ static const struct fd_ops mail_writer_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ @@ -210,6 +212,7 @@ static const struct fd_ops mailslot_device_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/mapping.c b/server/mapping.c index b2d334c7889..57641d13787 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -143,6 +143,7 @@ static const struct fd_ops mapping_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ no_fd_ioctl, /* ioctl */ no_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/named_pipe.c b/server/named_pipe.c index 9cd424fe368..6dd2fd628a2 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -196,6 +196,7 @@ static const struct fd_ops pipe_server_fd_ops = pipe_end_read, /* read */ pipe_end_write, /* write */ pipe_server_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ pipe_server_ioctl, /* ioctl */ pipe_end_queue_async, /* queue_async */ pipe_end_reselect_async /* reselect_async */ @@ -239,6 +240,7 @@ static const struct fd_ops pipe_client_fd_ops = pipe_end_read, /* read */ pipe_end_write, /* write */ pipe_client_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ pipe_client_ioctl, /* ioctl */ pipe_end_queue_async, /* queue_async */ pipe_end_reselect_async /* reselect_async */ @@ -285,6 +287,7 @@ static const struct fd_ops named_pipe_device_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ named_pipe_device_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ diff --git a/server/protocol.def b/server/protocol.def index b0372a25fce..2e74d60b7c4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1259,6 +1259,13 @@ enum server_fd_type obj_handle_t event; /* event set when finished */ @END +/* Queries volume information */ +@REQ(get_volume_info) + obj_handle_t handle; /* handle to the file */ + unsigned int info_class; /* queried information class */ +@REPLY + VARARG(data,bytes); /* volume info data */ +@END /* Lock a region of a file */ @REQ(lock_file) diff --git a/server/request.h b/server/request.h index a6ca5560f46..7747ce30f58 100644 --- a/server/request.h +++ b/server/request.h @@ -160,6 +160,7 @@ DECL_HANDLER(get_handle_unix_name); DECL_HANDLER(get_handle_fd); DECL_HANDLER(get_directory_cache_entry); DECL_HANDLER(flush); +DECL_HANDLER(get_volume_info); DECL_HANDLER(lock_file); DECL_HANDLER(unlock_file); DECL_HANDLER(create_socket); @@ -453,6 +454,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_handle_fd, (req_handler)req_get_directory_cache_entry, (req_handler)req_flush, + (req_handler)req_get_volume_info, (req_handler)req_lock_file, (req_handler)req_unlock_file, (req_handler)req_create_socket, @@ -1029,6 +1031,10 @@ C_ASSERT( FIELD_OFFSET(struct flush_request, async) == 16 ); C_ASSERT( sizeof(struct flush_request) == 56 ); C_ASSERT( FIELD_OFFSET(struct flush_reply, event) == 8 ); C_ASSERT( sizeof(struct flush_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_volume_info_request, handle) == 12 ); +C_ASSERT( FIELD_OFFSET(struct get_volume_info_request, info_class) == 16 ); +C_ASSERT( sizeof(struct get_volume_info_request) == 24 ); +C_ASSERT( sizeof(struct get_volume_info_reply) == 8 ); C_ASSERT( FIELD_OFFSET(struct lock_file_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct lock_file_request, offset) == 16 ); C_ASSERT( FIELD_OFFSET(struct lock_file_request, count) == 24 ); diff --git a/server/serial.c b/server/serial.c index 85dd104bc68..f7aaebbaf69 100644 --- a/server/serial.c +++ b/server/serial.c @@ -114,6 +114,7 @@ static const struct fd_ops serial_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ serial_ioctl, /* ioctl */ serial_queue_async, /* queue_async */ serial_reselect_async /* reselect_async */ diff --git a/server/sock.c b/server/sock.c index cc9bbccad7e..1e126182190 100644 --- a/server/sock.c +++ b/server/sock.c @@ -167,6 +167,7 @@ static const struct fd_ops sock_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ sock_ioctl, /* ioctl */ sock_queue_async, /* queue_async */ sock_reselect_async /* reselect_async */ @@ -990,6 +991,7 @@ static const struct fd_ops ifchange_fd_ops = no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ + no_fd_get_volume_info, /* get_volume_info */ no_fd_ioctl, /* ioctl */ NULL, /* queue_async */ NULL /* reselect_async */ diff --git a/server/trace.c b/server/trace.c index 2aa934c11f0..6662d9af207 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1807,6 +1807,17 @@ static void dump_flush_reply( const struct flush_reply *req ) fprintf( stderr, " event=%04x", req->event ); } +static void dump_get_volume_info_request( const struct get_volume_info_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", info_class=%08x", req->info_class ); +} + +static void dump_get_volume_info_reply( const struct get_volume_info_reply *req ) +{ + dump_varargs_bytes( " data=", cur_size ); +} + static void dump_lock_file_request( const struct lock_file_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); @@ -4533,6 +4544,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_handle_fd_request, (dump_func)dump_get_directory_cache_entry_request, (dump_func)dump_flush_request, + (dump_func)dump_get_volume_info_request, (dump_func)dump_lock_file_request, (dump_func)dump_unlock_file_request, (dump_func)dump_create_socket_request, @@ -4823,6 +4835,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_handle_fd_reply, (dump_func)dump_get_directory_cache_entry_reply, (dump_func)dump_flush_reply, + (dump_func)dump_get_volume_info_reply, (dump_func)dump_lock_file_reply, NULL, (dump_func)dump_create_socket_reply, @@ -5113,6 +5126,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_handle_fd", "get_directory_cache_entry", "flush", + "get_volume_info", "lock_file", "unlock_file", "create_socket",