diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index c12110ea93eaf95403fcecfcfc80e89cb28b538a..217b67845ec4384a7c10ad40668428056ee403fc 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 71137f84f4381bd41aad65ea7a948dba680687dd..2bc277901ef95b94b39e38576e3132025f8631e7 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 4dd7933f3ee8b2bd1462644780edc29308215cae..c5c88da58dd9d7f88bc36ebe183b7174d4d6d1f8 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 5b69e769a61b268e1906b5a14a7c7eefa985c37c..cb6410b774105b338f083e3a35bb44242f9c938a 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 192395dcc7fba03d15a5a8f46dcad8451093e34d..90a4b6e8eec795aa57207e05d1891e80a9971352 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 9322e2c1c1590e3d2cf4c5404b888f14c6b439de..fa2b18a46b1a26ce541083695ff7cc398217b603 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 39c8150cb28f49778d226465af495b0ce584a98e..6c036acb641d60faa18a838dd863528f32aac052 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 15b60b78767fd305152886834c32f79937cb89fa..403da6526fb017377121985daf73a046f2f81546 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 d7affa514bf30be8112a61a6252809a50f7cd028..9fafedbd2046e8ed5c13c9938f61226d184cd324 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 b2d334c788940822fc22ab7fcb69efb141ea1764..57641d13787b96f149f425a40b4ce45c92701aee 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 9cd424fe368c6df2ed6ca13dc365f695308a96bf..6dd2fd628a2f6d237c783a1418e9d9f5e89f4427 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 b0372a25fce3ab94f8d8873ac553277028f41a67..2e74d60b7c49ebabc56e8703d956ab0c35c75412 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 a6ca5560f4620795448afed4b5b677c0743a4e74..7747ce30f5880d0ebcc8a28fc2364dd1a5f61011 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 85dd104bc68dd1c8fbbeb2c6edb6fc5127b2ae91..f7aaebbaf69519093a8e0df66db13af3f9827df1 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 cc9bbccad7e4756ad303bec65a90bfcd78174204..1e12618219070eadf412468b8afff351564d1544 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 2aa934c11f045d2d8d62b44859db609a69d7e0a3..6662d9af20749b79c4a544ae5ee4b062a3f5868e 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",