From 863637b158114511bb14e01ca555c580f0ef20b1 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Thu, 30 Jan 2003 00:26:44 +0000
Subject: [PATCH] Started moving functions that deal with Unix file descriptors
 to a separate fd object. This will be needed for file locking.

---
 server/Makefile.in  |   1 +
 server/async.c      |  31 ------
 server/atom.c       |   4 -
 server/change.c     |   4 -
 server/console.c    |  12 ---
 server/debugger.c   |   8 --
 server/device.c     |   4 -
 server/event.c      |   4 -
 server/fd.c         | 244 ++++++++++++++++++++++++++++++++++++++++++++
 server/file.c       |  86 +++++++---------
 server/file.h       |  56 ++++++++++
 server/handle.c     |   4 -
 server/hook.c       |   4 -
 server/mapping.c    |  20 ++--
 server/mutex.c      |   4 -
 server/named_pipe.c |  33 +++---
 server/object.c     |  47 ++-------
 server/object.h     |  20 +---
 server/pipe.c       |  28 +++--
 server/process.c    |  18 ++--
 server/queue.c      |   8 --
 server/registry.c   |  10 +-
 server/request.c    |  14 ++-
 server/select.c     |   4 +-
 server/semaphore.c  |   4 -
 server/serial.c     |  39 +++----
 server/smb.c        |  28 +++--
 server/snapshot.c   |   4 -
 server/sock.c       |  33 +++---
 server/thread.c     |  14 ++-
 server/timer.c      |   4 -
 31 files changed, 465 insertions(+), 329 deletions(-)
 create mode 100644 server/fd.c
 create mode 100644 server/file.h

diff --git a/server/Makefile.in b/server/Makefile.in
index 543b8e36509..bfdc29b9012 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -16,6 +16,7 @@ C_SRCS = \
 	debugger.c \
 	device.c \
 	event.c \
+	fd.c \
 	file.c \
 	handle.c \
 	hook.c \
diff --git a/server/async.c b/server/async.c
index 5bbbb44aa1a..2249fa1f889 100644
--- a/server/async.c
+++ b/server/async.c
@@ -147,34 +147,3 @@ void async_add_timeout(struct async *async, int timeout)
         async->timeout = add_timeout_user( &async->when, async_callback, async );
     }
 }
-
-DECL_HANDLER(register_async)
-{
-    struct object *obj = get_handle_obj( current->process, req->handle, 0, NULL);
-
-    if ( !(obj) || !obj->ops->queue_async )
-    {
-        set_error(STATUS_INVALID_HANDLE);
-        return;
-    }
-
-/*
- * The queue_async method must do the following:
- *
- * 1. Get the async_queue for the request of given type.
- * 2. Call find_async() to look for the specific client request in the queue (=> NULL if not found).
- * 3. If status is STATUS_PENDING:
- *      a) If no async request found in step 2 (new request): call create_async() to initialize one.
- *      b) Set request's status to STATUS_PENDING.
- *      c) If the "queue" field of the async request is NULL: call async_insert() to put it into the queue.
- *    Otherwise:
- *      If the async request was found in step 2, destroy it by calling destroy_async().
- * 4. Carry out any operations necessary to adjust the object's poll events
- *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
- *
- * See also the implementations in file.c, serial.c, and sock.c.
-*/
-
-    obj->ops->queue_async (obj, req->overlapped, req->status, req->type, req->count);
-    release_object(obj);
-}
diff --git a/server/atom.c b/server/atom.c
index 3ab80861f90..40b07f4cf94 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -71,12 +71,8 @@ static const struct object_ops atom_table_ops =
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satified */
-    NULL,                         /* get_poll_events */
-    NULL,                         /* poll_event */
     no_get_fd,                    /* get_fd */
-    no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
-    NULL,                         /* queue_async */
     atom_table_destroy            /* destroy */
 };
 
diff --git a/server/change.c b/server/change.c
index a6316426472..e110eadfeeb 100644
--- a/server/change.c
+++ b/server/change.c
@@ -46,12 +46,8 @@ static const struct object_ops change_ops =
     remove_queue,             /* remove_queue */
     change_signaled,          /* signaled */
     no_satisfied,             /* satisfied */
-    NULL,                     /* get_poll_events */
-    NULL,                     /* poll_event */
     no_get_fd,                /* get_fd */
-    no_flush,                 /* flush */
     no_get_file_info,         /* get_file_info */
-    NULL,                     /* queue_async */
     no_destroy                /* destroy */
 };
 
diff --git a/server/console.c b/server/console.c
index e7e4f317018..6288a1a02eb 100644
--- a/server/console.c
+++ b/server/console.c
@@ -51,12 +51,8 @@ static const struct object_ops console_input_ops =
     remove_queue,                     /* remove_queue */
     console_input_signaled,           /* signaled */
     no_satisfied,                     /* satisfied */
-    NULL,                             /* get_poll_events */
-    NULL,                             /* poll_event */
     no_get_fd,                        /* get_fd */
-    no_flush,                         /* flush */
     console_get_file_info,            /* get_file_info */
-    NULL,                             /* queue_async */
     console_input_destroy             /* destroy */
 };
 
@@ -80,12 +76,8 @@ static const struct object_ops console_input_events_ops =
     remove_queue,                     /* remove_queue */
     console_input_events_signaled,    /* signaled */
     no_satisfied,                     /* satisfied */
-    NULL,                             /* get_poll_events */
-    NULL,                             /* poll_event */
     no_get_fd,                        /* get_fd */
-    no_flush,                         /* flush */
     no_get_file_info,                 /* get_file_info */
-    NULL,                             /* queue_async */
     console_input_events_destroy      /* destroy */
 };
 
@@ -121,12 +113,8 @@ static const struct object_ops screen_buffer_ops =
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
     NULL,                             /* satisfied */
-    NULL,                             /* get_poll_events */
-    NULL,                             /* poll_event */
     no_get_fd,                        /* get_fd */
-    no_flush,                         /* flush */
     console_get_file_info,            /* get_file_info */
-    NULL,                             /* queue_async */
     screen_buffer_destroy             /* destroy */
 };
 
diff --git a/server/debugger.c b/server/debugger.c
index ba08bd2fde9..04276464e7e 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -72,12 +72,8 @@ static const struct object_ops debug_event_ops =
     remove_queue,                  /* remove_queue */
     debug_event_signaled,          /* signaled */
     no_satisfied,                  /* satisfied */
-    NULL,                          /* get_poll_events */
-    NULL,                          /* poll_event */
     no_get_fd,                     /* get_fd */
-    no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
-    NULL,                          /* queue_async */
     debug_event_destroy            /* destroy */
 };
 
@@ -93,12 +89,8 @@ static const struct object_ops debug_ctx_ops =
     remove_queue,                  /* remove_queue */
     debug_ctx_signaled,            /* signaled */
     no_satisfied,                  /* satisfied */
-    NULL,                          /* get_poll_events */
-    NULL,                          /* poll_event */
     no_get_fd,                     /* get_fd */
-    no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
-    NULL,                          /* queue_async */
     debug_ctx_destroy              /* destroy */
 };
 
diff --git a/server/device.c b/server/device.c
index 61ead6cb7d1..939e6c8651c 100644
--- a/server/device.c
+++ b/server/device.c
@@ -53,12 +53,8 @@ static const struct object_ops device_ops =
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
     NULL,                     /* satisfied */
-    NULL,                     /* get_poll_events */
-    NULL,                     /* poll_event */
     no_get_fd,                /* get_fd */
-    no_flush,                 /* flush */
     device_get_info,          /* get_file_info */
-    NULL,                     /* queue_async */
     no_destroy                /* destroy */
 };
 
diff --git a/server/event.c b/server/event.c
index b223487f073..927e2c77ed7 100644
--- a/server/event.c
+++ b/server/event.c
@@ -50,12 +50,8 @@ static const struct object_ops event_ops =
     remove_queue,              /* remove_queue */
     event_signaled,            /* signaled */
     event_satisfied,           /* satisfied */
-    NULL,                      /* get_poll_events */
-    NULL,                      /* poll_event */
     no_get_fd,                 /* get_fd */
-    no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
-    NULL,                      /* queue_async */
     no_destroy                 /* destroy */
 };
 
diff --git a/server/fd.c b/server/fd.c
new file mode 100644
index 00000000000..1dff6efe80c
--- /dev/null
+++ b/server/fd.c
@@ -0,0 +1,244 @@
+/*
+ * Server-side file descriptor management
+ *
+ * Copyright (C) 2003 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "object.h"
+#include "file.h"
+#include "handle.h"
+#include "process.h"
+#include "request.h"
+
+struct fd
+{
+    struct object        obj;        /* object header */
+    const struct fd_ops *fd_ops;     /* file descriptor operations */
+    struct object       *user;       /* object using this file descriptor */
+    int                  unix_fd;    /* unix file descriptor */
+    int                  mode;       /* file protection mode */
+};
+
+static void fd_dump( struct object *obj, int verbose );
+static void fd_destroy( struct object *obj );
+
+static const struct object_ops fd_ops =
+{
+    sizeof(struct fd),        /* size */
+    fd_dump,                  /* dump */
+    no_add_queue,             /* add_queue */
+    NULL,                     /* remove_queue */
+    NULL,                     /* signaled */
+    NULL,                     /* satisfied */
+    default_get_fd,           /* get_fd */
+    no_get_file_info,         /* get_file_info */
+    fd_destroy                /* destroy */
+};
+
+
+static void fd_dump( struct object *obj, int verbose )
+{
+    struct fd *fd = (struct fd *)obj;
+    fprintf( stderr, "Fd unix_fd=%d mode=%06o user=%p\n", fd->unix_fd, fd->mode, fd->user );
+}
+
+static void fd_destroy( struct object *obj )
+{
+#if 0
+    struct fd *fd = (struct fd *)obj;
+    close( fd->unix_fd );
+#endif
+}
+
+/* allocate an object that has an associated fd */
+void *alloc_fd_object( const struct object_ops *ops,
+                       const struct fd_ops *fd_user_ops, int unix_fd )
+{
+    struct object *user;
+    struct fd *fd = alloc_object( &fd_ops, -1 );
+
+    if (!fd) return NULL;
+    if (!(user = alloc_object( ops, unix_fd )))
+    {
+        release_object( fd );
+        return NULL;
+    }
+    fd->fd_ops   = fd_user_ops;
+    fd->user     = user;
+    fd->unix_fd  = unix_fd;
+    fd->mode     = 0;
+
+    user->fd_obj = fd;
+    return user;
+}
+
+/* retrieve the unix fd for an object */
+int get_unix_fd( struct object *obj )
+{
+    struct fd *fd = obj->ops->get_fd( obj );
+    int unix_fd = -1;
+
+    if (fd)
+    {
+        unix_fd = fd->unix_fd;
+        release_object( fd );
+    }
+    return unix_fd;
+}
+
+/* set the unix fd for an object; can only be done once */
+void set_unix_fd( struct object *obj, int unix_fd )
+{
+    struct fd *fd = obj->fd_obj;
+
+    assert( fd );
+    assert( fd->unix_fd == -1 );
+
+    fd->unix_fd = unix_fd;
+    obj->fd = unix_fd;
+}
+
+/* close a file descriptor */
+void close_fd( struct fd *fd )
+{
+    release_object( fd );
+}
+
+/* callback for event happening in the main poll() loop */
+void fd_poll_event( struct object *obj, int event )
+{
+    struct fd *fd = obj->fd_obj;
+    return fd->fd_ops->poll_event( fd->user, event );
+}
+
+/* default add_queue() routine for objects that poll() on an fd */
+int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry )
+{
+    struct fd *fd = obj->fd_obj;
+
+    if (!obj->head)  /* first on the queue */
+        set_select_events( obj, fd->fd_ops->get_poll_events( fd->user ) );
+    add_queue( obj, entry );
+    return 1;
+}
+
+/* default remove_queue() routine for objects that poll() on an fd */
+void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry )
+{
+    grab_object( obj );
+    remove_queue( obj, entry );
+    if (!obj->head)  /* last on the queue is gone */
+        set_select_events( obj, 0 );
+    release_object( obj );
+}
+
+/* default signaled() routine for objects that poll() on an fd */
+int default_fd_signaled( struct object *obj, struct thread *thread )
+{
+    struct fd *fd = obj->fd_obj;
+    int events = fd->fd_ops->get_poll_events( obj );
+
+    if (check_select_events( fd->unix_fd, events ))
+    {
+        /* stop waiting on select() if we are signaled */
+        set_select_events( obj, 0 );
+        return 1;
+    }
+    /* restart waiting on select() if we are no longer signaled */
+    if (obj->head) set_select_events( obj, events );
+    return 0;
+}
+
+/* default flush() routine */
+int no_flush( struct object *obj )
+{
+    set_error( STATUS_OBJECT_TYPE_MISMATCH );
+    return 0;
+}
+
+/* default queue_async() routine */
+void no_queue_async( struct object *obj, void* ptr, unsigned int status, int type, int count )
+{
+    set_error( STATUS_OBJECT_TYPE_MISMATCH );
+}
+
+/* same as get_handle_obj but retrieve the struct fd associated to the object */
+static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handle,
+                                     unsigned int access )
+{
+    struct fd *fd = NULL;
+    struct object *obj;
+
+    if ((obj = get_handle_obj( process, handle, 0, NULL )))
+    {
+        if (obj->fd_obj) fd = (struct fd *)grab_object( obj->fd_obj );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
+        release_object( obj );
+    }
+    return fd;
+}
+
+
+/* flush a file buffers */
+DECL_HANDLER(flush_file)
+{
+    struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
+
+    if (fd)
+    {
+        fd->fd_ops->flush( fd->user );
+        release_object( fd );
+    }
+}
+
+/* create / reschedule an async I/O */
+DECL_HANDLER(register_async)
+{
+    struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
+
+/*
+ * The queue_async method must do the following:
+ *
+ * 1. Get the async_queue for the request of given type.
+ * 2. Call find_async() to look for the specific client request in the queue (=> NULL if not found).
+ * 3. If status is STATUS_PENDING:
+ *      a) If no async request found in step 2 (new request): call create_async() to initialize one.
+ *      b) Set request's status to STATUS_PENDING.
+ *      c) If the "queue" field of the async request is NULL: call async_insert() to put it into the queue.
+ *    Otherwise:
+ *      If the async request was found in step 2, destroy it by calling destroy_async().
+ * 4. Carry out any operations necessary to adjust the object's poll events
+ *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
+ *
+ * See also the implementations in file.c, serial.c, and sock.c.
+*/
+
+    if (fd)
+    {
+        fd->fd_ops->queue_async( fd->user, req->overlapped, req->status, req->type, req->count );
+        release_object( fd );
+    }
+}
diff --git a/server/file.c b/server/file.c
index b302fe67f1b..b4560a82a74 100644
--- a/server/file.c
+++ b/server/file.c
@@ -40,6 +40,7 @@
 #include "winerror.h"
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
@@ -65,7 +66,6 @@ static struct file *file_hash[NAME_HASH_SIZE];
 static void file_dump( struct object *obj, int verbose );
 static int file_get_poll_events( struct object *obj );
 static void file_poll_event( struct object *obj, int event );
-static int file_get_fd( struct object *obj );
 static int file_flush( struct object *obj );
 static int file_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static void file_destroy( struct object *obj );
@@ -75,20 +75,24 @@ static const struct object_ops file_ops =
 {
     sizeof(struct file),          /* size */
     file_dump,                    /* dump */
-    default_poll_add_queue,       /* add_queue */
-    default_poll_remove_queue,    /* remove_queue */
-    default_poll_signaled,        /* signaled */
+    default_fd_add_queue,         /* add_queue */
+    default_fd_remove_queue,      /* remove_queue */
+    default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    default_get_fd,               /* get_fd */
+    file_get_info,                /* get_file_info */
+    file_destroy                  /* destroy */
+};
+
+static const struct fd_ops file_fd_ops =
+{
     file_get_poll_events,         /* get_poll_events */
     file_poll_event,              /* poll_event */
-    file_get_fd,                  /* get_fd */
     file_flush,                   /* flush */
     file_get_info,                /* get_file_info */
-    file_queue_async,             /* queue_async */
-    file_destroy                  /* destroy */
+    file_queue_async              /* queue_async */
 };
 
-
 static int get_name_hash( const char *name )
 {
     int hash = 0;
@@ -127,7 +131,8 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in
                                         unsigned int attrs, int drive_type )
 {
     struct file *file;
-    if ((file = alloc_object( &file_ops, fd )))
+
+    if ((file = alloc_fd_object( &file_ops, &file_fd_ops, fd )))
     {
         file->name       = NULL;
         file->next       = NULL;
@@ -291,22 +296,10 @@ static void file_poll_event( struct object *obj, int event )
 }
 
 
-static int file_get_fd( struct object *obj )
-{
-    struct file *file = (struct file *)obj;
-    assert( obj->ops == &file_ops );
-    return file->obj.fd;
-}
-
 static int file_flush( struct object *obj )
 {
-    int ret;
-    struct file *file = (struct file *)grab_object(obj);
-    assert( obj->ops == &file_ops );
-
-    ret = (fsync( file->obj.fd ) != -1);
+    int ret = (fsync( get_unix_fd(obj) ) != -1);
     if (!ret) file_set_error();
-    release_object( file );
     return ret;
 }
 
@@ -314,17 +307,17 @@ static int file_get_info( struct object *obj, struct get_file_info_reply *reply,
 {
     struct stat st;
     struct file *file = (struct file *)obj;
-    assert( obj->ops == &file_ops );
+    int unix_fd = get_unix_fd( obj );
 
     if (reply)
     {
-        if (fstat( file->obj.fd, &st ) == -1)
+        if (fstat( unix_fd, &st ) == -1)
         {
             file_set_error();
             return FD_TYPE_INVALID;
         }
         if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) ||
-            S_ISSOCK(st.st_mode) || isatty(file->obj.fd)) reply->type = FILE_TYPE_CHAR;
+            S_ISSOCK(st.st_mode) || isatty(unix_fd)) reply->type = FILE_TYPE_CHAR;
         else reply->type = FILE_TYPE_DISK;
         if (S_ISDIR(st.st_mode)) reply->attr = FILE_ATTRIBUTE_DIRECTORY;
         else reply->attr = FILE_ATTRIBUTE_ARCHIVE;
@@ -394,7 +387,7 @@ static void file_queue_async(struct object *obj, void *ptr, unsigned int status,
             async_insert( q, async );
 
         /* Check if the new pending request can be served immediately */
-        pfd.fd = obj->fd;
+        pfd.fd = get_unix_fd( obj );
         pfd.events = file_get_poll_events ( obj );
         pfd.revents = 0;
         poll ( &pfd, 1, 0 );
@@ -469,7 +462,7 @@ static int set_file_pointer( obj_handle_t handle, unsigned int *low, int *high,
     xto = *low+((off_t)*high<<32);
     if (!(file = get_file_obj( current->process, handle, 0 )))
         return 0;
-    if ((result = lseek(file->obj.fd,xto,whence))==-1)
+    if ((result = lseek( get_unix_fd(&file->obj), xto, whence))==-1)
     {
         /* Check for seek before start of file */
 
@@ -492,13 +485,14 @@ static int set_file_pointer( obj_handle_t handle, unsigned int *low, int *high,
 static int extend_file( struct file *file, off_t size )
 {
     static const char zero;
+    int unix_fd = get_unix_fd( &file->obj );
 
     /* extend the file one byte beyond the requested size and then truncate it */
     /* this should work around ftruncate implementations that can't extend files */
-    if ((lseek( file->obj.fd, size, SEEK_SET ) != -1) &&
-        (write( file->obj.fd, &zero, 1 ) != -1))
+    if ((lseek( unix_fd, size, SEEK_SET ) != -1) &&
+        (write( unix_fd, &zero, 1 ) != -1))
     {
-        ftruncate( file->obj.fd, size );
+        ftruncate( unix_fd, size );
         return 1;
     }
     file_set_error();
@@ -509,16 +503,17 @@ static int extend_file( struct file *file, off_t size )
 static int truncate_file( struct file *file )
 {
     int ret = 0;
-    off_t pos = lseek( file->obj.fd, 0, SEEK_CUR );
-    off_t eof = lseek( file->obj.fd, 0, SEEK_END );
+    int unix_fd = get_unix_fd( &file->obj );
+    off_t pos = lseek( unix_fd, 0, SEEK_CUR );
+    off_t eof = lseek( unix_fd, 0, SEEK_END );
 
     if (eof < pos) ret = extend_file( file, pos );
     else
     {
-        if (ftruncate( file->obj.fd, pos ) != -1) ret = 1;
+        if (ftruncate( unix_fd, pos ) != -1) ret = 1;
         else file_set_error();
     }
-    lseek( file->obj.fd, pos, SEEK_SET );  /* restore file pos */
+    lseek( unix_fd, pos, SEEK_SET );  /* restore file pos */
     return ret;
 }
 
@@ -527,17 +522,18 @@ int grow_file( struct file *file, int size_high, int size_low )
 {
     int ret = 0;
     struct stat st;
+    int unix_fd = get_unix_fd( &file->obj );
     off_t old_pos, size = size_low + (((off_t)size_high)<<32);
 
-    if (fstat( file->obj.fd, &st ) == -1)
+    if (fstat( unix_fd, &st ) == -1)
     {
         file_set_error();
         return 0;
     }
     if (st.st_size >= size) return 1;  /* already large enough */
-    old_pos = lseek( file->obj.fd, 0, SEEK_CUR );  /* save old pos */
+    old_pos = lseek( unix_fd, 0, SEEK_CUR );  /* save old pos */
     ret = extend_file( file, size );
-    lseek( file->obj.fd, old_pos, SEEK_SET );  /* restore file pos */
+    lseek( unix_fd, old_pos, SEEK_SET );  /* restore file pos */
     return ret;
 }
 
@@ -633,8 +629,8 @@ DECL_HANDLER(get_handle_fd)
         if (fd != -1) reply->fd = fd;
         else if (!get_error())
         {
-            if ((fd = obj->ops->get_fd( obj )) != -1)
-                send_client_fd( current->process, fd, req->handle );
+            int unix_fd = get_unix_fd( obj );
+            if (unix_fd != -1) send_client_fd( current->process, unix_fd, req->handle );
         }
         reply->type = obj->ops->get_file_info( obj, NULL, &reply->flags );
         release_object( obj );
@@ -663,18 +659,6 @@ DECL_HANDLER(truncate_file)
     }
 }
 
-/* flush a file buffers */
-DECL_HANDLER(flush_file)
-{
-    struct object *obj;
-
-    if ((obj = get_handle_obj( current->process, req->handle, 0, NULL )))
-    {
-        obj->ops->flush( obj );
-        release_object( obj );
-    }
-}
-
 /* set a file access and modification times */
 DECL_HANDLER(set_file_time)
 {
diff --git a/server/file.h b/server/file.h
new file mode 100644
index 00000000000..f5c9a32c308
--- /dev/null
+++ b/server/file.h
@@ -0,0 +1,56 @@
+/*
+ * Server-side file definitions
+ *
+ * Copyright (C) 2003 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __WINE_SERVER_FILE_H
+#define __WINE_SERVER_FILE_H
+
+#include "object.h"
+
+struct fd;
+
+/* operations valid on file descriptor objects */
+struct fd_ops
+{
+    /* get the events we want to poll() for on this object */
+    int  (*get_poll_events)(struct object *);
+    /* a poll() event occured */
+    void (*poll_event)(struct object *,int event);
+    /* flush the object buffers */
+    int  (*flush)(struct object *);
+    /* get file information */
+    int  (*get_file_info)(struct object *,struct get_file_info_reply *, int *flags);
+    /* queue an async operation - see register_async handler in async.c*/
+    void (*queue_async)(struct object *, void* ptr, unsigned int status, int type, int count);
+};
+
+extern void *alloc_fd_object( const struct object_ops *ops,
+                              const struct fd_ops *fd_user_ops, int unix_fd );
+extern int get_unix_fd( struct object *obj );
+extern void set_unix_fd( struct object *obj, int unix_fd );
+extern void close_fd( struct fd *fd );
+extern void fd_poll_event( struct object *obj, int event );
+
+extern int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry );
+extern void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry );
+extern int default_fd_signaled( struct object *obj, struct thread *thread );
+extern int no_flush( struct object *obj );
+extern void no_queue_async(struct object *obj, void* ptr, unsigned int status, int type, int count);
+
+#endif  /* __WINE_SERVER_FILE_H */
diff --git a/server/handle.c b/server/handle.c
index 9df42935535..471d5a7edee 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -104,12 +104,8 @@ static const struct object_ops handle_table_ops =
     NULL,                            /* remove_queue */
     NULL,                            /* signaled */
     NULL,                            /* satisfied */
-    NULL,                            /* get_poll_events */
-    NULL,                            /* poll_event */
     no_get_fd,                       /* get_fd */
-    no_flush,                        /* flush */
     no_get_file_info,                /* get_file_info */
-    NULL,                            /* queue_async */
     handle_table_destroy             /* destroy */
 };
 
diff --git a/server/hook.c b/server/hook.c
index 3a483c18f29..d10318dca0f 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -66,12 +66,8 @@ static const struct object_ops hook_table_ops =
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
-    NULL,                         /* get_poll_events */
-    NULL,                         /* poll_event */
     no_get_fd,                    /* get_fd */
-    no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
-    NULL,                         /* queue_async */
     hook_table_destroy            /* destroy */
 };
 
diff --git a/server/mapping.c b/server/mapping.c
index b7b055c6922..4881bc734d2 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -28,6 +28,7 @@
 
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
@@ -47,7 +48,7 @@ struct mapping
     struct mapping *shared_prev;     /* prev in shared PE mapping list */
 };
 
-static int mapping_get_fd( struct object *obj );
+static struct fd *mapping_get_fd( struct object *obj );
 static int mapping_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static void mapping_dump( struct object *obj, int verbose );
 static void mapping_destroy( struct object *obj );
@@ -60,12 +61,8 @@ static const struct object_ops mapping_ops =
     NULL,                        /* remove_queue */
     NULL,                        /* signaled */
     NULL,                        /* satisfied */
-    NULL,                        /* get_poll_events */
-    NULL,                        /* poll_event */
     mapping_get_fd,              /* get_fd */
-    no_flush,                    /* flush */
     mapping_get_info,            /* get_file_info */
-    NULL,                        /* queue_async */
     mapping_destroy              /* destroy */
 };
 
@@ -111,13 +108,7 @@ static void init_page_size(void)
 /* get the fd to use for mmaping a file */
 inline static int get_mmap_fd( struct file *file )
 {
-    struct object *obj;
-    if (!(obj = (struct object *)file))
-    {
-        set_error( STATUS_INVALID_HANDLE );
-        return -1;
-    }
-    return obj->ops->get_fd( obj );
+    return get_unix_fd( (struct object *)file );
 }
 
 /* find the shared PE mapping for a given mapping */
@@ -327,11 +318,12 @@ static void mapping_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
-static int mapping_get_fd( struct object *obj )
+static struct fd *mapping_get_fd( struct object *obj )
 {
     struct mapping *mapping = (struct mapping *)obj;
     assert( obj->ops == &mapping_ops );
-    return get_mmap_fd( mapping->file );
+
+    return default_get_fd( (struct object *)mapping->file );
 }
 
 static int mapping_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
diff --git a/server/mutex.c b/server/mutex.c
index fe765534156..9ca844e3c8e 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -54,12 +54,8 @@ static const struct object_ops mutex_ops =
     remove_queue,              /* remove_queue */
     mutex_signaled,            /* signaled */
     mutex_satisfied,           /* satisfied */
-    NULL,                      /* get_poll_events */
-    NULL,                      /* poll_event */
     no_get_fd,                 /* get_fd */
-    no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
-    NULL,                      /* queue_async */
     mutex_destroy              /* destroy */
 };
 
diff --git a/server/named_pipe.c b/server/named_pipe.c
index fab8188d9b1..f2323cc5056 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -38,6 +38,7 @@
 
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
@@ -90,35 +91,35 @@ static const struct object_ops named_pipe_ops =
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
-    NULL,                         /* get_poll_events */
-    NULL,                         /* poll_event */
     no_get_fd,                    /* get_fd */
-    no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
-    NULL,                         /* queue_async */
     named_pipe_destroy            /* destroy */
 };
 
 static void pipe_user_dump( struct object *obj, int verbose );
 static void pipe_user_destroy( struct object *obj);
-static int pipe_user_get_fd( struct object *obj );
 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 
 static const struct object_ops pipe_user_ops =
 {
     sizeof(struct pipe_user),     /* size */
     pipe_user_dump,               /* dump */
-    default_poll_add_queue,       /* add_queue */
-    default_poll_remove_queue,    /* remove_queue */
-    default_poll_signaled,        /* signaled */
+    default_fd_add_queue,         /* add_queue */
+    default_fd_remove_queue,      /* remove_queue */
+    default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    default_get_fd,               /* get_fd */
+    pipe_user_get_info,           /* get_file_info */
+    pipe_user_destroy             /* destroy */
+};
+
+static const struct fd_ops pipe_user_fd_ops =
+{
     NULL,                         /* get_poll_events */
     default_poll_event,           /* poll_event */
-    pipe_user_get_fd,             /* get_fd */
     no_flush,                     /* flush */
     pipe_user_get_info,           /* get_file_info */
-    NULL,                         /* queue_async */
-    pipe_user_destroy             /* destroy */
+    no_queue_async                /* queue_async */
 };
 
 static void named_pipe_dump( struct object *obj, int verbose )
@@ -192,13 +193,6 @@ static void pipe_user_destroy( struct object *obj)
     release_object(user->pipe);
 }
 
-static int pipe_user_get_fd( struct object *obj )
-{
-    struct pipe_user *user = (struct pipe_user *)obj;
-    assert( obj->ops == &pipe_user_ops );
-    return user->obj.fd;
-}
-
 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
 {
     if (reply)
@@ -243,7 +237,7 @@ static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
 {
     struct pipe_user *user;
 
-    user = alloc_object( &pipe_user_ops, fd );
+    user = alloc_fd_object( &pipe_user_ops, &pipe_user_fd_ops, fd );
     if(!user)
         return NULL;
 
@@ -475,4 +469,3 @@ DECL_HANDLER(get_named_pipe_info)
 
     release_object(user);
 }
-
diff --git a/server/object.c b/server/object.c
index 600c04039d9..77e116243ae 100644
--- a/server/object.c
+++ b/server/object.c
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "file.h"
 #include "thread.h"
 #include "unicode.h"
 #include "list.h"
@@ -137,6 +138,7 @@ void *alloc_object( const struct object_ops *ops, int fd )
     if (obj)
     {
         obj->refcount = 1;
+        obj->fd_obj   = NULL;
         obj->fd       = fd;
         obj->select   = -1;
         obj->ops      = ops;
@@ -218,6 +220,7 @@ void release_object( void *ptr )
         assert( !obj->head );
         assert( !obj->tail );
         obj->ops->destroy( obj );
+        if (obj->fd_obj) close_fd( obj->fd_obj );
         if (obj->name) free_name( obj );
         if (obj->select != -1) remove_select_user( obj );
         if (obj->fd != -1) close( obj->fd );
@@ -287,16 +290,17 @@ int no_satisfied( struct object *obj, struct thread *thread )
     return 0;  /* not abandoned */
 }
 
-int no_get_fd( struct object *obj )
+struct fd *no_get_fd( struct object *obj )
 {
     set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return -1;
+    return NULL;
 }
 
-int no_flush( struct object *obj )
+struct fd *default_get_fd( struct object *obj )
 {
+    if (obj->fd_obj) return (struct fd *)grab_object( obj->fd_obj );
     set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return 0;
+    return NULL;
 }
 
 int no_get_file_info( struct object *obj, struct get_file_info_reply *info, int *flags )
@@ -310,41 +314,6 @@ void no_destroy( struct object *obj )
 {
 }
 
-/* default add_queue() routine for objects that poll() on an fd */
-int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry )
-{
-    if (!obj->head)  /* first on the queue */
-        set_select_events( obj, obj->ops->get_poll_events( obj ) );
-    add_queue( obj, entry );
-    return 1;
-}
-
-/* default remove_queue() routine for objects that poll() on an fd */
-void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry )
-{
-    grab_object(obj);
-    remove_queue( obj, entry );
-    if (!obj->head)  /* last on the queue is gone */
-        set_select_events( obj, 0 );
-    release_object( obj );
-}
-
-/* default signaled() routine for objects that poll() on an fd */
-int default_poll_signaled( struct object *obj, struct thread *thread )
-{
-    int events = obj->ops->get_poll_events( obj );
-
-    if (check_select_events( obj->fd, events ))
-    {
-        /* stop waiting on select() if we are signaled */
-        set_select_events( obj, 0 );
-        return 1;
-    }
-    /* restart waiting on select() if we are no longer signaled */
-    if (obj->head) set_select_events( obj, events );
-    return 0;
-}
-
 /* default handler for poll() events */
 void default_poll_event( struct object *obj, int event )
 {
diff --git a/server/object.h b/server/object.h
index 711f5845e23..7868e2fbd73 100644
--- a/server/object.h
+++ b/server/object.h
@@ -55,18 +55,10 @@ struct object_ops
     int  (*signaled)(struct object *,struct thread *);
     /* wait satisfied; return 1 if abandoned */
     int  (*satisfied)(struct object *,struct thread *);
-    /* get the events we want to poll() for on this object */
-    int  (*get_poll_events)(struct object *);
-    /* a poll() event occured */
-    void (*poll_event)(struct object *,int event);
-    /* return a Unix fd that can be used to read/write from the object */
-    int  (*get_fd)(struct object *);
-    /* flush the object buffers */
-    int  (*flush)(struct object *);
+    /* return an fd object that can be used to read/write from the object */
+    struct fd *(*get_fd)(struct object *);
     /* get file information */
     int  (*get_file_info)(struct object *,struct get_file_info_reply *, int *flags);
-    /* queue an async operation - see register_async handler in async.c*/
-    void (*queue_async)(struct object *, void* ptr, unsigned int status, int type, int count);
     /* destroy on refcount == 0 */
     void (*destroy)(struct object *);
 };
@@ -74,6 +66,7 @@ struct object_ops
 struct object
 {
     unsigned int              refcount;    /* reference count */
+    struct fd                *fd_obj;      /* file descriptor */
     int                       fd;          /* file descriptor */
     int                       select;      /* select() user id */
     const struct object_ops  *ops;
@@ -107,13 +100,10 @@ extern void release_object( void *obj );
 extern struct object *find_object( const struct namespace *namespace, const WCHAR *name, size_t len );
 extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
 extern int no_satisfied( struct object *obj, struct thread *thread );
-extern int no_get_fd( struct object *obj );
-extern int no_flush( struct object *obj );
+extern struct fd *no_get_fd( struct object *obj );
+extern struct fd *default_get_fd( struct object *obj );
 extern int no_get_file_info( struct object *obj, struct get_file_info_reply *info, int *flags );
 extern void no_destroy( struct object *obj );
-extern int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry );
-extern void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry );
-extern int default_poll_signaled( struct object *obj, struct thread *thread );
 extern void default_poll_event( struct object *obj, int event );
 #ifdef DEBUG_OBJECTS
 extern void dump_objects(void);
diff --git a/server/pipe.c b/server/pipe.c
index ce6f11a2036..4f57a2fdc8b 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -32,6 +32,7 @@
 
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
@@ -47,7 +48,7 @@ struct pipe
 
 static void pipe_dump( struct object *obj, int verbose );
 static int pipe_get_poll_events( struct object *obj );
-static int pipe_get_fd( struct object *obj );
+static struct fd *pipe_get_fd( struct object *obj );
 static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static void pipe_destroy( struct object *obj );
 
@@ -55,17 +56,22 @@ static const struct object_ops pipe_ops =
 {
     sizeof(struct pipe),          /* size */
     pipe_dump,                    /* dump */
-    default_poll_add_queue,       /* add_queue */
-    default_poll_remove_queue,    /* remove_queue */
-    default_poll_signaled,        /* signaled */
+    default_fd_add_queue,         /* add_queue */
+    default_fd_remove_queue,      /* remove_queue */
+    default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    pipe_get_fd,                  /* get_fd */
+    pipe_get_info,                /* get_file_info */
+    pipe_destroy                  /* destroy */
+};
+
+static const struct fd_ops pipe_fd_ops =
+{
     pipe_get_poll_events,         /* get_poll_events */
     default_poll_event,           /* poll_event */
-    pipe_get_fd,                  /* get_fd */
     no_flush,                     /* flush */
     pipe_get_info,                /* get_file_info */
-    NULL,                         /* queue_async */
-    pipe_destroy                  /* destroy */
+    no_queue_async                /* queue_async */
 };
 
 
@@ -73,7 +79,7 @@ static struct pipe *create_pipe_side( int fd, int side )
 {
     struct pipe *pipe;
 
-    if ((pipe = alloc_object( &pipe_ops, fd )))
+    if ((pipe = alloc_fd_object( &pipe_ops, &pipe_fd_ops, fd )))
     {
         pipe->other  = NULL;
         pipe->side   = side;
@@ -123,7 +129,7 @@ static int pipe_get_poll_events( struct object *obj )
     return (pipe->side == READ_SIDE) ? POLLIN : POLLOUT;
 }
 
-static int pipe_get_fd( struct object *obj )
+static struct fd *pipe_get_fd( struct object *obj )
 {
     struct pipe *pipe = (struct pipe *)obj;
     assert( obj->ops == &pipe_ops );
@@ -131,9 +137,9 @@ static int pipe_get_fd( struct object *obj )
     if (!pipe->other)
     {
         set_error( STATUS_PIPE_BROKEN );
-        return -1;
+        return NULL;
     }
-    return pipe->obj.fd;
+    return (struct fd *)grab_object( pipe->obj.fd_obj );
 }
 
 static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
diff --git a/server/process.c b/server/process.c
index 7d66d1b9eeb..8319129d65a 100644
--- a/server/process.c
+++ b/server/process.c
@@ -36,6 +36,7 @@
 #include "winbase.h"
 #include "winnt.h"
 
+#include "file.h"
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
@@ -62,13 +63,18 @@ static const struct object_ops process_ops =
     remove_queue,                /* remove_queue */
     process_signaled,            /* signaled */
     no_satisfied,                /* satisfied */
+    no_get_fd,                   /* get_fd */
+    no_get_file_info,            /* get_file_info */
+    process_destroy              /* destroy */
+};
+
+static const struct fd_ops process_fd_ops =
+{
     NULL,                        /* get_poll_events */
     process_poll_event,          /* poll_event */
-    no_get_fd,                   /* get_fd */
     no_flush,                    /* flush */
     no_get_file_info,            /* get_file_info */
-    NULL,                        /* queue_async */
-    process_destroy              /* destroy */
+    no_queue_async               /* queue_async */
 };
 
 /* process startup info */
@@ -102,12 +108,8 @@ static const struct object_ops startup_info_ops =
     remove_queue,                  /* remove_queue */
     startup_info_signaled,         /* signaled */
     no_satisfied,                  /* satisfied */
-    NULL,                          /* get_poll_events */
-    NULL,                          /* poll_event */
     no_get_fd,                     /* get_fd */
-    no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
-    NULL,                        /* queue_async */
     startup_info_destroy           /* destroy */
 };
 
@@ -190,7 +192,7 @@ struct thread *create_process( int fd )
     struct thread *thread = NULL;
     int request_pipe[2];
 
-    if (!(process = alloc_object( &process_ops, fd ))) goto error;
+    if (!(process = alloc_fd_object( &process_ops, &process_fd_ops, fd ))) goto error;
     process->next            = NULL;
     process->prev            = NULL;
     process->parent          = NULL;
diff --git a/server/queue.c b/server/queue.c
index 8eaba4d2a34..39c0d0ec956 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -143,12 +143,8 @@ static const struct object_ops msg_queue_ops =
     msg_queue_remove_queue,    /* remove_queue */
     msg_queue_signaled,        /* signaled */
     msg_queue_satisfied,       /* satisfied */
-    NULL,                      /* get_poll_events */
-    NULL,                      /* poll_event */
     no_get_fd,                 /* get_fd */
-    no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
-    NULL,                      /* queue_async */
     msg_queue_destroy          /* destroy */
 };
 
@@ -161,12 +157,8 @@ static const struct object_ops thread_input_ops =
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
-    NULL,                         /* get_poll_events */
-    NULL,                         /* poll_event */
     no_get_fd,                    /* get_fd */
-    no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
-    NULL,                         /* queue_async */
     thread_input_destroy          /* destroy */
 };
 
diff --git a/server/registry.c b/server/registry.c
index 31dfe97c4cf..5b75b50ebb1 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -37,7 +37,9 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <unistd.h>
+
 #include "object.h"
+#include "file.h"
 #include "handle.h"
 #include "request.h"
 #include "unicode.h"
@@ -166,12 +168,8 @@ static const struct object_ops key_ops =
     NULL,                    /* remove_queue */
     NULL,                    /* signaled */
     NULL,                    /* satisfied */
-    NULL,                    /* get_poll_events */
-    NULL,                    /* poll_event */
     no_get_fd,               /* get_fd */
-    no_flush,                /* flush */
     no_get_file_info,        /* get_file_info */
-    NULL,                    /* queue_async */
     key_destroy              /* destroy */
 };
 
@@ -1452,7 +1450,7 @@ static void load_registry( struct key *key, obj_handle_t handle )
     int fd;
 
     if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL ))) return;
-    fd = dup(obj->ops->get_fd( obj ));
+    fd = dup( get_unix_fd( obj ) );
     release_object( obj );
     if (fd != -1)
     {
@@ -1547,7 +1545,7 @@ static void save_registry( struct key *key, obj_handle_t handle )
         return;
     }
     if (!(obj = get_handle_obj( current->process, handle, GENERIC_WRITE, NULL ))) return;
-    fd = dup(obj->ops->get_fd( obj ));
+    fd = dup( get_unix_fd( obj ) );
     release_object( obj );
     if (fd != -1)
     {
diff --git a/server/request.c b/server/request.c
index ff1450b0120..98bec45d8dd 100644
--- a/server/request.c
+++ b/server/request.c
@@ -48,6 +48,7 @@
 #include "wincon.h"
 #include "wine/library.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "process.h"
@@ -81,13 +82,18 @@ static const struct object_ops master_socket_ops =
     NULL,                          /* remove_queue */
     NULL,                          /* signaled */
     NULL,                          /* satisfied */
+    no_get_fd,                     /* get_fd */
+    no_get_file_info,              /* get_file_info */
+    no_destroy                     /* destroy */
+};
+
+static const struct fd_ops master_socket_fd_ops =
+{
     NULL,                          /* get_poll_events */
     master_socket_poll_event,      /* poll_event */
-    no_get_fd,                     /* get_fd */
     no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
-    NULL,                          /* queue_async */
-    no_destroy                     /* destroy */
+    no_queue_async                 /* queue_async */
 };
 
 
@@ -670,7 +676,7 @@ static void acquire_lock(void)
     chmod( server_socket_name, 0600 );  /* make sure no other user can connect */
     if (listen( fd, 5 ) == -1) fatal_perror( "listen" );
 
-    if (!(master_socket = alloc_object( &master_socket_ops, fd )))
+    if (!(master_socket = alloc_fd_object( &master_socket_ops, &master_socket_fd_ops, fd )))
         fatal_error( "out of memory\n" );
     master_socket->timeout = NULL;
     set_select_events( &master_socket->obj, POLLIN );
diff --git a/server/select.c b/server/select.c
index 9b70d04fc92..2ea23548184 100644
--- a/server/select.c
+++ b/server/select.c
@@ -28,7 +28,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "object.h"
+#include "file.h"
 #include "thread.h"
 #include "process.h"
 
@@ -301,7 +301,7 @@ void select_loop(void)
             {
                 if (pollfd[i].revents)
                 {
-                    poll_users[i]->ops->poll_event( poll_users[i], pollfd[i].revents );
+                    fd_poll_event( poll_users[i], pollfd[i].revents );
                     if (!--ret) break;
                 }
             }
diff --git a/server/semaphore.c b/server/semaphore.c
index ee9098855ef..3f5e9534d55 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -50,12 +50,8 @@ static const struct object_ops semaphore_ops =
     remove_queue,                  /* remove_queue */
     semaphore_signaled,            /* signaled */
     semaphore_satisfied,           /* satisfied */
-    NULL,                          /* get_poll_events */
-    NULL,                          /* poll_event */
     no_get_fd,                     /* get_fd */
-    no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
-    NULL,                          /* queue_async */
     no_destroy                     /* destroy */
 };
 
diff --git a/server/serial.c b/server/serial.c
index 22c336f977e..0e4d79f4ff5 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -39,13 +39,13 @@
 #include "winerror.h"
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
 #include "async.h"
 
 static void serial_dump( struct object *obj, int verbose );
-static int serial_get_fd( struct object *obj );
 static int serial_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static int serial_get_poll_events( struct object *obj );
 static void serial_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count);
@@ -82,17 +82,22 @@ static const struct object_ops serial_ops =
 {
     sizeof(struct serial),        /* size */
     serial_dump,                  /* dump */
-    default_poll_add_queue,       /* add_queue */
-    default_poll_remove_queue,    /* remove_queue */
-    default_poll_signaled,        /* signaled */
+    default_fd_add_queue,         /* add_queue */
+    default_fd_remove_queue,      /* remove_queue */
+    default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    default_get_fd,               /* get_fd */
+    serial_get_info,              /* get_file_info */
+    destroy_serial                /* destroy */
+};
+
+static const struct fd_ops serial_fd_ops =
+{
     serial_get_poll_events,       /* get_poll_events */
     serial_poll_event,            /* poll_event */
-    serial_get_fd,                /* get_fd */
     serial_flush,                 /* flush */
     serial_get_info,              /* get_file_info */
-    serial_queue_async,           /* queue_async */
-    destroy_serial                /* destroy */
+    serial_queue_async            /* queue_async */
 };
 
 static struct serial *create_serial( const char *nameptr, size_t len, unsigned int access, int attributes )
@@ -137,7 +142,7 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i
        if(0>fcntl(fd, F_SETFL, 0))
            perror("fcntl");
 
-    if ((serial = alloc_object( &serial_ops, fd )))
+    if ((serial = alloc_fd_object( &serial_ops, &serial_fd_ops, fd )))
     {
         serial->attrib       = attributes;
         serial->access       = access;
@@ -194,13 +199,6 @@ static int serial_get_poll_events( struct object *obj )
     return events;
 }
 
-static int serial_get_fd( struct object *obj )
-{
-    struct serial *serial = (struct serial *)obj;
-    assert( obj->ops == &serial_ops );
-    return serial->obj.fd;
-}
-
 static int serial_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
 {
     struct serial *serial = (struct serial *) obj;
@@ -245,7 +243,7 @@ static void serial_poll_event(struct object *obj, int event)
     if(IS_READY(serial->wait_q) && (POLLIN & event) )
         async_notify(serial->wait_q.head,STATUS_ALERTED);
 
-    set_select_events(obj,obj->ops->get_poll_events(obj));
+    set_select_events( obj, serial_get_poll_events(obj) );
 }
 
 static void serial_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count)
@@ -295,7 +293,7 @@ static void serial_queue_async(struct object *obj, void *ptr, unsigned int statu
         }
 
         /* Check if the new pending request can be served immediately */
-        pfd.fd = obj->fd;
+        pfd.fd = get_unix_fd( obj );
         pfd.events = serial_get_poll_events ( obj );
         pfd.revents = 0;
         poll ( &pfd, 1, 0 );
@@ -315,16 +313,11 @@ static void serial_queue_async(struct object *obj, void *ptr, unsigned int statu
 
 static int serial_flush( struct object *obj )
 {
-    int ret;
-    struct serial *serial = (struct serial *)grab_object(obj);
-    assert( obj->ops == &serial_ops );
-
     /* MSDN says: If hFile is a handle to a communications device,
      * the function only flushes the transmit buffer.
      */
-    ret = (tcflush( serial->obj.fd, TCOFLUSH ) != -1);
+    int ret = (tcflush( get_unix_fd(obj), TCOFLUSH ) != -1);
     if (!ret) file_set_error();
-    release_object( serial );
     return ret;
 }
 
diff --git a/server/smb.c b/server/smb.c
index e9247746cd4..ab00685f235 100644
--- a/server/smb.c
+++ b/server/smb.c
@@ -40,12 +40,12 @@
 #include "winerror.h"
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
 
 static void smb_dump( struct object *obj, int verbose );
-static int smb_get_fd( struct object *obj );
 static int smb_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static int smb_get_poll_events( struct object *obj );
 static void destroy_smb(struct object *obj);
@@ -64,17 +64,22 @@ static const struct object_ops smb_ops =
 {
     sizeof(struct smb),        /* size */
     smb_dump,                  /* dump */
-    default_poll_add_queue,    /* add_queue */
-    default_poll_remove_queue, /* remove_queue */
-    default_poll_signaled,     /* signaled */
+    default_fd_add_queue,      /* add_queue */
+    default_fd_remove_queue,   /* remove_queue */
+    default_fd_signaled,       /* signaled */
     no_satisfied,              /* satisfied */
+    default_get_fd,            /* get_fd */
+    smb_get_info,              /* get_file_info */
+    destroy_smb                /* destroy */
+};
+
+static const struct fd_ops smb_fd_ops =
+{
     smb_get_poll_events,       /* get_poll_events */
     default_poll_event,        /* poll_event */
-    smb_get_fd,                /* get_fd */
     no_flush,                  /* flush */
     smb_get_info,              /* get_file_info */
-    NULL,                      /* queue_async */
-    destroy_smb                /* destroy */
+    no_queue_async             /* queue_async */
 };
 
 static void destroy_smb( struct object *obj)
@@ -108,13 +113,6 @@ static int smb_get_poll_events( struct object *obj )
     return events;
 }
 
-static int smb_get_fd( struct object *obj )
-{
-    struct smb *smb = (struct smb *)obj;
-    assert( obj->ops == &smb_ops );
-    return smb->obj.fd;
-}
-
 static int smb_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
 {
     /* struct smb *smb = (struct smb *) obj; */
@@ -154,7 +152,7 @@ DECL_HANDLER(create_smb)
         return;
     }
 
-    smb = alloc_object( &smb_ops, fd );
+    smb = alloc_fd_object( &smb_ops, &smb_fd_ops, fd );
     if (smb)
     {
         smb->tree_id = req->tree_id;
diff --git a/server/snapshot.c b/server/snapshot.c
index 0df1ac42106..90a8bf4ed0b 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -61,12 +61,8 @@ static const struct object_ops snapshot_ops =
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
-    NULL,                         /* get_poll_events */
-    NULL,                         /* poll_event */
     no_get_fd,                    /* get_fd */
-    no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
-    NULL,                         /* queue_async */
     snapshot_destroy              /* destroy */
 };
 
diff --git a/server/sock.c b/server/sock.c
index 05324b9ef17..d528ab5ebdc 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -44,9 +44,10 @@
 #include <time.h>
 #include <unistd.h>
 
-#include "winerror.h"
 #include "winbase.h"
+
 #include "process.h"
+#include "file.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
@@ -83,7 +84,6 @@ static void sock_dump( struct object *obj, int verbose );
 static int sock_signaled( struct object *obj, struct thread *thread );
 static int sock_get_poll_events( struct object *obj );
 static void sock_poll_event( struct object *obj, int event );
-static int sock_get_fd( struct object *obj );
 static int sock_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static void sock_destroy( struct object *obj );
 static int sock_get_error( int err );
@@ -98,13 +98,18 @@ static const struct object_ops sock_ops =
     remove_queue,                 /* remove_queue */
     sock_signaled,                /* signaled */
     no_satisfied,                 /* satisfied */
+    default_get_fd,               /* get_fd */
+    sock_get_info,                /* get_file_info */
+    sock_destroy                  /* destroy */
+};
+
+static const struct fd_ops sock_fd_ops =
+{
     sock_get_poll_events,         /* get_poll_events */
     sock_poll_event,              /* poll_event */
-    sock_get_fd,                  /* get_fd */
     no_flush,                     /* flush */
     sock_get_info,                /* get_file_info */
-    sock_queue_async,             /* queue_async */
-    sock_destroy                  /* destroy */
+    sock_queue_async              /* queue_async */
 };
 
 
@@ -438,7 +443,7 @@ static int sock_signaled( struct object *obj, struct thread *thread )
     struct sock *sock = (struct sock *)obj;
     assert( obj->ops == &sock_ops );
 
-    return check_select_events( sock->obj.fd, sock_get_poll_events( &sock->obj ) );
+    return check_select_events( get_unix_fd(obj), sock_get_poll_events( &sock->obj ) );
 }
 
 static int sock_get_poll_events( struct object *obj )
@@ -467,13 +472,6 @@ static int sock_get_poll_events( struct object *obj )
     return ev;
 }
 
-static int sock_get_fd( struct object *obj )
-{
-    struct sock *sock = (struct sock *)obj;
-    assert( obj->ops == &sock_ops );
-    return sock->obj.fd;
-}
-
 static int sock_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
 {
     struct sock *sock = (struct sock*) obj;
@@ -592,8 +590,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
         return NULL;
     }
     fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
-    if (!(sock = alloc_object( &sock_ops, -1 ))) return NULL;
-    sock->obj.fd = sockfd;
+    if (!(sock = alloc_fd_object( &sock_ops, &sock_fd_ops, -1 ))) return NULL;
+    set_unix_fd( &sock->obj, sockfd );
     sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0;
     sock->mask    = 0;
     sock->hmask   = 0;
@@ -640,13 +638,13 @@ static struct sock *accept_socket( obj_handle_t handle )
          * return.
          */
         slen = sizeof(saddr);
-        acceptfd = accept(sock->obj.fd,&saddr,&slen);
+        acceptfd = accept( get_unix_fd(&sock->obj), &saddr, &slen);
         if (acceptfd==-1) {
             sock_set_error();
             release_object( sock );
             return NULL;
         }
-        if (!(acceptsock = alloc_object( &sock_ops, -1 )))
+        if (!(acceptsock = alloc_fd_object( &sock_ops, &sock_fd_ops, acceptfd )))
         {
             release_object( sock );
             return NULL;
@@ -654,7 +652,6 @@ static struct sock *accept_socket( obj_handle_t handle )
 
         /* newly created socket gets the same properties of the listening socket */
         fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
-        acceptsock->obj.fd = acceptfd;
         acceptsock->state  = FD_WINE_CONNECTED|FD_READ|FD_WRITE;
         if (sock->state & FD_WINE_NONBLOCKING)
             acceptsock->state |= FD_WINE_NONBLOCKING;
diff --git a/server/thread.c b/server/thread.c
index f8396e09436..dceeef4e679 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -35,6 +35,7 @@
 
 #include "winbase.h"
 
+#include "file.h"
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
@@ -86,13 +87,18 @@ static const struct object_ops thread_ops =
     remove_queue,               /* remove_queue */
     thread_signaled,            /* signaled */
     no_satisfied,               /* satisfied */
+    no_get_fd,                  /* get_fd */
+    no_get_file_info,           /* get_file_info */
+    destroy_thread              /* destroy */
+};
+
+static const struct fd_ops thread_fd_ops =
+{
     NULL,                       /* get_poll_events */
     thread_poll_event,          /* poll_event */
-    no_get_fd,                  /* get_fd */
     no_flush,                   /* flush */
     no_get_file_info,           /* get_file_info */
-    NULL,                       /* queue_async */
-    destroy_thread              /* destroy */
+    no_queue_async              /* queue_async */
 };
 
 static struct thread *first_thread;
@@ -144,7 +150,7 @@ struct thread *create_thread( int fd, struct process *process )
 {
     struct thread *thread;
 
-    if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
+    if (!(thread = alloc_fd_object( &thread_ops, &thread_fd_ops, fd ))) return NULL;
 
     init_thread_structure( thread );
 
diff --git a/server/timer.c b/server/timer.c
index ddc137d4fc2..2d48fc6be65 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -57,12 +57,8 @@ static const struct object_ops timer_ops =
     remove_queue,              /* remove_queue */
     timer_signaled,            /* signaled */
     timer_satisfied,           /* satisfied */
-    NULL,                      /* get_poll_events */
-    NULL,                      /* poll_event */
     no_get_fd,                 /* get_fd */
-    no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
-    NULL,                      /* queue_async */
     timer_destroy              /* destroy */
 };
 
-- 
GitLab