From 2ab2f31f18fd2089c311a529f80a9d5ff6a52beb Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek@codeweavers.com>
Date: Mon, 2 Oct 2017 16:42:16 +0200
Subject: [PATCH] server: Allow server side NtQueryVolumeInformationFile
 implementation.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---
 dlls/ntdll/file.c              | 15 ++++++++++++++-
 include/wine/server_protocol.h | 18 +++++++++++++++++-
 server/change.c                |  1 +
 server/console.c               |  1 +
 server/device.c                |  1 +
 server/fd.c                    | 18 ++++++++++++++++++
 server/file.c                  |  1 +
 server/file.h                  |  3 +++
 server/mailslot.c              |  3 +++
 server/mapping.c               |  1 +
 server/named_pipe.c            |  3 +++
 server/protocol.def            |  7 +++++++
 server/request.h               |  6 ++++++
 server/serial.c                |  1 +
 server/sock.c                  |  2 ++
 server/trace.c                 | 14 ++++++++++++++
 16 files changed, 93 insertions(+), 2 deletions(-)

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",
-- 
GitLab