>From 8eb230b505ddd986b689caf96510fbe016d721a7 Mon Sep 17 00:00:00 2001
From: Adam Martinson <adam.r.martinson@gmail.com>
Date: Thu, 20 Dec 2012 19:55:13 -0600
Subject: [PATCH 3/9] server: Use the same object type for both ends of a named pipe.

Makes either end of a named pipe is readable after the other has been closed.
(If the pipe has not been disconnected)
---
 server/named_pipe.c |  399 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 249 insertions(+), 150 deletions(-)

diff --git a/server/named_pipe.c b/server/named_pipe.c
index 7c0f7ba..3ee4ff6 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1998 Alexandre Julliard
  * Copyright (C) 2001 Mike McCormack
+ * Copyright (C) 2012 Adam Martinson
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -63,20 +64,22 @@ enum pipe_state
     ps_wait_connect
 };
 
+enum pipe_instance_end
+{
+    pipe_server = 0,
+    pipe_client = 1
+};
+
 struct named_pipe;
 
 struct pipe_instance
 {
     struct object        obj;        /* object header */
-    struct fd           *fd;         /* pipe file descriptor */
     struct fd           *ioctl_fd;   /* file descriptor for ioctls when not connected */
     struct list          entry;      /* entry in named pipe instances list */
     enum pipe_state      state;      /* instance state */
-    struct pipe_end     *client;     /* client that this server is connected to */
     struct named_pipe   *pipe;
-    struct timeout_user *flush_poll;
-    struct event        *event;
-    unsigned int         options;    /* pipe options */
+    struct pipe_end     *ends[2];    /* ends that this instance connects */
 };
 
 struct pipe_end
@@ -84,13 +87,15 @@ struct pipe_end
     struct object            obj;        /* object header */
     struct fd               *fd;         /* pipe file descriptor */
     struct pipe_instance    *inst;       /* instance that this end is connected to */
+    unsigned int             options;    /* pipe options */
     unsigned int             flags;      /* pipe flags */
+    struct timeout_user     *flush_poll;
+    struct event            *event_empty;
 };
 
 struct named_pipe
 {
     struct object       obj;         /* object header */
-    unsigned int        flags;
     unsigned int        sharing;
     unsigned int        maxinstances;
     unsigned int        outsize;
@@ -138,7 +143,6 @@ static const struct object_ops named_pipe_ops =
 static void pipe_instance_dump( struct object *obj, int verbose );
 static struct fd *pipe_instance_get_fd( struct object *obj );
 static void pipe_instance_destroy( struct object *obj);
-static void pipe_instance_flush( struct fd *fd, struct event **event );
 static enum server_fd_type pipe_instance_get_fd_type( struct fd *fd );
 static obj_handle_t pipe_instance_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
                                        int blocking, const void *data, data_size_t size );
@@ -167,7 +171,7 @@ static const struct fd_ops pipe_instance_fd_ops =
 {
     default_fd_get_poll_events,   /* get_poll_events */
     default_poll_event,           /* poll_event */
-    pipe_instance_flush,          /* flush */
+    no_flush,                     /* flush */
     pipe_instance_get_fd_type,    /* get_fd_type */
     pipe_instance_ioctl,          /* ioctl */
     default_fd_queue_async,       /* queue_async */
@@ -182,6 +186,8 @@ static struct fd *pipe_end_get_fd( struct object *obj );
 static void pipe_end_destroy( struct object *obj );
 static void pipe_end_flush( struct fd *fd, struct event **event );
 static enum server_fd_type pipe_end_get_fd_type( struct fd *fd );
+static obj_handle_t pipe_end_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+                                       int blocking, const void *data, data_size_t size );
 
 static const struct object_ops pipe_end_ops =
 {
@@ -209,7 +215,7 @@ static const struct fd_ops pipe_end_fd_ops =
     default_poll_event,           /* poll_event */
     pipe_end_flush,               /* flush */
     pipe_end_get_fd_type,         /* get_fd_type */
-    default_fd_ioctl,             /* ioctl */
+    pipe_end_ioctl,               /* ioctl */
     default_fd_queue_async,       /* queue_async */
     default_fd_reselect_async,    /* reselect_async */
     default_fd_cancel_async       /* cancel_async */
@@ -259,6 +265,14 @@ static const struct fd_ops named_pipe_device_fd_ops =
     default_fd_cancel_async           /* cancel_async */
 };
 
+static inline int is_server_end( struct pipe_end *end )
+{
+    int res = (end->flags & NAMED_PIPE_SERVER_END)? 1 : 0;
+    if (end->inst)
+        assert( end->inst->ends[!res] == end );
+    return res;
+}
+
 static void named_pipe_dump( struct object *obj, int verbose )
 {
     struct named_pipe *pipe = (struct named_pipe *) obj;
@@ -312,6 +326,8 @@ static struct fd *pipe_end_get_fd( struct object *obj )
     struct pipe_end *end = (struct pipe_end *) obj;
     if (end->fd)
         return (struct fd *) grab_object( end->fd );
+    else if ((end->flags & NAMED_PIPE_SERVER_END) && end->inst)
+        return (struct fd *) grab_object( end->inst->ioctl_fd );
     set_error( STATUS_PIPE_DISCONNECTED );
     return NULL;
 }
@@ -323,17 +339,31 @@ static void set_instance_state( struct pipe_instance *inst, enum pipe_state stat
     switch(state)
     {
     case ps_connected:
-    case ps_disconnected_client:
-        assert( inst->fd );
+        assert( inst->ends[pipe_server] );
+        assert( inst->ends[pipe_server]->fd );
+        assert( inst->ends[pipe_client] );
+        assert( inst->ends[pipe_client]->fd );
         break;
     case ps_wait_open:
     case ps_idle_server:
-        assert( !inst->fd );
+        assert( inst->ends[pipe_server] );
+        assert( !inst->ends[pipe_server]->fd );
+        assert( !inst->ends[pipe_client] );
         set_no_fd_status( inst->ioctl_fd, STATUS_PIPE_LISTENING );
         break;
+    case ps_disconnected_client:
+        assert( !inst->ends[pipe_server] );
+        assert( inst->ends[pipe_client] );
+        break;
     case ps_disconnected_server:
+        assert( inst->ends[pipe_server] );
+        assert( !inst->ends[pipe_client] );
+        set_no_fd_status( inst->ioctl_fd, STATUS_PIPE_DISCONNECTED );
+        break;
     case ps_wait_connect:
-        assert( !inst->fd );
+        assert( inst->ends[pipe_server] );
+        assert( !inst->ends[pipe_server]->fd );
+        assert( !inst->ends[pipe_client] );
         set_no_fd_status( inst->ioctl_fd, STATUS_PIPE_DISCONNECTED );
         break;
     }
@@ -343,37 +373,47 @@ static struct fd *pipe_instance_get_fd( struct object *obj )
 {
     struct pipe_instance *inst = (struct pipe_instance *) obj;
 
-    return (struct fd *)grab_object( inst->fd ? inst->fd : inst->ioctl_fd );
+    return (struct fd *)grab_object( inst->ioctl_fd );
 }
 
 
-static void notify_empty( struct pipe_instance *inst )
+static void notify_empty( struct pipe_end *end )
 {
-    if (!inst->flush_poll)
+    if (!end->flush_poll)
         return;
-    assert( inst->state == ps_connected );
-    assert( inst->event );
-    remove_timeout_user( inst->flush_poll );
-    inst->flush_poll = NULL;
-    set_event( inst->event );
-    release_object( inst->event );
-    inst->event = NULL;
+    assert( end->inst && end->inst->state == ps_connected );
+    assert( end->event_empty );
+    remove_timeout_user( end->flush_poll );
+    end->flush_poll = NULL;
+    set_event( end->event_empty );
+    release_object( end->event_empty );
+    end->event_empty = NULL;
+}
+
+static void do_disconnect_end( struct pipe_instance *inst, enum pipe_instance_end e, int is_shutdown )
+{
+    assert( inst->ends[e]->inst == inst );
+    assert( inst->ends[e]->fd );
+    if (!is_shutdown)
+        shutdown( get_unix_fd( inst->ends[e]->fd ), SHUT_RDWR );
+    release_object( inst->ends[e]->fd );
+    inst->ends[e]->fd = NULL;
 }
 
 static void do_disconnect( struct pipe_instance *inst )
 {
-    /* we may only have a server fd, if the client disconnected */
-    if (inst->client)
+    int is_shutdown = 0;
+    /* we may only have 1 end */
+    if (inst->ends[pipe_server])
     {
-        assert( inst->client->inst == inst );
-        assert( inst->client->fd );
-        release_object( inst->client->fd );
-        inst->client->fd = NULL;
+        do_disconnect_end( inst, pipe_server, 0 );
+        is_shutdown = 1;
+    }
+
+    if (inst->ends[pipe_client])
+    {
+        do_disconnect_end( inst, pipe_client, is_shutdown );
     }
-    assert( inst->fd );
-    shutdown( get_unix_fd( inst->fd ), SHUT_RDWR );
-    release_object( inst->fd );
-    inst->fd = NULL;
 }
 
 static void pipe_instance_destroy( struct object *obj )
@@ -382,18 +422,8 @@ static void pipe_instance_destroy( struct object *obj )
 
     assert( obj->ops == &pipe_instance_ops );
 
-    if (inst->fd)
-    {
-        notify_empty( inst );
-        do_disconnect( inst );
-    }
-
-    if (inst->client)
-    {
-        inst->client->inst = NULL;
-        inst->client = NULL;
-    }
-
+    assert( !inst->ends[pipe_server] );
+    assert( !inst->ends[pipe_client] );
     assert( inst->pipe->numinstances );
     inst->pipe->numinstances--;
 
@@ -408,31 +438,34 @@ static void pipe_end_destroy( struct object *obj )
     struct pipe_instance *inst = end->inst;
 
     assert( obj->ops == &pipe_end_ops );
+    if (end->event_empty)
+        notify_empty( end );
 
     if (inst)
     {
-        notify_empty( inst );
+        assert( inst->ends[!is_server_end( end )] == end );
+        if (!inst->ends[is_server_end( end )])
+            assert( inst->obj.refcount == 1 );
+
+        inst->ends[!is_server_end( end )] = NULL;
 
         switch(inst->state)
         {
         case ps_connected:
-            /* Don't destroy the instances's fd here as we can't
-               do a successful flush without it. */
-            set_instance_state( inst, ps_disconnected_client );
+            if (end->flags & NAMED_PIPE_SERVER_END)
+                set_instance_state( inst, ps_disconnected_client );
+            else
+                set_instance_state( inst, ps_disconnected_server );
             break;
         case ps_disconnected_server:
-            set_instance_state( inst, ps_wait_connect );
-            break;
+        case ps_disconnected_client:
         case ps_idle_server:
         case ps_wait_open:
-        case ps_disconnected_client:
         case ps_wait_connect:
-            assert( 0 );
             break;
         }
-        assert( inst->client );
-        inst->client = NULL;
-        end->inst = NULL;
+
+        release_object( inst );
     }
     if (end->fd) release_object( end->fd );
 }
@@ -508,14 +541,13 @@ void create_named_pipe_device( struct directory *root, const struct unicode_str
     if (dev) make_object_static( &dev->obj );
 }
 
-static int pipe_data_remaining( struct pipe_instance *inst )
+static int pipe_data_remaining( struct pipe_end *end )
 {
     struct pollfd pfd;
     int fd;
 
-    assert( inst->client );
-
-    fd = get_unix_fd( inst->client->fd );
+    assert( end->fd );
+    fd = get_unix_fd( end->fd );
     if (fd < 0)
         return 0;
     pfd.fd = fd;
@@ -530,49 +562,49 @@ static int pipe_data_remaining( struct pipe_instance *inst )
 
 static void check_flushed( void *arg )
 {
-    struct pipe_instance *inst = (struct pipe_instance*) arg;
+    struct pipe_end *end = (struct pipe_end*) arg;
 
-    assert( inst->event );
-    if (pipe_data_remaining( inst ))
+    assert( end->event_empty );
+    if (pipe_data_remaining( end ))
     {
-        inst->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, inst );
+        end->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, end );
     }
     else
     {
-        /* notify_empty( server ); */
-        inst->flush_poll = NULL;
-        set_event( inst->event );
-        release_object( inst->event );
-        inst->event = NULL;
+        notify_empty( end );
+        end->flush_poll = NULL;
+        set_event( end->event_empty );
+        release_object( end->event_empty );
+        end->event_empty = NULL;
     }
 }
 
-static void pipe_instance_flush( struct fd *fd, struct event **event )
+static void pipe_end_flush( struct fd *fd, struct event **event )
 {
-    struct pipe_instance *inst = get_fd_user( fd );
+    struct pipe_end *other_end, *end = get_fd_user( fd );
 
-    if (!inst || inst->state != ps_connected) return;
+    if (!end) return;
+    assert( end->inst );
+    if (end->inst->state != ps_connected) return;
+
+    other_end = end->inst->ends[is_server_end( end )];
+    assert( other_end );
 
     /* FIXME: if multiple threads flush the same pipe,
               maybe should create a list of processes to notify */
-    if (inst->flush_poll) return;
+    if (other_end->flush_poll) return;
 
-    if (pipe_data_remaining( inst ))
+    if (pipe_data_remaining( other_end ))
     {
         /* this kind of sux -
            there's no unix way to be alerted when a pipe becomes empty */
-        inst->event = create_event( NULL, NULL, 0, 0, 0, NULL );
-        if (!inst->event) return;
-        inst->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, inst );
-        *event = inst->event;
+        other_end->event_empty = create_event( NULL, NULL, 0, 0, 0, NULL );
+        if (!other_end->event_empty) return;
+        other_end->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, other_end );
+        *event = other_end->event_empty;
     }
 }
 
-static void pipe_end_flush( struct fd *fd, struct event **event )
-{
-    /* FIXME: what do we have to do for this? */
-}
-
 static inline int is_overlapped( unsigned int options )
 {
     return !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
@@ -615,6 +647,7 @@ static obj_handle_t pipe_instance_ioctl( struct fd *fd, ioctl_code_t code, const
         {
         case ps_idle_server:
         case ps_wait_connect:
+        case ps_disconnected_server:
             if (blocking)
             {
                 async_data_t new_data = *async_data;
@@ -630,6 +663,7 @@ static obj_handle_t pipe_instance_ioctl( struct fd *fd, ioctl_code_t code, const
 
             if (async)
             {
+                assert( inst->pipe );
                 set_instance_state( inst, ps_wait_open );
                 if (inst->pipe->waiters) async_wake_up( inst->pipe->waiters, STATUS_SUCCESS );
                 release_object( async );
@@ -638,10 +672,7 @@ static obj_handle_t pipe_instance_ioctl( struct fd *fd, ioctl_code_t code, const
             }
             break;
         case ps_connected:
-            set_error( STATUS_PIPE_CONNECTED );
-            break;
-        case ps_disconnected_server:
-            set_error( STATUS_PIPE_BUSY );
+            assert( 0 );
             break;
         case ps_disconnected_client:
             set_error( STATUS_NO_DATA_DETECTED );
@@ -656,32 +687,86 @@ static obj_handle_t pipe_instance_ioctl( struct fd *fd, ioctl_code_t code, const
         switch(inst->state)
         {
         case ps_connected:
-            assert( inst->client );
-            assert( inst->client->fd );
+            assert( 0 );
+            break;
+        case ps_idle_server:
+        case ps_wait_open:
+            set_error( STATUS_PIPE_LISTENING );
+            break;
+        case ps_wait_connect:
+        case ps_disconnected_server:
+        case ps_disconnected_client:
+            set_error( STATUS_PIPE_DISCONNECTED );
+            break;
+        }
+        return 0;
 
-            notify_empty( inst );
+    default:
+        return default_fd_ioctl( fd, code, async_data, blocking, data, size );
+    }
+}
+
+static obj_handle_t pipe_end_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
+                                       int blocking, const void *data, data_size_t size )
+{
+    struct pipe_end *end = get_fd_user( fd );
 
-            /* dump the client and server fds, but keep the pointers
-               around - client loses all waiting data */
-            do_disconnect( inst );
-            set_instance_state( inst, ps_disconnected_server );
+    assert( end->inst );
+
+    switch(code)
+    {
+    case FSCTL_PIPE_DISCONNECT:
+        switch(end->inst->state)
+        {
+        case ps_connected:
+            assert( end->inst->ends[pipe_server] );
+            assert( end->inst->ends[pipe_server]->fd );
+            assert( end->inst->ends[pipe_client] );
+            assert( end->inst->ends[pipe_client]->fd );
+
+            notify_empty( end->inst->ends[pipe_server] );
+            notify_empty( end->inst->ends[pipe_client] );
+
+            /* all waiting data lost */
+            do_disconnect( end->inst );
+            if (is_server_end( end ))
+            {
+                end->inst->ends[pipe_client]->inst = NULL;
+                end->inst->ends[pipe_client] = NULL;
+                set_instance_state( end->inst, ps_disconnected_server );
+                release_object( end->inst );
+            }
+            else
+            {
+                /* FIXME: is this allowed?? */
+                struct pipe_instance *inst = end->inst;
+                end->inst->ends[pipe_client] = NULL;
+                end->inst = NULL;
+                set_instance_state( inst, ps_disconnected_server );
+                release_object( inst );
+            }
+            break;
+        case ps_disconnected_server:
+            assert( !end->inst->ends[pipe_client] );
+            do_disconnect( end->inst );
             break;
         case ps_disconnected_client:
-            assert( !inst->client );
-            do_disconnect( inst );
-            set_instance_state( inst, ps_wait_connect );
+            /* FIXME: is this allowed?? */
+            assert( !end->inst->ends[pipe_server] );
+            do_disconnect( end->inst );
             break;
         case ps_idle_server:
         case ps_wait_open:
-            set_error( STATUS_PIPE_LISTENING );
-            break;
-        case ps_disconnected_server:
         case ps_wait_connect:
-            set_error( STATUS_PIPE_DISCONNECTED );
+            assert( 0 );
             break;
         }
         return 0;
 
+    case FSCTL_PIPE_LISTEN:
+        set_error( STATUS_PIPE_CONNECTED );
+        return 0;
+
     default:
         return default_fd_ioctl( fd, code, async_data, blocking, data, size );
     }
@@ -730,15 +815,20 @@ static struct named_pipe *create_named_pipe( struct directory *root, const struc
     return pipe;
 }
 
-static struct pipe_instance *get_pipe_instance_obj( struct process *process,
+static struct pipe_end *get_pipe_end_obj( struct process *process,
                                 obj_handle_t handle, unsigned int access )
 {
-    struct object *obj;
-    obj = get_handle_obj( process, handle, access, &pipe_instance_ops );
-    return (struct pipe_instance *) obj;
+    struct pipe_end *end;
+    end = (struct pipe_end *)get_handle_obj( process, handle, 0, &pipe_end_ops );
+    if (end && is_server_end( end ))
+    {
+        release_object( end );
+        end = (struct pipe_end *)get_handle_obj( process, handle, access, &pipe_end_ops );
+    }
+    return end;
 }
 
-static struct pipe_end *create_pipe_end( unsigned int flags )
+static struct pipe_end *create_pipe_end( struct pipe_instance *inst, unsigned int options, unsigned int flags )
 {
     struct pipe_end *end;
 
@@ -747,13 +837,23 @@ static struct pipe_end *create_pipe_end( unsigned int flags )
         return NULL;
 
     end->fd = NULL;
-    end->inst = NULL;
+    end->inst = inst;
+    end->options = options;
+    end->flush_poll = NULL;
+    end->event_empty = NULL;
     end->flags = flags;
 
+    if (flags & NAMED_PIPE_SERVER_END)
+        inst->ends[pipe_server] = end;
+    else
+        inst->ends[pipe_client] = end;
+
+    grab_object( inst );
+
     return end;
 }
 
-static struct pipe_instance *create_pipe_instance( struct named_pipe *pipe, unsigned int options )
+static struct pipe_instance *create_pipe_instance( struct named_pipe *pipe, unsigned int options, unsigned int flags )
 {
     struct pipe_instance *inst;
 
@@ -761,11 +861,15 @@ static struct pipe_instance *create_pipe_instance( struct named_pipe *pipe, unsi
     if (!inst)
         return NULL;
 
-    inst->fd = NULL;
     inst->pipe = pipe;
-    inst->client = NULL;
-    inst->flush_poll = NULL;
-    inst->options = options;
+
+    inst->ends[pipe_client] = NULL;
+    inst->ends[pipe_server] = create_pipe_end( inst, options, flags | NAMED_PIPE_SERVER_END );
+    if (!inst->ends[pipe_server])
+    {
+        release_object( inst );
+        return NULL;
+    }
 
     list_add_head( &pipe->instances, &inst->entry );
     grab_object( pipe );
@@ -814,6 +918,10 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc
         return NULL;
     }
 
+    assert( inst->ends[pipe_server] );
+    assert( !inst->ends[pipe_server]->fd );
+    assert( !inst->ends[pipe_client] );
+
     pipe_sharing = inst->pipe->sharing;
     if (((access & GENERIC_READ) && !(pipe_sharing & FILE_SHARE_READ)) ||
         ((access & GENERIC_WRITE) && !(pipe_sharing & FILE_SHARE_WRITE)))
@@ -823,17 +931,17 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc
         return NULL;
     }
 
-    if ((client = create_pipe_end( options )))
+    if ((client = create_pipe_end( inst, options, inst->ends[pipe_server]->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE )))
     {
         if (!socketpair( PF_UNIX, SOCK_STREAM, 0, fds ))
         {
-            assert( !inst->fd );
+            assert( !inst->ends[pipe_server]->fd );
 
             /* for performance reasons, only set nonblocking mode when using
              * overlapped I/O. Otherwise, we will be doing too much busy
              * looping */
             if (is_overlapped( options )) fcntl( fds[1], F_SETFL, O_NONBLOCK );
-            if (is_overlapped( inst->options )) fcntl( fds[0], F_SETFL, O_NONBLOCK );
+            if (is_overlapped( inst->ends[pipe_server]->options )) fcntl( fds[0], F_SETFL, O_NONBLOCK );
 
             if (pipe->insize)
             {
@@ -847,17 +955,18 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc
             }
 
             client->fd = create_anonymous_fd( &pipe_end_fd_ops, fds[1], &client->obj, options );
-            inst->fd = create_anonymous_fd( &pipe_instance_fd_ops, fds[0], &inst->obj, inst->options );
-            if (client->fd && inst->fd)
+            inst->ends[pipe_server]->fd = create_anonymous_fd( &pipe_end_fd_ops, fds[0],
+                                                              &inst->ends[pipe_server]->obj,
+                                                              inst->ends[pipe_server]->options );
+
+            if (client->fd && inst->ends[pipe_server]->fd)
             {
                 allow_fd_caching( client->fd );
-                allow_fd_caching( inst->fd );
-                fd_copy_completion( inst->ioctl_fd, inst->fd );
+                allow_fd_caching( inst->ends[pipe_server]->fd );
+                fd_copy_completion( inst->ioctl_fd, inst->ends[pipe_server]->fd );
                 if (inst->state == ps_wait_open)
                     fd_async_wake_up( inst->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS );
                 set_instance_state( inst, ps_connected );
-                inst->client = client;
-                client->inst = inst;
             }
             else
             {
@@ -978,7 +1087,6 @@ DECL_HANDLER(create_named_pipe)
         pipe->outsize = req->outsize;
         pipe->maxinstances = req->maxinstances;
         pipe->timeout = req->timeout;
-        pipe->flags = req->flags;
         pipe->sharing = req->sharing;
     }
     else
@@ -998,10 +1106,11 @@ DECL_HANDLER(create_named_pipe)
         clear_error(); /* clear the name collision */
     }
 
-    inst = create_pipe_instance( pipe, req->options );
+    inst = create_pipe_instance( pipe, req->options, req->flags  );
     if (inst)
     {
-        reply->handle = alloc_handle( current->process, inst, req->access, req->attributes );
+        reply->handle = alloc_handle( current->process, inst->ends[pipe_server], req->access, req->attributes );
+        release_object( inst->ends[pipe_server] );
         inst->pipe->numinstances++;
         release_object( inst );
     }
@@ -1011,34 +1120,24 @@ DECL_HANDLER(create_named_pipe)
 
 DECL_HANDLER(get_named_pipe_info)
 {
-    struct pipe_instance *inst;
-    struct pipe_end *client = NULL;
+    struct pipe_end *end;
 
-    inst = get_pipe_instance_obj( current->process, req->handle, FILE_READ_ATTRIBUTES );
-    if (!inst)
+    if ((end = get_pipe_end_obj( current->process, req->handle, FILE_READ_ATTRIBUTES )))
     {
-        if (get_error() != STATUS_OBJECT_TYPE_MISMATCH)
+        if (!end->inst)
+        {
+            set_error( STATUS_PIPE_DISCONNECTED );
+            release_object( end );
             return;
-
-        clear_error();
-        client = (struct pipe_end *)get_handle_obj( current->process, req->handle,
-                                                       0, &pipe_end_ops );
-        if (!client) return;
-        inst = client->inst;
-    }
-
-    reply->flags        = inst->pipe->flags;
-    reply->sharing      = inst->pipe->sharing;
-    reply->maxinstances = inst->pipe->maxinstances;
-    reply->instances    = inst->pipe->numinstances;
-    reply->insize       = inst->pipe->insize;
-    reply->outsize      = inst->pipe->outsize;
-
-    if (client)
-        release_object(client);
-    else
-    {
-        reply->flags |= NAMED_PIPE_SERVER_END;
-        release_object( inst );
+        }
+        assert( end->inst->pipe );
+        reply->flags        = end->flags;
+        reply->sharing      = end->inst->pipe->sharing;
+        reply->maxinstances = end->inst->pipe->maxinstances;
+        reply->instances    = end->inst->pipe->numinstances;
+        reply->insize       = end->inst->pipe->insize;
+        reply->outsize      = end->inst->pipe->outsize;
+
+        release_object( end );
     }
 }
-- 
1.7.1

