From 8930427b21d5c8615a3dc94c5031bcf1e1e72c45 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Mon, 20 Nov 2006 14:14:04 +0100
Subject: [PATCH] server: Return an fd type in the get_handle_fd request.

---
 include/wine/server_protocol.h | 15 ++++++++++++++-
 server/change.c                | 15 +++++----------
 server/fd.c                    | 25 +++++++++++++++----------
 server/file.c                  |  9 +++++----
 server/file.h                  |  4 ++--
 server/mailslot.c              | 21 ++++++++++++---------
 server/named_pipe.c            | 29 ++++++++++++++---------------
 server/protocol.def            | 13 +++++++++++++
 server/serial.c                | 14 +++++++-------
 server/sock.c                  | 14 +++++++-------
 server/trace.c                 |  1 +
 11 files changed, 95 insertions(+), 65 deletions(-)

diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 09b8906cf65..d068d1f0ab3 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -844,8 +844,21 @@ struct get_handle_fd_request
 struct get_handle_fd_reply
 {
     struct reply_header __header;
+    int          type;
     int          flags;
 };
+enum server_fd_type
+{
+    FD_TYPE_INVALID,
+    FD_TYPE_FILE,
+    FD_TYPE_DIR,
+    FD_TYPE_SOCKET,
+    FD_TYPE_SERIAL,
+    FD_TYPE_PIPE,
+    FD_TYPE_MAILSLOT,
+    FD_TYPE_DEVICE,
+    FD_TYPE_NB_TYPES
+};
 #define FD_FLAG_OVERLAPPED         0x01
 #define FD_FLAG_TIMEOUT            0x02
 #define FD_FLAG_RECV_SHUTDOWN      0x04
@@ -4404,6 +4417,6 @@ union generic_reply
     struct query_symlink_reply query_symlink_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 259
+#define SERVER_PROTOCOL_VERSION 260
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/change.c b/server/change.c
index 5468e85f8b9..c90adbe7da1 100644
--- a/server/change.c
+++ b/server/change.c
@@ -182,7 +182,7 @@ static const struct object_ops dir_ops =
 };
 
 static int dir_get_poll_events( struct fd *fd );
-static int dir_get_info( struct fd *fd );
+static enum server_fd_type dir_get_info( struct fd *fd, int *flags );
 static void dir_cancel_async( struct fd *fd );
 
 static const struct fd_ops dir_fd_ops =
@@ -372,9 +372,10 @@ static int dir_get_poll_events( struct fd *fd )
     return 0;
 }
 
-static int dir_get_info( struct fd *fd )
+static enum server_fd_type dir_get_info( struct fd *fd, int *flags )
 {
-    return 0;
+    *flags = 0;
+    return FD_TYPE_DIR;
 }
 
 static void dir_cancel_async( struct fd *fd )
@@ -550,14 +551,13 @@ static struct inode *inode_from_name( struct inode *inode, const char *name )
 
 static int inotify_get_poll_events( struct fd *fd );
 static void inotify_poll_event( struct fd *fd, int event );
-static int inotify_get_info( struct fd *fd );
 
 static const struct fd_ops inotify_fd_ops =
 {
     inotify_get_poll_events,  /* get_poll_events */
     inotify_poll_event,       /* poll_event */
     no_flush,                 /* flush */
-    inotify_get_info,         /* get_file_info */
+    no_get_file_info,         /* get_file_info */
     default_fd_queue_async,   /* queue_async */
     default_fd_cancel_async,  /* cancel_async */
 };
@@ -823,11 +823,6 @@ static void inotify_poll_event( struct fd *fd, int event )
     }
 }
 
-static int inotify_get_info( struct fd *fd )
-{
-    return 0;
-}
-
 static inline struct fd *create_inotify_fd( void )
 {
     int unix_fd;
diff --git a/server/fd.c b/server/fd.c
index 3848d101a56..157db69f956 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1774,9 +1774,10 @@ void fd_queue_async_timeout( struct fd *fd, void *apc, void *user, void *io_sb,
                              const struct timeval *timeout )
 {
     struct list *queue;
-    int events;
+    int events, flags;
 
-    if (!(fd->fd_ops->get_file_info( fd ) & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT)))
+    fd->fd_ops->get_file_info( fd, &flags );
+    if (!(flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT)))
     {
         set_error( STATUS_INVALID_HANDLE );
         return;
@@ -1824,10 +1825,10 @@ int no_flush( struct fd *fd, struct event **event )
 }
 
 /* default get_file_info() routine */
-int no_get_file_info( struct fd *fd )
+enum server_fd_type no_get_file_info( struct fd *fd, int *flags )
 {
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return 0;
+    *flags = 0;
+    return FD_TYPE_INVALID;
 }
 
 /* default queue_async() routine */
@@ -1955,13 +1956,17 @@ DECL_HANDLER(get_handle_fd)
 
     if ((fd = get_handle_fd_obj( current->process, req->handle, req->access )))
     {
-        if (!req->cached)
+        reply->type = fd->fd_ops->get_file_info( fd, &reply->flags );
+        if (reply->type != FD_TYPE_INVALID)
         {
-            int unix_fd = get_unix_fd( fd );
-            if (unix_fd != -1) send_client_fd( current->process, unix_fd, req->handle );
+            if (fd->inode && fd->inode->device->removable) reply->flags |= FD_FLAG_REMOVABLE;
+            if (!req->cached)
+            {
+                int unix_fd = get_unix_fd( fd );
+                if (unix_fd != -1) send_client_fd( current->process, unix_fd, req->handle );
+            }
         }
-        reply->flags = fd->fd_ops->get_file_info( fd );
-        if (fd->inode && fd->inode->device->removable) reply->flags |= FD_FLAG_REMOVABLE;
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         release_object( fd );
     }
 }
diff --git a/server/file.c b/server/file.c
index ec34295a171..d84e4f31c51 100644
--- a/server/file.c
+++ b/server/file.c
@@ -70,7 +70,7 @@ static void file_destroy( struct object *obj );
 
 static int file_get_poll_events( struct fd *fd );
 static int file_flush( struct fd *fd, struct event **event );
-static int file_get_info( struct fd *fd );
+static enum server_fd_type file_get_info( struct fd *fd, int *flags );
 
 static const struct object_ops file_ops =
 {
@@ -238,12 +238,13 @@ static int file_flush( struct fd *fd, struct event **event )
     return ret;
 }
 
-static int file_get_info( struct fd *fd )
+static enum server_fd_type file_get_info( struct fd *fd, int *flags )
 {
     struct file *file = get_fd_user( fd );
 
-    if (is_overlapped( file )) return FD_FLAG_OVERLAPPED;
-    else return 0;
+    *flags = 0;
+    if (is_overlapped( file )) *flags |= FD_FLAG_OVERLAPPED;
+    return FD_TYPE_FILE;
 }
 
 static struct fd *file_get_fd( struct object *obj )
diff --git a/server/file.h b/server/file.h
index fc8b9041d20..6edb59f1600 100644
--- a/server/file.h
+++ b/server/file.h
@@ -37,7 +37,7 @@ struct fd_ops
     /* flush the object buffers */
     int  (*flush)(struct fd *, struct event **);
     /* get file information */
-    int  (*get_file_info)(struct fd *);
+    enum server_fd_type (*get_file_info)(struct fd *fd, int *flags);
     /* queue an async operation */
     void (*queue_async)(struct fd *, void* apc, void* user, void* io_sb, int type, int count);
     /* cancel an async operation */
@@ -72,7 +72,7 @@ extern void fd_queue_async_timeout( struct fd *fd, void *apc, void *user, void *
 extern void default_fd_queue_async( struct fd *fd, void *apc, void *user, void *io_sb, int type, int count );
 extern void default_fd_cancel_async( struct fd *fd );
 extern int no_flush( struct fd *fd, struct event **event );
-extern int no_get_file_info( struct fd *fd );
+extern enum server_fd_type no_get_file_info( struct fd *fd, int *flags );
 extern void no_queue_async( struct fd *fd, void* apc, void* user, void* io_sb, int type, int count);
 extern void no_cancel_async( struct fd *fd );
 extern void main_loop(void);
diff --git a/server/mailslot.c b/server/mailslot.c
index 578f75131c6..d9537f42814 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -84,7 +84,7 @@ static const struct object_ops mailslot_ops =
     mailslot_destroy           /* destroy */
 };
 
-static int mailslot_get_info( struct fd * );
+static enum server_fd_type mailslot_get_info( struct fd *fd, int *flags );
 static void mailslot_queue_async( struct fd *, void*, void*, void*, int, int );
 
 static const struct fd_ops mailslot_fd_ops =
@@ -128,7 +128,7 @@ static const struct object_ops mail_writer_ops =
     mail_writer_destroy         /* destroy */
 };
 
-static int mail_writer_get_info( struct fd *fd );
+static enum server_fd_type mail_writer_get_info( struct fd *fd, int *flags );
 
 static const struct fd_ops mail_writer_fd_ops =
 {
@@ -153,7 +153,7 @@ static struct fd *mailslot_device_get_fd( struct object *obj );
 static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name,
                                                    unsigned int attr );
 static void mailslot_device_destroy( struct object *obj );
-static int mailslot_device_get_file_info( struct fd *fd );
+static enum server_fd_type mailslot_device_get_file_info( struct fd *fd, int *flags );
 
 static const struct object_ops mailslot_device_ops =
 {
@@ -212,11 +212,12 @@ static int mailslot_message_count(struct mailslot *mailslot)
     return (poll( &pfd, 1, 0 ) == 1) ? 1 : 0;
 }
 
-static int mailslot_get_info( struct fd *fd )
+static enum server_fd_type mailslot_get_info( struct fd *fd, int *flags )
 {
     struct mailslot *mailslot = get_fd_user( fd );
     assert( mailslot->obj.ops == &mailslot_ops );
-    return FD_FLAG_TIMEOUT | FD_FLAG_AVAILABLE;
+    *flags = FD_FLAG_TIMEOUT | FD_FLAG_AVAILABLE;
+    return FD_TYPE_MAILSLOT;
 }
 
 static struct fd *mailslot_get_fd( struct object *obj )
@@ -298,9 +299,10 @@ static void mailslot_device_destroy( struct object *obj )
     free( device->mailslots );
 }
 
-static int mailslot_device_get_file_info( struct fd *fd )
+static enum server_fd_type mailslot_device_get_file_info( struct fd *fd, int *flags )
 {
-    return 0;
+    *flags = 0;
+    return FD_TYPE_DEVICE;
 }
 
 void create_mailslot_device( struct directory *root, const struct unicode_str *name )
@@ -396,9 +398,10 @@ static void mail_writer_destroy( struct object *obj)
     release_object( writer->mailslot );
 }
 
-static int mail_writer_get_info( struct fd *fd )
+static enum server_fd_type mail_writer_get_info( struct fd *fd, int *flags )
 {
-    return 0;
+    *flags = 0;
+    return FD_TYPE_MAILSLOT;
 }
 
 static struct fd *mail_writer_get_fd( struct object *obj )
diff --git a/server/named_pipe.c b/server/named_pipe.c
index e58f5b07825..8cbd7e57df5 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -134,7 +134,7 @@ static void pipe_server_dump( struct object *obj, int verbose );
 static struct fd *pipe_server_get_fd( struct object *obj );
 static void pipe_server_destroy( struct object *obj);
 static int pipe_server_flush( struct fd *fd, struct event **event );
-static int pipe_server_get_info( struct fd *fd );
+static enum server_fd_type pipe_server_get_info( struct fd *fd, int *flags );
 
 static const struct object_ops pipe_server_ops =
 {
@@ -167,7 +167,7 @@ static void pipe_client_dump( struct object *obj, int verbose );
 static struct fd *pipe_client_get_fd( struct object *obj );
 static void pipe_client_destroy( struct object *obj );
 static int pipe_client_flush( struct fd *fd, struct event **event );
-static int pipe_client_get_info( struct fd *fd );
+static enum server_fd_type pipe_client_get_info( struct fd *fd, int *flags );
 
 static const struct object_ops pipe_client_ops =
 {
@@ -200,7 +200,7 @@ static struct fd *named_pipe_device_get_fd( struct object *obj );
 static struct object *named_pipe_device_lookup_name( struct object *obj,
     struct unicode_str *name, unsigned int attr );
 static void named_pipe_device_destroy( struct object *obj );
-static int named_pipe_device_get_file_info( struct fd *fd );
+static enum server_fd_type named_pipe_device_get_file_info( struct fd *fd, int *flags );
 
 static const struct object_ops named_pipe_device_ops =
 {
@@ -438,9 +438,10 @@ static void named_pipe_device_destroy( struct object *obj )
     free( device->pipes );
 }
 
-static int named_pipe_device_get_file_info( struct fd *fd )
+static enum server_fd_type named_pipe_device_get_file_info( struct fd *fd, int *flags )
 {
-    return 0;
+    *flags = 0;
+    return FD_TYPE_DEVICE;
 }
 
 void create_named_pipe_device( struct directory *root, const struct unicode_str *name )
@@ -545,24 +546,22 @@ static inline int is_overlapped( unsigned int options )
     return !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
 }
 
-static int pipe_server_get_info( struct fd *fd )
+static enum server_fd_type pipe_server_get_info( struct fd *fd, int *flags )
 {
     struct pipe_server *server = get_fd_user( fd );
-    int flags = FD_FLAG_AVAILABLE;
- 
-    if (is_overlapped( server->options )) flags |= FD_FLAG_OVERLAPPED;
 
-    return flags;
+    *flags = FD_FLAG_AVAILABLE;
+    if (is_overlapped( server->options )) *flags |= FD_FLAG_OVERLAPPED;
+    return FD_TYPE_PIPE;
 }
 
-static int pipe_client_get_info( struct fd *fd )
+static enum server_fd_type pipe_client_get_info( struct fd *fd, int *flags )
 {
     struct pipe_client *client = get_fd_user( fd );
-    int flags = FD_FLAG_AVAILABLE;
-
-    if (is_overlapped( client->flags )) flags |= FD_FLAG_OVERLAPPED;
 
-    return flags;
+    *flags = FD_FLAG_AVAILABLE;
+    if (is_overlapped( client->flags )) *flags |= FD_FLAG_OVERLAPPED;
+    return FD_TYPE_PIPE;
 }
 
 static struct named_pipe *create_named_pipe( struct directory *root, const struct unicode_str *name,
diff --git a/server/protocol.def b/server/protocol.def
index 192b8a39cfb..e8f219642c3 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -661,8 +661,21 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
     unsigned int access;        /* wanted access rights */
     int          cached;        /* is it cached on the client already? */
 @REPLY
+    int          type;          /* file type (see below) */
     int          flags;         /* file read/write flags (see below) */
 @END
+enum server_fd_type
+{
+    FD_TYPE_INVALID,  /* invalid file (no associated fd) */
+    FD_TYPE_FILE,     /* regular file */
+    FD_TYPE_DIR,      /* directory */
+    FD_TYPE_SOCKET,   /* socket */
+    FD_TYPE_SERIAL,   /* serial port */
+    FD_TYPE_PIPE,     /* named pipe */
+    FD_TYPE_MAILSLOT, /* mailslot */
+    FD_TYPE_DEVICE,   /* Windows device file */
+    FD_TYPE_NB_TYPES
+};
 #define FD_FLAG_OVERLAPPED         0x01 /* fd opened in overlapped mode */
 #define FD_FLAG_TIMEOUT            0x02 /* read/write is synchronous */
 #define FD_FLAG_RECV_SHUTDOWN      0x04
diff --git a/server/serial.c b/server/serial.c
index a7722565d91..03909d0710e 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -63,7 +63,7 @@ static void serial_destroy(struct object *obj);
 
 static int serial_get_poll_events( struct fd *fd );
 static void serial_poll_event( struct fd *fd, int event );
-static int serial_get_info( struct fd *fd );
+static enum server_fd_type serial_get_info( struct fd *fd, int *flags );
 static int serial_flush( struct fd *fd, struct event **event );
 static void serial_queue_async( struct fd *fd, void *apc, void *user, void *iosb, int type, int count );
 static void serial_cancel_async( struct fd *fd );
@@ -205,22 +205,22 @@ static int serial_get_poll_events( struct fd *fd )
     return events;
 }
 
-static int serial_get_info( struct fd *fd )
+static enum server_fd_type serial_get_info( struct fd *fd, int *flags )
 {
-    int flags = 0;
     struct serial *serial = get_fd_user( fd );
     assert( serial->obj.ops == &serial_ops );
 
+    *flags = 0;
     if (!(serial->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
-        flags |= FD_FLAG_OVERLAPPED;
+        *flags |= FD_FLAG_OVERLAPPED;
     else if (!(serial->readinterval == MAXDWORD &&
                serial->readmult == 0 && serial->readconst == 0))
-        flags |= FD_FLAG_TIMEOUT;
+        *flags |= FD_FLAG_TIMEOUT;
     if (serial->readinterval == MAXDWORD &&
         serial->readmult == 0 && serial->readconst == 0)
-        flags |= FD_FLAG_AVAILABLE;
+        *flags |= FD_FLAG_AVAILABLE;
 
-    return flags;
+    return FD_TYPE_SERIAL;
 }
 
 static void serial_poll_event(struct fd *fd, int event)
diff --git a/server/sock.c b/server/sock.c
index 963746938b4..a98057f17f0 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -95,7 +95,7 @@ static void sock_destroy( struct object *obj );
 
 static int sock_get_poll_events( struct fd *fd );
 static void sock_poll_event( struct fd *fd, int event );
-static int sock_get_info( struct fd *fd );
+static enum server_fd_type sock_get_info( struct fd *fd, int *flags );
 static void sock_queue_async( struct fd *fd, void *apc, void *user, void *iosb, int type, int count );
 static void sock_cancel_async( struct fd *fd );
 
@@ -493,19 +493,19 @@ static int sock_get_poll_events( struct fd *fd )
     return ev;
 }
 
-static int sock_get_info( struct fd *fd )
+static enum server_fd_type sock_get_info( struct fd *fd, int *flags )
 {
-    int flags = FD_FLAG_AVAILABLE;
     struct sock *sock = get_fd_user( fd );
     assert( sock->obj.ops == &sock_ops );
 
-    if (sock->flags & WSA_FLAG_OVERLAPPED) flags |= FD_FLAG_OVERLAPPED;
+    *flags = FD_FLAG_AVAILABLE;
+    if (sock->flags & WSA_FLAG_OVERLAPPED) *flags |= FD_FLAG_OVERLAPPED;
     if ( sock->type != SOCK_STREAM || sock->state & FD_WINE_CONNECTED )
     {
-        if ( !(sock->state & FD_READ  ) ) flags |= FD_FLAG_RECV_SHUTDOWN;
-        if ( !(sock->state & FD_WRITE ) ) flags |= FD_FLAG_SEND_SHUTDOWN;
+        if ( !(sock->state & FD_READ  ) ) *flags |= FD_FLAG_RECV_SHUTDOWN;
+        if ( !(sock->state & FD_WRITE ) ) *flags |= FD_FLAG_SEND_SHUTDOWN;
     }
-    return flags;
+    return FD_TYPE_SOCKET;
 }
 
 static void sock_queue_async( struct fd *fd, void *apc, void *user, void *iosb,
diff --git a/server/trace.c b/server/trace.c
index 50268f94222..0e07987ff6b 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1104,6 +1104,7 @@ 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, " type=%d,", req->type );
     fprintf( stderr, " flags=%d", req->flags );
 }
 
-- 
GitLab