server: Allow server side NtQueryVolumeInformationFile implementation.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index c12110e..217b678 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -3212,8 +3212,21 @@
     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 71137f8..2bc2779 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1536,6 +1536,19 @@
 };
 
 
+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 @@
     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 @@
     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 @@
     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 @@
     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 4dd7933..c5c88da 100644
--- a/server/change.c
+++ b/server/change.c
@@ -187,6 +187,7 @@
     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 5b69e76..cb6410b 100644
--- a/server/console.c
+++ b/server/console.c
@@ -191,6 +191,7 @@
     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 192395d..90a4b6e 100644
--- a/server/device.c
+++ b/server/device.c
@@ -209,6 +209,7 @@
     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 9322e2c..fa2b18a 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2175,6 +2175,12 @@
     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 @@
     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 39c8150..6c036ac 100644
--- a/server/file.c
+++ b/server/file.c
@@ -107,6 +107,7 @@
     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 15b60b7..403da65 100644
--- a/server/file.h
+++ b/server/file.h
@@ -62,6 +62,8 @@
     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 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 d7affa5..9fafedb 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -104,6 +104,7 @@
     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 @@
     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 @@
     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 b2d334c..57641d1 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -143,6 +143,7 @@
     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 9cd424f..6dd2fd6 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -196,6 +196,7 @@
     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 @@
     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 @@
     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 b0372a2..2e74d60 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1259,6 +1259,13 @@
     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 a6ca556..7747ce3 100644
--- a/server/request.h
+++ b/server/request.h
@@ -160,6 +160,7 @@
 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 @@
     (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( 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 85dd104..f7aaebb 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -114,6 +114,7 @@
     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 cc9bbcc..1e12618 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -167,6 +167,7 @@
     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 @@
     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 2aa934c..6662d9a 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1807,6 +1807,17 @@
     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 @@
     (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 @@
     (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 @@
     "get_handle_fd",
     "get_directory_cache_entry",
     "flush",
+    "get_volume_info",
     "lock_file",
     "unlock_file",
     "create_socket",