Patch by Elrond:
[reactos.git] / reactos / drivers / fs / np / fsctrl.c
index 715b84a..1f5ba90 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:  See COPYING in the top level directory
  * PROJECT:    ReactOS kernel
  * FILE:       drivers/fs/np/fsctrl.c
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include "npfs.h"
-
 #define NDEBUG
 #include <debug.h>
 
+#include "npfs.h"
+
 /* FUNCTIONS *****************************************************************/
 
 static VOID STDCALL
@@ -24,20 +22,21 @@ NpfsListeningCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
 {
   PNPFS_WAITER_ENTRY Waiter;
 
-  DPRINT1("NpfsListeningCancelRoutine() called\n");
+  Waiter = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
+
+  DPRINT1("NpfsListeningCancelRoutine() called for <%wZ>\n",
+         &Waiter->Fcb->Pipe->PipeName);
 
   IoReleaseCancelSpinLock(Irp->CancelIrql);
 
-  Waiter = Irp->Tail.Overlay.DriverContext[0];
 
-  KeLockMutex(&Waiter->Pipe->FcbListLock);
+  KeLockMutex(&Waiter->Fcb->Pipe->FcbListLock);
   RemoveEntryList(&Waiter->Entry);
-  KeUnlockMutex(&Waiter->Pipe->FcbListLock);
+  KeUnlockMutex(&Waiter->Fcb->Pipe->FcbListLock);
 
   Irp->IoStatus.Status = STATUS_CANCELLED;
   Irp->IoStatus.Information = 0;
   IoCompleteRequest(Irp, IO_NO_INCREMENT);
-  ExFreePool(Waiter);
 }
 
 
@@ -48,18 +47,13 @@ NpfsAddListeningServerInstance(PIRP Irp,
   PNPFS_WAITER_ENTRY Entry;
   KIRQL oldIrql;
 
-  Entry = ExAllocatePool(NonPagedPool, sizeof(NPFS_WAITER_ENTRY));
-  if (Entry == NULL)
-    return STATUS_INSUFFICIENT_RESOURCES;
+  Entry = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
 
-  Entry->Irp = Irp;
   Entry->Fcb = Fcb;
-  Entry->Pipe = Fcb->Pipe;
 
   KeLockMutex(&Fcb->Pipe->FcbListLock);
 
   IoMarkIrpPending(Irp);
-  Irp->Tail.Overlay.DriverContext[0] = Entry;
   InsertTailList(&Fcb->Pipe->WaiterListHead, &Entry->Entry);
 
   IoAcquireCancelSpinLock(&oldIrql);
@@ -71,14 +65,13 @@ NpfsAddListeningServerInstance(PIRP Irp,
       return STATUS_PENDING;
     }
   IoReleaseCancelSpinLock(oldIrql);
-  
+
   RemoveEntryList(&Entry->Entry);
-  
+
   Irp->IoStatus.Status = STATUS_CANCELLED;
   Irp->IoStatus.Information = 0;
   IoCompleteRequest(Irp, IO_NO_INCREMENT);
   KeUnlockMutex(&Fcb->Pipe->FcbListLock);
-  ExFreePool(Entry);
 
   return STATUS_CANCELLED;
 }
@@ -173,38 +166,101 @@ NpfsConnectPipe(PIRP Irp,
 static NTSTATUS
 NpfsDisconnectPipe(PNPFS_FCB Fcb)
 {
-  DPRINT("NpfsDisconnectPipe()\n");
-
-  if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
-    return STATUS_SUCCESS;
-
-  if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
-    {
-      Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-      /* FIXME: Shouldn't this be FILE_PIPE_CLOSING_STATE? */
-      Fcb->OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-
-      /* FIXME: remove data queue(s) */
-
-      Fcb->OtherSide->OtherSide = NULL;
+   NTSTATUS Status;
+   PNPFS_FCB OtherSide;
+   PNPFS_PIPE Pipe;
+   BOOLEAN Server;
+
+   DPRINT("NpfsDisconnectPipe()\n");
+
+   Pipe = Fcb->Pipe;
+   KeLockMutex(&Pipe->FcbListLock);
+
+   if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
+   {
+      DPRINT("Pipe is already disconnected\n");
+      Status = STATUS_SUCCESS;
+   }
+   else if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
+   {
+      Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
+      OtherSide = Fcb->OtherSide;
       Fcb->OtherSide = NULL;
-
-      DPRINT("Pipe disconnected\n");
-      return STATUS_SUCCESS;
-    }
-
-  if (Fcb->PipeState == FILE_PIPE_CLOSING_STATE)
-    {
       Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-      Fcb->OtherSide = NULL;
-
-      /* FIXME: remove data queue(s) */
-
-      DPRINT("Pipe disconnected\n");
-      return STATUS_SUCCESS;
-    }
-
-  return STATUS_UNSUCCESSFUL;
+      /* Lock the server first */
+      if (Server)
+      {
+         ExAcquireFastMutex(&Fcb->DataListLock);
+        ExAcquireFastMutex(&OtherSide->DataListLock);
+      }
+      else
+      {
+        ExAcquireFastMutex(&OtherSide->DataListLock);
+         ExAcquireFastMutex(&Fcb->DataListLock);
+      }
+      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)
+      {
+         ExReleaseFastMutex(&Fcb->DataListLock);
+        ExReleaseFastMutex(&OtherSide->DataListLock);
+      }
+      else
+      {
+        ExReleaseFastMutex(&OtherSide->DataListLock);
+        ExReleaseFastMutex(&OtherSide->DataListLock);
+      }
+      Status = STATUS_SUCCESS;
+   }
+   else if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
+   {
+      PLIST_ENTRY Entry;
+      PNPFS_WAITER_ENTRY WaitEntry = NULL;
+      BOOLEAN Complete = FALSE;
+      PIRP Irp = NULL;
+
+      Entry = Fcb->Pipe->WaiterListHead.Flink;
+      while (Entry != &Fcb->Pipe->WaiterListHead)
+      {
+         WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
+        if (WaitEntry->Fcb == Fcb)
+        {
+            RemoveEntryList(Entry);
+           Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DriverContext);
+           Complete = (NULL == IoSetCancelRoutine(Irp, NULL));
+            break;
+        }
+        Entry = Entry->Flink;
+      }
+
+      if (Irp)
+      {
+         if (Complete)
+        {
+           Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
+            Irp->IoStatus.Information = 0;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        }
+      }
+      Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+      Status = STATUS_SUCCESS;
+   }
+   else if (Fcb->PipeState == FILE_PIPE_CLOSING_STATE)
+   {
+      Status = STATUS_PIPE_CLOSING;
+   }
+   else
+   {
+      Status = STATUS_UNSUCCESSFUL;
+   }
+   KeUnlockMutex(&Pipe->FcbListLock);
+   return Status;
 }
 
 
@@ -215,12 +271,12 @@ NpfsWaitPipe(PIRP Irp,
   PNPFS_PIPE Pipe;
   PLIST_ENTRY current_entry;
   PNPFS_FCB ServerFcb;
-  PNPFS_WAIT_PIPE WaitPipe;
+  PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
   NTSTATUS Status;
 
   DPRINT("NpfsWaitPipe\n");
 
-  WaitPipe = (PNPFS_WAIT_PIPE)Irp->AssociatedIrp.SystemBuffer;
+  WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
   Pipe = Fcb->Pipe;
 
   if (Fcb->PipeState != 0)
@@ -269,80 +325,6 @@ NpfsWaitPipe(PIRP Irp,
  * RETURNS:
  *     Status of operation
  */
-static NTSTATUS
-NpfsGetState(PIRP Irp,
-            PIO_STACK_LOCATION IrpSp)
-{
-  PNPFS_GET_STATE Reply;
-  PNPFS_PIPE Pipe;
-  PNPFS_FCB Fcb;
-
-  /* Validate parameters */
-  if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(NPFS_GET_STATE))
-    {
-      DPRINT("Status (0x%X).\n", STATUS_INVALID_PARAMETER);
-      return STATUS_INVALID_PARAMETER;
-    }
-
-  Fcb = IrpSp->FileObject->FsContext;
-  Reply = (PNPFS_GET_STATE)Irp->AssociatedIrp.SystemBuffer;
-  Pipe = Fcb->Pipe;
-
-  Reply->WriteModeMessage = (Pipe->WriteMode == FILE_PIPE_MESSAGE_MODE);
-  Reply->ReadModeMessage = (Pipe->ReadMode == FILE_PIPE_MESSAGE_MODE);
-  Reply->NonBlocking = (Pipe->CompletionMode == FILE_PIPE_QUEUE_OPERATION);
-  Reply->InBufferSize = Pipe->InboundQuota;
-  Reply->OutBufferSize = Pipe->OutboundQuota;
-  Reply->Timeout = Pipe->TimeOut;
-
-  DPRINT("Status (0x%X).\n", STATUS_SUCCESS);
-
-  return STATUS_SUCCESS;
-}
-
-
-/*
- * FUNCTION: Set state of a pipe
- * ARGUMENTS:
- *     Irp   = Pointer to I/O request packet
- *     IrpSp = Pointer to current stack location of Irp
- * RETURNS:
- *     Status of operation
- */
-static NTSTATUS
-NpfsSetState(PIRP Irp,
-            PIO_STACK_LOCATION IrpSp)
-{
-  PNPFS_SET_STATE Request;
-  PNPFS_PIPE Pipe;
-  PNPFS_FCB Fcb;
-
-  /* Validate parameters */
-  if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(NPFS_SET_STATE))
-    {
-      DPRINT("Status (0x%X).\n", STATUS_INVALID_PARAMETER);
-      return STATUS_INVALID_PARAMETER;
-    }
-
-  Fcb = IrpSp->FileObject->FsContext;
-  Request = (PNPFS_SET_STATE)Irp->AssociatedIrp.SystemBuffer;
-  Pipe = Fcb->Pipe;
-
-  Pipe->WriteMode =
-    Request->WriteModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
-  Pipe->ReadMode =
-    Request->WriteModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
-  Pipe->CompletionMode =
-    Request->NonBlocking ? FILE_PIPE_QUEUE_OPERATION : FILE_PIPE_COMPLETE_OPERATION;
-  Pipe->InboundQuota = Request->InBufferSize;
-  Pipe->OutboundQuota = Request->OutBufferSize;
-  Pipe->TimeOut = Request->Timeout;
-
-  DPRINT("Status (0x%X).\n", STATUS_SUCCESS);
-
-  return STATUS_SUCCESS;
-}
-
 
 /*
  * FUNCTION: Peek at a pipe (get information about messages)
@@ -407,6 +389,8 @@ NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
   DPRINT("Pipe: %p\n", Pipe);
   DPRINT("PipeName: %wZ\n", &Pipe->PipeName);
 
+  Irp->IoStatus.Information = 0;
+
   switch (IoStack->Parameters.FileSystemControl.FsControlCode)
     {
       case FSCTL_PIPE_ASSIGN_EVENT:
@@ -459,16 +443,6 @@ NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
        Status = STATUS_NOT_IMPLEMENTED;
        break;
 
-      case FSCTL_PIPE_GET_STATE:
-       DPRINT("Get state\n");
-       Status = NpfsGetState(Irp, (PIO_STACK_LOCATION)IoStack);
-       break;
-
-      case FSCTL_PIPE_SET_STATE:
-       DPRINT("Set state\n");
-       Status = NpfsSetState(Irp, (PIO_STACK_LOCATION)IoStack);
-       break;
-
       case FSCTL_PIPE_INTERNAL_READ:
        DPRINT("Internal read\n");
        Status = STATUS_NOT_IMPLEMENTED;
@@ -490,15 +464,14 @@ NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
        break;
 
       default:
-       DPRINT("IoControlCode: %x\n", IoStack->Parameters.FileSystemControl.FsControlCode)
+       DPRINT("IoControlCode: %x\n", IoStack->Parameters.FileSystemControl.FsControlCode);
        Status = STATUS_UNSUCCESSFUL;
     }
 
   if (Status != STATUS_PENDING)
     {
       Irp->IoStatus.Status = Status;
-      Irp->IoStatus.Information = 0;
+
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
     }