Revert 18883 and 18912, as they break named pipes
[reactos.git] / reactos / drivers / fs / np / create.c
index 5b505f4..773abf7 100644 (file)
-/* $Id: create.c,v 1.12 2002/05/07 22:40:35 hbirr Exp $
- *
+/*
  * COPYRIGHT:  See COPYING in the top level directory
  * PROJECT:    ReactOS kernel
- * FILE:       services/fs/np/create.c
+ * FILE:       drivers/fs/np/create.c
  * PURPOSE:    Named pipe filesystem
  * PROGRAMMER: David Welch <welch@cwcom.net>
  */
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
+#define NDEBUG
+#include <debug.h>
 
 #include "npfs.h"
 
-#define NDEBUG
-#include <debug.h>
+/* FUNCTIONS *****************************************************************/
 
+static PNPFS_PIPE
+NpfsFindPipe(PNPFS_DEVICE_EXTENSION DeviceExt,
+            PUNICODE_STRING PipeName)
+{
+  PLIST_ENTRY CurrentEntry;
+  PNPFS_PIPE Pipe;
 
-/* GLOBALS *******************************************************************/
+  CurrentEntry = DeviceExt->PipeListHead.Flink;
+  while (CurrentEntry != &DeviceExt->PipeListHead)
+    {
+      Pipe = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE, PipeListEntry);
+      if (RtlCompareUnicodeString(PipeName,
+                                 &Pipe->PipeName,
+                                 TRUE) == 0)
+       {
+         DPRINT("<%wZ> = <%wZ>\n", PipeName, &Pipe->PipeName);
+         return Pipe;
+       }
+
+       CurrentEntry = CurrentEntry->Flink;
+     }
 
+  return NULL;
+}
+
+
+static PNPFS_FCB
+NpfsFindListeningServerInstance(PNPFS_PIPE Pipe)
+{
+  PLIST_ENTRY CurrentEntry;
+  PNPFS_WAITER_ENTRY Waiter;
+  KIRQL oldIrql;
+  PIRP Irp;
+
+  CurrentEntry = Pipe->WaiterListHead.Flink;
+  while (CurrentEntry != &Pipe->WaiterListHead)
+    {
+      Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
+      Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
+      if (Waiter->Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
+       {
+         DPRINT("Server found! Fcb %p\n", Waiter->Fcb);
+
+         IoAcquireCancelSpinLock(&oldIrql);
+          if (!Irp->Cancel)
+           {
+             IoSetCancelRoutine(Irp, NULL);
+              IoReleaseCancelSpinLock(oldIrql);
+              return Waiter->Fcb;
+            }
+          IoReleaseCancelSpinLock(oldIrql);
+       }
+
+      CurrentEntry = CurrentEntry->Flink;
+    }
+
+  return NULL;
+}
+
+
+static VOID
+NpfsSignalAndRemoveListeningServerInstance(PNPFS_PIPE Pipe,
+                                          PNPFS_FCB Fcb)
+{
+  PLIST_ENTRY CurrentEntry;
+  PNPFS_WAITER_ENTRY Waiter;
+  PIRP Irp;
+
+  CurrentEntry = Pipe->WaiterListHead.Flink;
+  while (CurrentEntry != &Pipe->WaiterListHead)
+    {
+      Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
+      if (Waiter->Fcb == Fcb)
+       {
+         DPRINT("Server found! Fcb %p\n", Waiter->Fcb);
+
+         RemoveEntryList(&Waiter->Entry);
+         Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
+         Irp->IoStatus.Status = STATUS_SUCCESS;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+         break;
+       }
+      CurrentEntry = CurrentEntry->Flink;
+    }
+}
 
-/* FUNCTIONS *****************************************************************/
 
 NTSTATUS STDCALL
 NpfsCreate(PDEVICE_OBJECT DeviceObject,
           PIRP Irp)
 {
-   PIO_STACK_LOCATION IoStack;
-   PFILE_OBJECT FileObject;
-   PNPFS_PIPE Pipe;
-   PNPFS_FCB ClientFcb;
-   PNPFS_FCB ServerFcb;
-   PNPFS_PIPE current;
-   PLIST_ENTRY current_entry;
-   PNPFS_DEVICE_EXTENSION DeviceExt;
-   KIRQL oldIrql;
-   ULONG Disposition;
-   
-   DPRINT1("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
-   
-   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-   IoStack = IoGetCurrentIrpStackLocation(Irp);
-   FileObject = IoStack->FileObject;
-   Disposition = ((IoStack->Parameters.Create.Options >> 24) & 0xff);
-   DPRINT("FileObject %p\n", FileObject);
-   DPRINT("FileName %wZ\n", &FileObject->FileName);
+  PEXTENDED_IO_STACK_LOCATION IoStack;
+  PFILE_OBJECT FileObject;
+  PNPFS_PIPE Pipe;
+  PNPFS_FCB ClientFcb;
+  PNPFS_FCB ServerFcb = NULL;
+  PNPFS_DEVICE_EXTENSION DeviceExt;
+  BOOLEAN SpecialAccess;
 
-   ClientFcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
-   if (ClientFcb == NULL)
-     {
-       Irp->IoStatus.Status = STATUS_NO_MEMORY;
-       Irp->IoStatus.Information = 0;
-       
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       DPRINT("No memory!\n");
-       
-       return(STATUS_NO_MEMORY);
-     }
-   
-   KeLockMutex(&DeviceExt->PipeListLock);
-   current_entry = DeviceExt->PipeListHead.Flink;
-   while (current_entry != &DeviceExt->PipeListHead)
-     {
-       current = CONTAINING_RECORD(current_entry,
-                                   NPFS_PIPE,
-                                   PipeListEntry);
-       
-       if (RtlCompareUnicodeString(&FileObject->FileName,
-                                   &current->PipeName,
-                                   TRUE) == 0)
-         {
-            break;
-         }
-       
-       current_entry = current_entry->Flink;
-     }
-   
-   if (current_entry == &DeviceExt->PipeListHead)
-     {
-       ExFreePool(ClientFcb);
-       KeUnlockMutex(&DeviceExt->PipeListLock);
-       
-       Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-       Irp->IoStatus.Information = 0;
-       
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       DPRINT("No pipe found!\n");
-       
-       return(STATUS_OBJECT_NAME_NOT_FOUND);
-     }
-   
-   Pipe = current;
-   
-   ClientFcb->Pipe = Pipe;
-   ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
-   ClientFcb->OtherSide = NULL;
-   ClientFcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-   
-   /* initialize data list */
-   InitializeListHead(&ClientFcb->DataListHead);
-   KeInitializeSpinLock(&ClientFcb->DataListLock);
-   
-   KeInitializeEvent(&ClientFcb->ConnectEvent,
-                    SynchronizationEvent,
-                    FALSE);
-   
-   KeInitializeEvent(&ClientFcb->ReadEvent,
-                    SynchronizationEvent,
-                    FALSE);
-   
-   KeAcquireSpinLock(&Pipe->FcbListLock, &oldIrql);
-   InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
-   KeReleaseSpinLock(&Pipe->FcbListLock, oldIrql);
-   
-   Pipe->ReferenceCount++;
-   
-   KeUnlockMutex(&DeviceExt->PipeListLock);
-
-#if 0
-  if (Disposition == OPEN_EXISTING)
+  DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+
+  DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+  IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
+  FileObject = IoStack->FileObject;
+  DPRINT("FileObject %p\n", FileObject);
+  DPRINT("FileName %wZ\n", &FileObject->FileName);
+
+  Irp->IoStatus.Information = 0;
+
+  SpecialAccess = ((IoStack->Parameters.CreatePipe.ShareAccess & 3) == 3);
+  if (SpecialAccess)
     {
-      /* do not connect to listening servers */
-      FileObject->FsContext = ClientFcb;
+      DPRINT("NpfsCreate() open client end for special use!\n");
+    }
 
-      Irp->IoStatus.Status = STATUS_SUCCESS;
-      Irp->IoStatus.Information = 0;
+  /*
+   * Step 1. Find the pipe we're trying to open.
+   */
+  KeLockMutex(&DeviceExt->PipeListLock);
+  Pipe = NpfsFindPipe(DeviceExt,
+                     &FileObject->FileName);
+  if (Pipe == NULL)
+    {
+      /* Not found, bail out with error. */
+      DPRINT("No pipe found!\n");
+      KeUnlockMutex(&DeviceExt->PipeListLock);
+      Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
 
+  KeUnlockMutex(&DeviceExt->PipeListLock);
+
+  /*
+   * Acquire the lock for FCB lists. From now on no modifications to the
+   * FCB lists are allowed, because it can cause various misconsistencies.
+   */
+  KeLockMutex(&Pipe->FcbListLock);
+
+  /*
+   * Step 2. Create the client FCB.
+   */
+  ClientFcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
+  if (ClientFcb == NULL)
+    {
+      DPRINT("No memory!\n");
+      KeUnlockMutex(&Pipe->FcbListLock);
+      Irp->IoStatus.Status = STATUS_NO_MEMORY;
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-      DPRINT("Success!\n");
+      return STATUS_NO_MEMORY;
+    }
 
-      return(STATUS_SUCCESS);
+  ClientFcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
+  ClientFcb->Pipe = Pipe;
+  ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
+  ClientFcb->OtherSide = NULL;
+  ClientFcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
+  InitializeListHead(&ClientFcb->ReadRequestListHead);
+
+  DPRINT("Fcb: %x\n", ClientFcb);
+
+  /* Initialize data list. */
+  if (Pipe->OutboundQuota)
+    {
+      ClientFcb->Data = ExAllocatePool(PagedPool, Pipe->OutboundQuota);
+      if (ClientFcb->Data == NULL)
+        {
+          DPRINT("No memory!\n");
+          ExFreePool(ClientFcb);
+          KeUnlockMutex(&Pipe->FcbListLock);
+          Irp->IoStatus.Status = STATUS_NO_MEMORY;
+          IoCompleteRequest(Irp, IO_NO_INCREMENT);
+          return STATUS_NO_MEMORY;
+        }
+    }
+  else
+    {
+      ClientFcb->Data = NULL;
     }
-#endif
 
-   /* search for disconnected or listening server fcb */
-   current_entry = Pipe->ServerFcbListHead.Flink;
-   while (current_entry != &Pipe->ServerFcbListHead)
-     {
-       ServerFcb = CONTAINING_RECORD(current_entry,
-                                     NPFS_FCB,
-                                     FcbListEntry);
-       if ((ServerFcb->PipeState == FILE_PIPE_LISTENING_STATE)
-           || (ServerFcb->PipeState == FILE_PIPE_DISCONNECTED_STATE))
-         {
-            DPRINT("Server found! Fcb %p\n", ServerFcb);
-            break;
-         }
-       current_entry = current_entry->Flink;
-     }
-   
-   if (current_entry == &Pipe->ServerFcbListHead)
-     {
-       DPRINT("No server fcb found!\n");
+  ClientFcb->ReadPtr = ClientFcb->Data;
+  ClientFcb->WritePtr = ClientFcb->Data;
+  ClientFcb->ReadDataAvailable = 0;
+  ClientFcb->WriteQuotaAvailable = Pipe->OutboundQuota;
+  ClientFcb->MaxDataLength = Pipe->OutboundQuota;
+  ExInitializeFastMutex(&ClientFcb->DataListLock);
+  KeInitializeEvent(&ClientFcb->ConnectEvent, SynchronizationEvent, FALSE);
+  KeInitializeEvent(&ClientFcb->ReadEvent, SynchronizationEvent, FALSE);
+  KeInitializeEvent(&ClientFcb->WriteEvent, SynchronizationEvent, FALSE);
 
-       FileObject->FsContext = ClientFcb;
 
-       Irp->IoStatus.Status = STATUS_SUCCESS;
-       Irp->IoStatus.Information = 0;
+  /*
+   * Step 3. Search for listening server FCB.
+   */
 
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+  if (!SpecialAccess)
+    {
+      /*
+       * WARNING: Point of no return! Once we get the server FCB it's
+       * possible that we completed a wait request and so we have to
+       * complete even this request.
+       */
+
+      ServerFcb = NpfsFindListeningServerInstance(Pipe);
+      if (ServerFcb == NULL)
+        {
+          PLIST_ENTRY CurrentEntry;
+          PNPFS_FCB Fcb;
+
+          /*
+           * If no waiting server FCB was found then try to pick
+           * one of the listing server FCB on the pipe.
+           */
+
+          CurrentEntry = Pipe->ServerFcbListHead.Flink;
+          while (CurrentEntry != &Pipe->ServerFcbListHead)
+            {
+              Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, FcbListEntry);
+              if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
+                {
+                  ServerFcb = Fcb;
+                  break;
+                }
+              CurrentEntry = CurrentEntry->Flink;
+            }
+
+          /*
+           * No one is listening to me?! I'm so lonely... :(
+           */
+
+          if (ServerFcb == NULL)
+            {
+              /* Not found, bail out with error for FILE_OPEN requests. */
+              DPRINT("No listening server fcb found!\n");
+              if (ClientFcb->Data)
+                ExFreePool(ClientFcb->Data);
+              KeUnlockMutex(&Pipe->FcbListLock);
+              Irp->IoStatus.Status = STATUS_PIPE_BUSY;
+              IoCompleteRequest(Irp, IO_NO_INCREMENT);
+              return STATUS_PIPE_BUSY;
+            }
+        }
+      else
+        {
+          /* Signal the server thread and remove it from the waiter list */
+          /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
+          NpfsSignalAndRemoveListeningServerInstance(Pipe, ServerFcb);
+        }
+    }
+  else if (IsListEmpty(&Pipe->ServerFcbListHead))
+    {
+      DPRINT("No server fcb found!\n");
+      KeUnlockMutex(&Pipe->FcbListLock);
+      Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_UNSUCCESSFUL;
+    }
 
-       return(STATUS_SUCCESS);
-     }
-   
-   ClientFcb->OtherSide = ServerFcb;
-   ServerFcb->OtherSide = ClientFcb;
-   ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
-   ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
-   
-   /* FIXME: create data queue(s) */
-   
-   /* wake server thread */
-   KeSetEvent(&ServerFcb->ConnectEvent, 0, FALSE);
-   
-   FileObject->FsContext = ClientFcb;
-   
-   Irp->IoStatus.Status = STATUS_SUCCESS;
-   Irp->IoStatus.Information = 0;
-   
-   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   DPRINT("Success!\n");
-   
-   return(STATUS_SUCCESS);
+  /*
+   * Step 4. Add the client FCB to a list and connect it if possible.
+   */
+
+  /* Add the client FCB to the pipe FCB list. */
+  InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
+
+  /* Connect to listening server side */
+  if (ServerFcb)
+    {
+      ClientFcb->OtherSide = ServerFcb;
+      ServerFcb->OtherSide = ClientFcb;
+      ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
+      ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
+    }
+
+  KeUnlockMutex(&Pipe->FcbListLock);
+
+  FileObject->FsContext = ClientFcb;
+
+  Irp->IoStatus.Status = STATUS_SUCCESS;
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+  DPRINT("Success!\n");
+
+  return STATUS_SUCCESS;
 }
 
 
@@ -189,266 +307,436 @@ NTSTATUS STDCALL
 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
                    PIRP Irp)
 {
-   PIO_STACK_LOCATION IoStack;
+   PEXTENDED_IO_STACK_LOCATION IoStack;
    PFILE_OBJECT FileObject;
    PNPFS_DEVICE_EXTENSION DeviceExt;
    PNPFS_PIPE Pipe;
    PNPFS_FCB Fcb;
-   KIRQL oldIrql;
-   PLIST_ENTRY current_entry;
-   PNPFS_PIPE current;
-   PIO_PIPE_CREATE_BUFFER Buffer;
-   
-   DPRINT1("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
-   
+   PNAMED_PIPE_CREATE_PARAMETERS Buffer;
+   BOOLEAN NewPipe = FALSE;
+
+   DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+
    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-   IoStack = IoGetCurrentIrpStackLocation(Irp);
+   IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
    FileObject = IoStack->FileObject;
    DPRINT("FileObject %p\n", FileObject);
    DPRINT("Pipe name %wZ\n", &FileObject->FileName);
-   
-   Buffer = (PIO_PIPE_CREATE_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
-   
-   Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
-   if (Pipe == NULL)
-     {
-       Irp->IoStatus.Status = STATUS_NO_MEMORY;
-       Irp->IoStatus.Information = 0;
-       
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       
-       return(STATUS_NO_MEMORY);
-     }
-   
+
+   Buffer = IoStack->Parameters.CreatePipe.Parameters;
+
+   Irp->IoStatus.Information = 0;
+
    Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
    if (Fcb == NULL)
      {
-       ExFreePool(Pipe);
-       
        Irp->IoStatus.Status = STATUS_NO_MEMORY;
-       Irp->IoStatus.Information = 0;
-       
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       
-       return(STATUS_NO_MEMORY);
+       return STATUS_NO_MEMORY;
      }
-   
-   if (RtlCreateUnicodeString(&Pipe->PipeName, FileObject->FileName.Buffer) == 0)
-     {
-       ExFreePool(Pipe);
-       ExFreePool(Fcb);
-       
-       Irp->IoStatus.Status = STATUS_NO_MEMORY;
-       Irp->IoStatus.Information = 0;
-       
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-       return(STATUS_NO_MEMORY);
-     }
-   
-   Pipe->ReferenceCount = 0;
-   InitializeListHead(&Pipe->ServerFcbListHead);
-   InitializeListHead(&Pipe->ClientFcbListHead);
-   KeInitializeSpinLock(&Pipe->FcbListLock);
-
-   Pipe->PipeType = Buffer->WriteModeMessage ? FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE;
-   Pipe->PipeWriteMode = Buffer->WriteModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
-   Pipe->PipeReadMode = Buffer->ReadModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
-   Pipe->PipeBlockMode = Buffer->NonBlocking;
-   Pipe->PipeConfiguration = IoStack->Parameters.Create.Options & 0x3;
-   Pipe->MaximumInstances = Buffer->MaxInstances;
-   Pipe->CurrentInstances = 0;
-   Pipe->TimeOut = Buffer->TimeOut;
-   Pipe->InboundQuota = Buffer->InBufferSize;
-   Pipe->OutboundQuota = Buffer->OutBufferSize;
-   
+   Fcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
    KeLockMutex(&DeviceExt->PipeListLock);
-   current_entry = DeviceExt->PipeListHead.Flink;
-   while (current_entry != &DeviceExt->PipeListHead)
+
+   /*
+    * First search for existing Pipe with the same name.
+    */
+   Pipe = NpfsFindPipe(DeviceExt,
+                      &FileObject->FileName);
+   if (Pipe != NULL)
+     {
+       /*
+        * Found Pipe with the same name. Check if we are
+        * allowed to use it.
+        */
+       KeUnlockMutex(&DeviceExt->PipeListLock);
+
+       if (Pipe->CurrentInstances >= Pipe->MaximumInstances)
+         {
+           DPRINT("Out of instances.\n");
+           ExFreePool(Fcb);
+           Irp->IoStatus.Status = STATUS_PIPE_BUSY;
+           IoCompleteRequest(Irp, IO_NO_INCREMENT);
+           return STATUS_PIPE_BUSY;
+         }
+
+       /* FIXME: Check pipe modes also! */
+       if (Pipe->MaximumInstances != Buffer->MaximumInstances ||
+           Pipe->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart)
+         {
+           DPRINT("Asked for invalid pipe mode.\n");
+           ExFreePool(Fcb);
+           Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
+           IoCompleteRequest(Irp, IO_NO_INCREMENT);
+           return STATUS_ACCESS_DENIED;
+         }
+     }
+   else
      {
-       current = CONTAINING_RECORD(current_entry,
-                                   NPFS_PIPE,
-                                   PipeListEntry);
-       
-       if (RtlCompareUnicodeString(&Pipe->PipeName, &current->PipeName, TRUE) == 0)
-         {
-            break;
-         }
-       
-       current_entry = current_entry->Flink;
+       NewPipe = TRUE;
+       Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
+       if (Pipe == NULL)
+         {
+           KeUnlockMutex(&DeviceExt->PipeListLock);
+           Irp->IoStatus.Status = STATUS_NO_MEMORY;
+           Irp->IoStatus.Information = 0;
+           IoCompleteRequest(Irp, IO_NO_INCREMENT);
+           return STATUS_NO_MEMORY;
+         }
+
+       Pipe->PipeName.Length = FileObject->FileName.Length;
+       Pipe->PipeName.MaximumLength = Pipe->PipeName.Length + sizeof(UNICODE_NULL);
+       Pipe->PipeName.Buffer = ExAllocatePool(NonPagedPool, Pipe->PipeName.MaximumLength);
+       if (Pipe->PipeName.Buffer == NULL)
+         {
+           KeUnlockMutex(&DeviceExt->PipeListLock);
+           ExFreePool(Pipe);
+           ExFreePool(Fcb);
+           Irp->IoStatus.Status = STATUS_NO_MEMORY;
+           Irp->IoStatus.Information = 0;
+           IoCompleteRequest(Irp, IO_NO_INCREMENT);
+           return STATUS_NO_MEMORY;
+         }
+
+       RtlCopyUnicodeString(&Pipe->PipeName, &FileObject->FileName);
+
+       InitializeListHead(&Pipe->ServerFcbListHead);
+       InitializeListHead(&Pipe->ClientFcbListHead);
+       InitializeListHead(&Pipe->WaiterListHead);
+       KeInitializeMutex(&Pipe->FcbListLock, 0);
+
+       Pipe->PipeType = Buffer->NamedPipeType;
+       Pipe->WriteMode = Buffer->ReadMode;
+       Pipe->ReadMode = Buffer->ReadMode;
+       Pipe->CompletionMode = Buffer->CompletionMode;
+       Pipe->PipeConfiguration = IoStack->Parameters.CreatePipe.Options & 0x3;
+       Pipe->MaximumInstances = Buffer->MaximumInstances;
+       Pipe->CurrentInstances = 0;
+       Pipe->TimeOut = Buffer->DefaultTimeout;
+       if (!(IoStack->Parameters.CreatePipe.Options & FILE_PIPE_OUTBOUND) ||
+           IoStack->Parameters.CreatePipe.Options & FILE_PIPE_FULL_DUPLEX)
+         {
+           if (Buffer->InboundQuota == 0)
+             {
+               Pipe->InboundQuota = DeviceExt->DefaultQuota;
+             }
+           else
+             {
+               Pipe->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
+               if (Pipe->InboundQuota < DeviceExt->MinQuota)
+                 {
+                   Pipe->InboundQuota = DeviceExt->MinQuota;
+                 }
+               else if (Pipe->InboundQuota > DeviceExt->MaxQuota)
+                 {
+                   Pipe->InboundQuota = DeviceExt->MaxQuota;
+                 }
+             }
+         }
+       else
+         {
+           Pipe->InboundQuota = 0;
+         }
+
+       if (IoStack->Parameters.CreatePipe.Options & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
+         {
+           if (Buffer->OutboundQuota == 0)
+             {
+               Pipe->OutboundQuota = DeviceExt->DefaultQuota;
+             }
+           else
+             {
+               Pipe->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
+               if (Pipe->OutboundQuota < DeviceExt->MinQuota)
+                 {
+                   Pipe->OutboundQuota = DeviceExt->MinQuota;
+                 }
+               else if (Pipe->OutboundQuota > DeviceExt->MaxQuota)
+                 {
+                   Pipe->OutboundQuota = DeviceExt->MaxQuota;
+                 }
+             }
+         }
+       else
+         {
+           Pipe->OutboundQuota = 0;
+         }
+
+       InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
+       KeUnlockMutex(&DeviceExt->PipeListLock);
      }
-   
-   if (current_entry != &DeviceExt->PipeListHead)
+
+   if (Pipe->InboundQuota)
      {
-       RtlFreeUnicodeString(&Pipe->PipeName);
-       ExFreePool(Pipe);
-       
-       Pipe = current;
+       Fcb->Data = ExAllocatePool(PagedPool, Pipe->InboundQuota);
+       if (Fcb->Data == NULL)
+         {
+           ExFreePool(Fcb);
+
+           if (NewPipe)
+             {
+               KeLockMutex(&DeviceExt->PipeListLock);
+              RemoveEntryList(&Pipe->PipeListEntry);
+               KeUnlockMutex(&DeviceExt->PipeListLock);
+               RtlFreeUnicodeString(&Pipe->PipeName);
+               ExFreePool(Pipe);
+             }
+
+           Irp->IoStatus.Status = STATUS_NO_MEMORY;
+           IoCompleteRequest(Irp, IO_NO_INCREMENT);
+           return STATUS_NO_MEMORY;
+         }
      }
    else
      {
-       InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
+       Fcb->Data = NULL;
      }
-   Pipe->ReferenceCount++;
+
+   Fcb->ReadPtr = Fcb->Data;
+   Fcb->WritePtr = Fcb->Data;
+   Fcb->ReadDataAvailable = 0;
+   Fcb->WriteQuotaAvailable = Pipe->InboundQuota;
+   Fcb->MaxDataLength = Pipe->InboundQuota;
+   InitializeListHead(&Fcb->ReadRequestListHead);
+   ExInitializeFastMutex(&Fcb->DataListLock);
+
    Pipe->CurrentInstances++;
-   
-   KeAcquireSpinLock(&Pipe->FcbListLock, &oldIrql);
-   InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
-   KeReleaseSpinLock(&Pipe->FcbListLock, oldIrql);
-   
+
    Fcb->Pipe = Pipe;
    Fcb->PipeEnd = FILE_PIPE_SERVER_END;
+   Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
    Fcb->OtherSide = NULL;
-   Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-   Fcb->ReadDataAvailable = 0;
-   Fcb->WriteQuotaAvailable = 0;
 
-   /* initialize data list */
-   InitializeListHead(&Fcb->DataListHead);
-   KeInitializeSpinLock(&Fcb->DataListLock);
+   DPRINT("Fcb: %x\n", Fcb);
 
-   KeInitializeEvent(&Fcb->ConnectEvent,
-                    SynchronizationEvent,
-                    FALSE);
-   
-   KeInitializeEvent(&Fcb->ReadEvent,
-                    SynchronizationEvent,
-                    FALSE);
+   KeInitializeEvent(&Fcb->ConnectEvent, SynchronizationEvent, FALSE);
+   KeInitializeEvent(&Fcb->ReadEvent, SynchronizationEvent, FALSE);
+   KeInitializeEvent(&Fcb->WriteEvent, SynchronizationEvent, FALSE);
 
+   KeLockMutex(&Pipe->FcbListLock);
+   InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
+   KeUnlockMutex(&Pipe->FcbListLock);
 
-   KeUnlockMutex(&DeviceExt->PipeListLock);
-   
    FileObject->FsContext = Fcb;
-   
+
    Irp->IoStatus.Status = STATUS_SUCCESS;
-   Irp->IoStatus.Information = 0;
-   
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-   
-   return(STATUS_SUCCESS);
+
+   DPRINT("Success!\n");
+
+   return STATUS_SUCCESS;
 }
 
 
 NTSTATUS STDCALL
-NpfsClose(PDEVICE_OBJECT DeviceObject,
-         PIRP Irp)
+NpfsCleanup(PDEVICE_OBJECT DeviceObject,
+           PIRP Irp)
 {
-  PNPFS_DEVICE_EXTENSION DeviceExt;
-  PIO_STACK_LOCATION IoStack;
-  PFILE_OBJECT FileObject;
-  PNPFS_FCB Fcb;
-  PNPFS_PIPE Pipe;
-  KIRQL oldIrql;
-  PLIST_ENTRY CurrentEntry;
-  PNPFS_PIPE_DATA Current;
-
+   PNPFS_DEVICE_EXTENSION DeviceExt;
+   PIO_STACK_LOCATION IoStack;
+   PFILE_OBJECT FileObject;
+   PNPFS_FCB Fcb, OtherSide;
+   PNPFS_PIPE Pipe;
+   BOOLEAN Server;
 
-  DPRINT1("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+   DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
-  IoStack = IoGetCurrentIrpStackLocation(Irp);
-  DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-  FileObject = IoStack->FileObject;
-  Fcb =  FileObject->FsContext;
+   IoStack = IoGetCurrentIrpStackLocation(Irp);
+   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+   FileObject = IoStack->FileObject;
+   Fcb = FileObject->FsContext;
 
-  if (Fcb == NULL)
-    {
+   if (Fcb == NULL)
+   {
+      DPRINT("Success!\n");
       Irp->IoStatus.Status = STATUS_SUCCESS;
       Irp->IoStatus.Information = 0;
-
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_SUCCESS;
+   }
 
-      return(STATUS_SUCCESS);
-    }
+   DPRINT("Fcb %x\n", Fcb);
+   Pipe = Fcb->Pipe;
 
-  DPRINT("Fcb %x\n", Fcb);
-  Pipe = Fcb->Pipe;
+   DPRINT("Cleaning pipe %wZ\n", &Pipe->PipeName);
 
-  DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
+   KeLockMutex(&Pipe->FcbListLock);
 
-  KeLockMutex(&DeviceExt->PipeListLock);
+   Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
 
-
-   if (Fcb->PipeEnd == FILE_PIPE_SERVER_END)
-    {
+   if (Server)
+   {
       /* FIXME: Clean up existing connections here ?? */
       DPRINT("Server\n");
-      Pipe->CurrentInstances--;
-      if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
+   }
+   else
+   {
+      DPRINT("Client\n");
+   }
+   if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
+   {
+      OtherSide = Fcb->OtherSide;
+      /* Lock the server first */
+      if (Server)
       {
-          if (Fcb->OtherSide)
-          {
-             Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
-          }
-           Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+         ExAcquireFastMutex(&Fcb->DataListLock);
+        ExAcquireFastMutex(&OtherSide->DataListLock);
       }
-    }
-  Pipe->ReferenceCount--;
-
-  if (Fcb->PipeEnd == FILE_PIPE_CLIENT_END)
-  {
-      DPRINT("Client\n");
-      if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
+      else
       {
-         if (Fcb->OtherSide)
-        {
-           Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
-
-           /* Signaling the read event. If is possible that an other
-            * thread waits of read data.
-            */
-            KeSetEvent(&Fcb->OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
-        }
-         Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+        ExAcquireFastMutex(&OtherSide->DataListLock);
+         ExAcquireFastMutex(&Fcb->DataListLock);
       }
-  }
-  
-  FileObject->FsContext = NULL;
-
-  if (Pipe->ReferenceCount == 0)
-    {
-      KeAcquireSpinLock(&Pipe->FcbListLock, &oldIrql);
-      if (Fcb->OtherSide)
+      OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+      OtherSide->OtherSide = NULL;
+      /*
+       * Signaling the write event. If is possible that an other
+       * thread waits for an empty buffer.
+       */
+      KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
+      KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
+      if (Server)
       {
-         RemoveEntryList(&Fcb->OtherSide->FcbListEntry);
+         ExReleaseFastMutex(&Fcb->DataListLock);
+        ExReleaseFastMutex(&OtherSide->DataListLock);
       }
-      RemoveEntryList(&Fcb->FcbListEntry);
-      KeReleaseSpinLock(&Pipe->FcbListLock, oldIrql);
-      if (Fcb->OtherSide)
-      {  
-        KeAcquireSpinLock(&Fcb->OtherSide->DataListLock, &oldIrql);
-        while (!IsListEmpty(&Fcb->OtherSide->DataListHead))
+      else
+      {
+        ExReleaseFastMutex(&OtherSide->DataListLock);
+        ExReleaseFastMutex(&Fcb->DataListLock);
+      }
+   }
+   else if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
+   {
+      PLIST_ENTRY Entry;
+      PNPFS_WAITER_ENTRY WaitEntry = NULL;
+      BOOLEAN Complete = FALSE;
+      KIRQL oldIrql;
+      PIRP tmpIrp;
+
+      Entry = Fcb->Pipe->WaiterListHead.Flink;
+      while (Entry != &Fcb->Pipe->WaiterListHead)
+      {
+         WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
+        if (WaitEntry->Fcb == Fcb)
         {
-            CurrentEntry = RemoveHeadList(&Fcb->OtherSide->DataListHead);
-            Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE_DATA, ListEntry);
-
-            NpfsFreePipeData(Current);
+            RemoveEntryList(Entry);
+           tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
+           IoAcquireCancelSpinLock(&oldIrql);
+           if (!tmpIrp->Cancel)
+           {
+               IoSetCancelRoutine(tmpIrp, NULL);
+              Complete = TRUE;
+           }
+           IoReleaseCancelSpinLock(oldIrql);
+            if (Complete)
+           {
+              tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
+               tmpIrp->IoStatus.Information = 0;
+               IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
+           }
+           break;
         }
-         KeReleaseSpinLock(&Fcb->OtherSide->DataListLock, oldIrql);
-         ExFreePool(Fcb->OtherSide);
+        Entry = Entry->Flink;
       }
 
-      KeAcquireSpinLock(&Fcb->DataListLock, &oldIrql);
-      while (!IsListEmpty(&Fcb->DataListHead))
-      {
-         CurrentEntry = RemoveHeadList(&Fcb->DataListHead);
-        Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE_DATA, ListEntry);
-        NpfsFreePipeData(Current);
-      }
-      KeReleaseSpinLock(&Fcb->DataListLock, oldIrql);
-      ExFreePool(Fcb);
+   }
+   Fcb->PipeState = FILE_PIPE_CLOSING_STATE;
+
+   KeUnlockMutex(&Pipe->FcbListLock);
+
+   ExAcquireFastMutex(&Fcb->DataListLock);
+   if (Fcb->Data)
+   {
+      ExFreePool(Fcb->Data);
+      Fcb->Data = NULL;
+      Fcb->ReadPtr = NULL;
+      Fcb->WritePtr = NULL;
+   }
+   ExReleaseFastMutex(&Fcb->DataListLock);
+
+   Irp->IoStatus.Status = STATUS_SUCCESS;
+   Irp->IoStatus.Information = 0;
+   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+   DPRINT("Success!\n");
+
+   return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+NpfsClose(PDEVICE_OBJECT DeviceObject,
+          PIRP Irp)
+{
+   PNPFS_DEVICE_EXTENSION DeviceExt;
+   PIO_STACK_LOCATION IoStack;
+   PFILE_OBJECT FileObject;
+   PNPFS_FCB Fcb;
+   PNPFS_PIPE Pipe;
+   BOOLEAN Server;
+
+   DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+
+   IoStack = IoGetCurrentIrpStackLocation(Irp);
+   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+   FileObject = IoStack->FileObject;
+   Fcb = FileObject->FsContext;
+
+   if (Fcb == NULL)
+   {
+      DPRINT("Success!\n");
+      Irp->IoStatus.Status = STATUS_SUCCESS;
+      Irp->IoStatus.Information = 0;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_SUCCESS;
+   }
+
+   DPRINT("Fcb %x\n", Fcb);
+   Pipe = Fcb->Pipe;
+
+   DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
+
+   KeLockMutex(&Pipe->FcbListLock);
+
+   Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
+
+   if (Server)
+   {
+      DPRINT("Server\n");
+      Pipe->CurrentInstances--;
+   }
+   else
+   {
+      DPRINT("Client\n");
+   }
+
+   ASSERT (Fcb->PipeState == FILE_PIPE_CLOSING_STATE);
+
+   FileObject->FsContext = NULL;
+
+   RemoveEntryList(&Fcb->FcbListEntry);
+
+   ExFreePool(Fcb);
+
+   KeUnlockMutex(&Pipe->FcbListLock);
+
+   if (IsListEmpty(&Pipe->ServerFcbListHead) &&
+       IsListEmpty(&Pipe->ClientFcbListHead))
+   {
       RtlFreeUnicodeString(&Pipe->PipeName);
+      KeLockMutex(&DeviceExt->PipeListLock);
       RemoveEntryList(&Pipe->PipeListEntry);
+      KeUnlockMutex(&DeviceExt->PipeListLock);
       ExFreePool(Pipe);
-    }
-
-  KeUnlockMutex(&DeviceExt->PipeListLock);
+   }
 
-  Irp->IoStatus.Status = STATUS_SUCCESS;
-  Irp->IoStatus.Information = 0;
+   Irp->IoStatus.Status = STATUS_SUCCESS;
+   Irp->IoStatus.Information = 0;
+   IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+   DPRINT("Success!\n");
 
-  return(STATUS_SUCCESS);
+   return STATUS_SUCCESS;
 }
 
 /* EOF */