[FASTFAT] Start implementing FAT32 statistics support
[reactos.git] / drivers / filesystems / npfs / fsctrl.c
index ce68432..d9ff6c8 100644 (file)
 /*
-* COPYRIGHT:  See COPYING in the top level directory
-* PROJECT:    ReactOS kernel
-* FILE:       drivers/filesystems/npfs/fsctrl.c
-* PURPOSE:    Named pipe filesystem
-* PROGRAMMER: David Welch <welch@cwcom.net>
-*             Eric Kohl
-*             Michael Martin
-*/
+ * PROJECT:     ReactOS Named Pipe FileSystem
+ * LICENSE:     BSD - See COPYING.ARM in the top level directory
+ * FILE:        drivers/filesystems/npfs/fsctrl.c
+ * PURPOSE:     Named Pipe FileSystem I/O Controls
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
 
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include "npfs.h"
 
-#define NDEBUG
-#include <debug.h>
+// File ID number for NPFS bugchecking support
+#define NPFS_BUGCHECK_FILE_ID   (NPFS_BUGCHECK_FSCTRL)
 
-//#define USING_PROPER_NPFS_WAIT_SEMANTICS
+/* GLOBALS ********************************************************************/
 
-/* FUNCTIONS *****************************************************************/
+IO_STATUS_BLOCK NpUserIoStatusBlock;
 
-static DRIVER_CANCEL NpfsListeningCancelRoutine;
-static VOID NTAPI
-NpfsListeningCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
-                           IN PIRP Irp)
-{
-    PNPFS_WAITER_ENTRY Waiter;
-
-    UNREFERENCED_PARAMETER(DeviceObject);
-
-    Waiter = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
-
-    DPRINT("NpfsListeningCancelRoutine() called for <%wZ>\n",
-        &Waiter->Ccb->Fcb->PipeName);
-
-    IoReleaseCancelSpinLock(Irp->CancelIrql);
+/* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+NpInternalTransceive(IN PDEVICE_OBJECT DeviceObject,
+                     IN PIRP Irp,
+                     IN PLIST_ENTRY List)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
 
-    KeLockMutex(&Waiter->Ccb->Fcb->CcbListLock);
-    RemoveEntryList(&Waiter->Entry);
-    KeUnlockMutex(&Waiter->Ccb->Fcb->CcbListLock);
-
-    Irp->IoStatus.Status = STATUS_CANCELLED;
-    Irp->IoStatus.Information = 0;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+NTSTATUS
+NTAPI
+NpInternalRead(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp,
+               IN BOOLEAN Overflow,
+               IN PLIST_ENTRY List)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
 }
 
+NTSTATUS
+NTAPI
+NpInternalWrite(IN PDEVICE_OBJECT DeviceObject,
+                IN PIRP Irp,
+                IN PLIST_ENTRY List)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
 
-static NTSTATUS
-NpfsAddListeningServerInstance(PIRP Irp,
-                               PNPFS_CCB Ccb)
+NTSTATUS
+NTAPI
+NpQueryClientProcess(IN PDEVICE_OBJECT DeviceObject,
+                   IN PIRP Irp)
 {
-    PNPFS_WAITER_ENTRY Entry;
-    KIRQL oldIrql;
+    PIO_STACK_LOCATION IoStackLocation;
+    NODE_TYPE_CODE NodeTypeCode;
+    PNP_CCB Ccb;
+    PNP_CLIENT_PROCESS ClientSession, QueryBuffer;
+    ULONG Length;
+    PAGED_CODE();
+
+    /* Get the current stack location */
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Decode the file object and check the node type */
+    NodeTypeCode = NpDecodeFileObject(IoStackLocation->FileObject, 0, &Ccb, 0);
+    if (NodeTypeCode != NPFS_NTC_CCB)
+    {
+        return STATUS_PIPE_DISCONNECTED;
+    }
 
-    Entry = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
+    /* Get the length of the query buffer */
+    Length = IoStackLocation->Parameters.QueryFile.Length;
+    if (Length < 8)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
 
-    Entry->Ccb = Ccb;
+    QueryBuffer = Irp->AssociatedIrp.SystemBuffer;
 
-    KeLockMutex(&Ccb->Fcb->CcbListLock);
+    /* Lock the Ccb */
+    ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
 
-    IoAcquireCancelSpinLock(&oldIrql);
-    if (!Irp->Cancel)
+    /* Get the CCBs client session and check if it's set */
+    ClientSession = Ccb->ClientSession;
+    if (ClientSession != NULL)
+    {
+        /* Copy first 2 fields */
+        QueryBuffer->Unknown = ClientSession->Unknown;
+        QueryBuffer->Process = ClientSession->Process;
+    }
+    else
     {
-        Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
-        IoMarkIrpPending(Irp);
-        InsertTailList(&Ccb->Fcb->WaiterListHead, &Entry->Entry);
-        (void)IoSetCancelRoutine(Irp, NpfsListeningCancelRoutine);
-        IoReleaseCancelSpinLock(oldIrql);
-        KeUnlockMutex(&Ccb->Fcb->CcbListLock);
-        return STATUS_PENDING;
+        /* Copy the process from the CCB */
+        QueryBuffer->Unknown = NULL;
+        QueryBuffer->Process = Ccb->Process;
     }
-    IoReleaseCancelSpinLock(oldIrql);
 
-    RemoveEntryList(&Entry->Entry);
+    /* Does the caller provide a large enough buffer for the full data? */
+    if (Length >= sizeof(NP_CLIENT_PROCESS))
+    {
+        Irp->IoStatus.Information = sizeof(NP_CLIENT_PROCESS);
 
-    Irp->IoStatus.Status = STATUS_CANCELLED;
-    Irp->IoStatus.Information = 0;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-    KeUnlockMutex(&Ccb->Fcb->CcbListLock);
+        /* Do we have a ClientSession structure? */
+        if (ClientSession != NULL)
+        {
+            /* Copy length and the data */
+            QueryBuffer->DataLength = ClientSession->DataLength;
+            RtlCopyMemory(QueryBuffer->Buffer,
+                          ClientSession->Buffer,
+                          ClientSession->DataLength);
+
+            /* NULL terminate the buffer */
+            NT_ASSERT(QueryBuffer->DataLength <= 30);
+            QueryBuffer->Buffer[QueryBuffer->DataLength / sizeof(WCHAR)] = 0;
+        }
+        else
+        {
+            /* No data */
+            QueryBuffer->DataLength = 0;
+            QueryBuffer->Buffer[0] = 0;
+        }
+    }
+    else
+    {
+        Irp->IoStatus.Information = FIELD_OFFSET(NP_CLIENT_PROCESS, DataLength);
+    }
 
-    return STATUS_CANCELLED;
-}
+    /* Unlock the Ccb */
+    ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
 
+    return STATUS_SUCCESS;
+}
 
-static NTSTATUS
-NpfsConnectPipe(PIRP Irp,
-                PNPFS_CCB Ccb)
+NTSTATUS
+NTAPI
+NpSetClientProcess(IN PDEVICE_OBJECT DeviceObject,
+                   IN PIRP Irp)
 {
-    PIO_STACK_LOCATION IoStack;
-    PFILE_OBJECT FileObject;
-    ULONG Flags;
-    PLIST_ENTRY current_entry;
-    PNPFS_FCB Fcb;
-    PNPFS_CCB ClientCcb;
-    NTSTATUS Status;
-    KPROCESSOR_MODE WaitMode;
-
-    DPRINT("NpfsConnectPipe()\n");
+    PIO_STACK_LOCATION IoStackLocation;
+    NODE_TYPE_CODE NodeTypeCode;
+    PNP_CCB Ccb;
+    ULONG Length;
+    PNP_CLIENT_PROCESS InputBuffer, ClientSession, OldClientSession;
+    PAGED_CODE();
+
+    /* Get the current stack location */
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Only kernel calls are allowed! */
+    if (IoStackLocation->MinorFunction != IRP_MN_KERNEL_CALL)
+    {
+        return STATUS_ACCESS_DENIED;
+    }
 
-    /* Fail, if the CCB is not a pipe CCB */
-    if (Ccb->Type != CCB_PIPE)
+    /* Decode the file object and check the node type */
+    NodeTypeCode = NpDecodeFileObject(IoStackLocation->FileObject, 0, &Ccb, 0);
+    if (NodeTypeCode != NPFS_NTC_CCB)
     {
-        DPRINT("Not a pipe\n");
-        return STATUS_ILLEGAL_FUNCTION;
+        return STATUS_PIPE_DISCONNECTED;
     }
 
-    /* Fail, if the CCB is not a server end CCB */
-    if (Ccb->PipeEnd != FILE_PIPE_SERVER_END)
+    /* Get the length of the query buffer and check if it's valid */
+    Length = IoStackLocation->Parameters.QueryFile.Length;
+    if (Length != sizeof(NP_CLIENT_PROCESS))
     {
-        DPRINT("Not the server end\n");
-        return STATUS_ILLEGAL_FUNCTION;
+        return STATUS_INVALID_PARAMETER;
     }
 
-    if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
+    /* Get the buffer and check if the data Length is valid */
+    InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+    if (InputBuffer->DataLength > 30)
     {
-        KeResetEvent(&Ccb->ConnectEvent);
-        return STATUS_PIPE_CONNECTED;
+        return STATUS_INVALID_PARAMETER;
     }
 
-    if (Ccb->PipeState == FILE_PIPE_CLOSING_STATE)
-        return STATUS_PIPE_CLOSING;
+    /* Allocate a new structure */
+    ClientSession = ExAllocatePoolWithQuotaTag(PagedPool,
+                                               sizeof(NP_CLIENT_PROCESS),
+                                               'iFpN');
 
-    DPRINT("Waiting for connection...\n");
+    /* Copy the full input buffer */
+    RtlCopyMemory(ClientSession, InputBuffer, sizeof(NP_CLIENT_PROCESS));
 
-    Fcb = Ccb->Fcb;
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    FileObject = IoStack->FileObject;
-    Flags = FileObject->Flags;
-    WaitMode = Irp->RequestorMode;
+    /* Lock the Ccb */
+    ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
+
+    /* Get the old ClientSession and set the new */
+    OldClientSession = Ccb->ClientSession;
+    Ccb->ClientSession = ClientSession;
 
-    /* search for a listening client fcb */
-    KeLockMutex(&Fcb->CcbListLock);
+    /* Copy the process to the CCB */
+    Ccb->Process = ClientSession->Process;
 
-    current_entry = Fcb->ClientCcbListHead.Flink;
-    while (current_entry != &Fcb->ClientCcbListHead)
+    /* Unlock the Ccb */
+    ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
+
+    /* Check if there was already a ClientSession */
+    if (OldClientSession != NULL)
     {
-        ClientCcb = CONTAINING_RECORD(current_entry,
-            NPFS_CCB,
-            CcbListEntry);
+        /* Free it */
+        ExFreePoolWithTag(OldClientSession, 'iFpN');
+    }
 
-        if (ClientCcb->PipeState == 0)
-        {
-            /* found a passive (waiting) client CCB */
-            DPRINT("Passive (waiting) client CCB found -- wake the client\n");
-            KeSetEvent(&ClientCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
-            break;
-        }
+    return STATUS_SUCCESS;
+}
 
-#if 0
-        if (ClientCcb->PipeState == FILE_PIPE_LISTENING_STATE)
-        {
-            /* found a listening client CCB */
-            DPRINT("Listening client CCB found -- connecting\n");
+NTSTATUS
+NTAPI
+NpAssignEvent(IN PDEVICE_OBJECT DeviceObject,
+              IN PIRP Irp)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
 
-            /* connect client and server CCBs */
-            Ccb->OtherSide = ClientCcb;
-            ClientCcb->OtherSide = Ccb;
+NTSTATUS
+NTAPI
+NpQueryEvent(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
 
-            /* set connected state */
-            Ccb->PipeState = FILE_PIPE_CONNECTED_STATE;
-            ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
+NTSTATUS
+NTAPI
+NpImpersonate(IN PDEVICE_OBJECT DeviceObject,
+              IN PIRP Irp)
+{
+    ULONG NamedPipeEnd;
+    PNP_CCB Ccb;
+    NTSTATUS Status;
+    NODE_TYPE_CODE NodeTypeCode;
+    PIO_STACK_LOCATION IoStack;
+    PAGED_CODE();
 
-            KeUnlockMutex(&Fcb->CcbListLock);
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-            /* FIXME: create and initialize data queues */
+    NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
+    if (NodeTypeCode == NPFS_NTC_CCB && NamedPipeEnd == FILE_PIPE_SERVER_END)
+    {
+        Status = NpImpersonateClientContext(Ccb);
+    }
+    else
+    {
+        Status = STATUS_ILLEGAL_FUNCTION;
+    }
 
-            /* signal client's connect event */
-            DPRINT("Setting the ConnectEvent for %x\n", ClientCcb);
-            KeSetEvent(&ClientCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
+    return Status;
+}
 
-            return STATUS_PIPE_CONNECTED;
-        }
-#endif
+NTSTATUS
+NTAPI
+NpDisconnect(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp,
+             IN PLIST_ENTRY List)
+{
+    ULONG NamedPipeEnd;
+    PNP_CCB Ccb;
+    NTSTATUS Status;
+    NODE_TYPE_CODE NodeTypeCode;
+    PIO_STACK_LOCATION IoStack;
+    PAGED_CODE();
 
-        current_entry = current_entry->Flink;
-    }
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-    /* no listening client fcb found */
-    DPRINT("No listening client fcb found -- waiting for client\n");
+    NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
+    if (NodeTypeCode == NPFS_NTC_CCB)
+    {
+        if (NamedPipeEnd == FILE_PIPE_SERVER_END)
+        {
+            ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
 
-    Status = NpfsAddListeningServerInstance(Irp, Ccb);
+            Status = NpSetDisconnectedPipeState(Ccb, List);
 
-    KeUnlockMutex(&Fcb->CcbListLock);
+            NpUninitializeSecurity(Ccb);
 
-    if ((Status == STATUS_PENDING) && (Flags & FO_SYNCHRONOUS_IO))
+            ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
+        }
+        else
+        {
+            Status = STATUS_ILLEGAL_FUNCTION;
+        }
+    }
+    else
     {
-        KeWaitForSingleObject(&Ccb->ConnectEvent,
-            UserRequest,
-            WaitMode,
-            (Flags & FO_ALERTABLE_IO) != 0,
-            NULL);
+        Status = STATUS_PIPE_DISCONNECTED;
     }
 
-    DPRINT("NpfsConnectPipe() done (Status %lx)\n", Status);
-
     return Status;
 }
 
-
-static NTSTATUS
-NpfsDisconnectPipe(PNPFS_CCB Ccb)
+NTSTATUS
+NTAPI
+NpListen(IN PDEVICE_OBJECT DeviceObject,
+         IN PIRP Irp,
+         IN PLIST_ENTRY List)
 {
+    ULONG NamedPipeEnd;
+    PNP_CCB Ccb;
     NTSTATUS Status;
-    PNPFS_FCB Fcb;
-    PNPFS_CCB OtherSide;
-    BOOLEAN Server;
+    NODE_TYPE_CODE NodeTypeCode;
+    PIO_STACK_LOCATION IoStack;
+    PAGED_CODE();
 
-    DPRINT("NpfsDisconnectPipe()\n");
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-    /* Fail, if the CCB is not a pipe CCB */
-    if (Ccb->Type != CCB_PIPE)
+    NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
+    if (NodeTypeCode == NPFS_NTC_CCB)
     {
-        DPRINT("Not a pipe\n");
-        return STATUS_ILLEGAL_FUNCTION;
-    }
+        if (NamedPipeEnd == FILE_PIPE_SERVER_END)
+        {
+            ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
 
-    /* Fail, if the CCB is not a server end CCB */
-    if (Ccb->PipeEnd != FILE_PIPE_SERVER_END)
+            Status = NpSetListeningPipeState(Ccb, Irp, List);
+
+            NpUninitializeSecurity(Ccb);
+
+            ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
+        }
+        else
+        {
+            Status = STATUS_ILLEGAL_FUNCTION;
+        }
+    }
+    else
     {
-        DPRINT("Not the server end\n");
-        return STATUS_ILLEGAL_FUNCTION;
+        Status = STATUS_ILLEGAL_FUNCTION;
     }
 
-    Fcb = Ccb->Fcb;
-    KeLockMutex(&Fcb->CcbListLock);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NpPeek(IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp,
+       IN PLIST_ENTRY List)
+{
+    PIO_STACK_LOCATION IoStack;
+    NODE_TYPE_CODE Type;
+    ULONG OutputLength;
+    ULONG NamedPipeEnd;
+    PNP_CCB Ccb;
+    PFILE_PIPE_PEEK_BUFFER PeekBuffer;
+    PNP_DATA_QUEUE DataQueue;
+    ULONG_PTR BytesPeeked;
+    IO_STATUS_BLOCK IoStatus;
+    NTSTATUS Status;
+    PNP_DATA_QUEUE_ENTRY DataEntry;
+    PAGED_CODE();
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    OutputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
+    Type = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
 
-    if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
+    if (!Type)
     {
-        DPRINT("Pipe is already disconnected\n");
-        Status = STATUS_PIPE_DISCONNECTED;
+        return STATUS_PIPE_DISCONNECTED;
     }
-    else if ((!Ccb->OtherSide) && (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE))
+
+    if ((Type != NPFS_NTC_CCB) &&
+        (OutputLength < FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)))
     {
-        ExAcquireFastMutex(&Ccb->DataListLock);
-        Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-        ExReleaseFastMutex(&Ccb->DataListLock);
-        Status = STATUS_SUCCESS;
+        return STATUS_INVALID_PARAMETER;
     }
-    else if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
+
+    PeekBuffer = Irp->AssociatedIrp.SystemBuffer;
+    if (NamedPipeEnd != FILE_PIPE_CLIENT_END)
     {
-        Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
-        OtherSide = Ccb->OtherSide;
-        //Ccb->OtherSide = NULL;
-        Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-        /* Lock the server first */
-        if (Server)
-        {
-            ExAcquireFastMutex(&Ccb->DataListLock);
-            ExAcquireFastMutex(&OtherSide->DataListLock);
-        }
-        else
+        if (NamedPipeEnd != FILE_PIPE_SERVER_END)
         {
-            ExAcquireFastMutex(&OtherSide->DataListLock);
-            ExAcquireFastMutex(&Ccb->DataListLock);
+            NpBugCheck(NamedPipeEnd, 0, 0);
         }
-        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)
+
+        DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
+    }
+    else
+    {
+        DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
+    }
+
+    if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE)
+    {
+        if (Ccb->NamedPipeState != FILE_PIPE_CLOSING_STATE)
         {
-            ExReleaseFastMutex(&OtherSide->DataListLock);
-            ExReleaseFastMutex(&Ccb->DataListLock);
+            return STATUS_INVALID_PIPE_STATE;
         }
-        else
+
+        if (DataQueue->QueueState != WriteEntries)
         {
-            ExReleaseFastMutex(&Ccb->DataListLock);
-            ExReleaseFastMutex(&OtherSide->DataListLock);
+            return STATUS_PIPE_BROKEN;
         }
-        Status = STATUS_SUCCESS;
     }
-    else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
+
+    PeekBuffer->NamedPipeState = 0;
+    PeekBuffer->ReadDataAvailable = 0;
+    PeekBuffer->NumberOfMessages = 0;
+    PeekBuffer->MessageLength = 0;
+    PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
+    BytesPeeked = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data);
+
+    if (DataQueue->QueueState == WriteEntries)
     {
-        PLIST_ENTRY Entry;
-        PNPFS_WAITER_ENTRY WaitEntry = NULL;
-        BOOLEAN Complete = FALSE;
-        PIRP Irp = NULL;
+        DataEntry = CONTAINING_RECORD(DataQueue->Queue.Flink,
+                                      NP_DATA_QUEUE_ENTRY,
+                                      QueueEntry);
+        ASSERT((DataEntry->DataEntryType == Buffered) || (DataEntry->DataEntryType == Unbuffered));
 
-        Entry = Ccb->Fcb->WaiterListHead.Flink;
-        while (Entry != &Ccb->Fcb->WaiterListHead)
+        PeekBuffer->ReadDataAvailable = DataQueue->BytesInQueue - DataQueue->ByteOffset;
+        if (Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE)
         {
-            WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
-            if (WaitEntry->Ccb == Ccb)
-            {
-                RemoveEntryList(Entry);
-                Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DriverContext);
-                Complete = (NULL != IoSetCancelRoutine(Irp, NULL));
-                break;
-            }
-            Entry = Entry->Flink;
+            PeekBuffer->NumberOfMessages = DataQueue->EntriesInQueue;
+            PeekBuffer->MessageLength = DataEntry->DataSize - DataQueue->ByteOffset;
         }
 
-        if (Irp)
+        if (OutputLength == FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data))
         {
-            if (Complete)
-            {
-                Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
-                Irp->IoStatus.Information = 0;
-                IoCompleteRequest(Irp, IO_NO_INCREMENT);
-            }
+            Status = PeekBuffer->ReadDataAvailable ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
+        }
+        else
+        {
+            IoStatus = NpReadDataQueue(DataQueue,
+                                       TRUE,
+                                       FALSE,
+                                       PeekBuffer->Data,
+                                       OutputLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data),
+                                       Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE,
+                                       Ccb,
+                                       List);
+            Status = IoStatus.Status;
+            BytesPeeked += IoStatus.Information;
         }
-        Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-        Status = STATUS_SUCCESS;
-    }
-    else if (Ccb->PipeState == FILE_PIPE_CLOSING_STATE)
-    {
-        Status = STATUS_PIPE_CLOSING;
     }
     else
     {
-        Status = STATUS_UNSUCCESSFUL;
+        Status = STATUS_SUCCESS;
     }
-    KeUnlockMutex(&Fcb->CcbListLock);
+
+    Irp->IoStatus.Information = BytesPeeked;
     return Status;
 }
 
-static NTSTATUS
-NpfsWaitPipe(PIRP Irp,
-             PNPFS_CCB Ccb)
+NTSTATUS
+NTAPI
+NpCompleteTransceiveIrp(IN PDEVICE_OBJECT DeviceObject,
+                        IN PIRP Irp,
+                        IN PVOID Context)
 {
-    PLIST_ENTRY current_entry;
-    PNPFS_FCB Fcb;
-    PNPFS_CCB ServerCcb;
-    PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
-    PLARGE_INTEGER TimeOut;
-    NTSTATUS Status;
-    PEXTENDED_IO_STACK_LOCATION IoStack;
-    PFILE_OBJECT FileObject;
-    PNPFS_VCB Vcb;
+    PAGED_CODE();
 
-    IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
-    ASSERT(IoStack);
-    FileObject = IoStack->FileObject;
-    ASSERT(FileObject);
-
-    DPRINT("Waiting on Pipe %wZ\n", &FileObject->FileName);
+    if (Irp->AssociatedIrp.SystemBuffer)
+    {
+        ExFreePool(Irp->AssociatedIrp.SystemBuffer);
+    }
 
-    WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+    IoFreeIrp(Irp);
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
 
-    ASSERT(Ccb->Fcb);
-    ASSERT(Ccb->Fcb->Vcb);
+NTSTATUS
+NTAPI
+NpTransceive(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp,
+             IN PLIST_ENTRY List)
+{
+    PIO_STACK_LOCATION IoStack;
+    PVOID InBuffer, OutBuffer;
+    ULONG InLength, OutLength, BytesWritten;
+    NODE_TYPE_CODE NodeTypeCode;
+    PNP_CCB Ccb;
+    ULONG NamedPipeEnd;
+    PNP_NONPAGED_CCB NonPagedCcb;
+    PNP_DATA_QUEUE ReadQueue, WriteQueue;
+    PNP_EVENT_BUFFER EventBuffer;
+    NTSTATUS Status;
+    PIRP NewIrp;
+    PAGED_CODE();
 
-    /* Get the VCB */
-    Vcb = Ccb->Fcb->Vcb;
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    InLength = IoStack->Parameters.FileSystemControl.InputBufferLength;
+    InBuffer = IoStack->Parameters.FileSystemControl.Type3InputBuffer;
+    OutLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
+    OutBuffer = Irp->UserBuffer;
 
-    /* Lock the pipe list */
-    KeLockMutex(&Vcb->PipeListLock);
+    if (Irp->RequestorMode == UserMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForRead(InBuffer, InLength, sizeof(CHAR));
+            ProbeForWrite(OutBuffer, OutLength, sizeof(CHAR));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
 
-    /* File a pipe with the given name */
-    Fcb = NpfsFindPipe(Vcb,
-                       &FileObject->FileName);
+    NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
+    if (NodeTypeCode != NPFS_NTC_CCB)
+    {
+        return STATUS_PIPE_DISCONNECTED;
+    }
 
-    /* Unlock the pipe list */
-    KeUnlockMutex(&Vcb->PipeListLock);
+    NonPagedCcb = Ccb->NonPagedCcb;
+    ExAcquireResourceExclusiveLite(&NonPagedCcb->Lock, TRUE);
 
-    /* Fail if not pipe was found */
-    if (Fcb == NULL)
+    if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE)
     {
-        DPRINT("No pipe found!\n");
-        return STATUS_OBJECT_NAME_NOT_FOUND;
+        Status = STATUS_INVALID_PIPE_STATE;
+        goto Quickie;
     }
 
-    /* search for listening server */
-    current_entry = Fcb->ServerCcbListHead.Flink;
-    while (current_entry != &Fcb->ServerCcbListHead)
+    if (NamedPipeEnd != FILE_PIPE_CLIENT_END)
     {
-        ServerCcb = CONTAINING_RECORD(current_entry,
-                                      NPFS_CCB,
-                                      CcbListEntry);
-
-        if (ServerCcb->PipeState == FILE_PIPE_LISTENING_STATE)
+        if (NamedPipeEnd != FILE_PIPE_SERVER_END)
         {
-            /* found a listening server CCB */
-            DPRINT("Listening server CCB found -- connecting\n");
-            NpfsDereferenceFcb(Fcb);
-            return STATUS_SUCCESS;
+            NpBugCheck(NamedPipeEnd, 0, 0);
         }
+        ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
+        WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
+    }
+    else
+    {
+        ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
+        WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
+    }
+
+    EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd];
 
-        current_entry = current_entry->Flink;
+    if (Ccb->Fcb->NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX ||
+        Ccb->ReadMode[NamedPipeEnd] != FILE_PIPE_MESSAGE_MODE)
+    {
+        Status = STATUS_INVALID_PIPE_STATE;
+        goto Quickie;
     }
 
-    /* No listening server fcb found, so wait for one */
+    if (ReadQueue->QueueState != Empty)
+    {
+        Status = STATUS_PIPE_BUSY;
+        goto Quickie;
+    }
 
-    /* If a timeout specified */
-    if (WaitPipe->TimeoutSpecified)
+    Status = NpWriteDataQueue(WriteQueue,
+                              FILE_PIPE_MESSAGE_MODE,
+                              InBuffer,
+                              InLength,
+                              Ccb->Fcb->NamedPipeType,
+                              &BytesWritten,
+                              Ccb,
+                              NamedPipeEnd,
+                              Irp->Tail.Overlay.Thread,
+                              List);
+    if (Status == STATUS_MORE_PROCESSING_REQUIRED)
     {
-        /* NMPWAIT_USE_DEFAULT_WAIT = 0 */
-        if (WaitPipe->Timeout.QuadPart == 0)
+        ASSERT(WriteQueue->QueueState != ReadEntries);
+        NewIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
+        if (!NewIrp)
         {
-            TimeOut = &Fcb->TimeOut;
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto Quickie;
+        }
+
+        IoSetCompletionRoutine(Irp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE);
+
+        if (BytesWritten)
+        {
+            NewIrp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
+                                                                            BytesWritten,
+                                                                            NPFS_WRITE_BLOCK_TAG);
+            if (!NewIrp->AssociatedIrp.SystemBuffer)
+            {
+                IoFreeIrp(NewIrp);
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto Quickie;
+            }
+
+            _SEH2_TRY
+            {
+                RtlCopyMemory(NewIrp->AssociatedIrp.SystemBuffer,
+                              (PVOID)((ULONG_PTR)InBuffer + InLength - BytesWritten),
+                              BytesWritten);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+                _SEH2_YIELD(goto Quickie);
+            }
+            _SEH2_END;
         }
         else
         {
-            TimeOut = &WaitPipe->Timeout;
+            NewIrp->AssociatedIrp.SystemBuffer = NULL;
+        }
+
+        IoStack = IoGetNextIrpStackLocation(NewIrp);
+        IoSetNextIrpStackLocation(NewIrp);
+
+        NewIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
+        NewIrp->IoStatus.Information = BytesWritten;
+
+        IoStack->Parameters.Read.Length = BytesWritten;
+        IoStack->MajorFunction = IRP_MJ_WRITE;
+
+        if (BytesWritten > 0) NewIrp->Flags = IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO;
+        NewIrp->UserIosb = &NpUserIoStatusBlock;
+
+        Status = NpAddDataQueueEntry(NamedPipeEnd,
+                                     Ccb,
+                                     WriteQueue,
+                                     WriteEntries,
+                                     Unbuffered,
+                                     BytesWritten,
+                                     NewIrp,
+                                     NULL,
+                                     0);
+        if (Status != STATUS_PENDING)
+        {
+            NewIrp->IoStatus.Status = Status;
+            InsertTailList(List, &NewIrp->Tail.Overlay.ListEntry);
         }
     }
-    else
+
+    if (!NT_SUCCESS(Status)) goto Quickie;
+
+    if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
+    ASSERT(ReadQueue->QueueState == Empty);
+    Status = NpAddDataQueueEntry(NamedPipeEnd,
+                                 Ccb,
+                                 ReadQueue,
+                                 ReadEntries,
+                                 Buffered,
+                                 OutLength,
+                                 Irp,
+                                 NULL,
+                                 0);
+    if (NT_SUCCESS(Status))
     {
-        /* Wait forever */
-        TimeOut = NULL;
+        if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
     }
-    NpfsDereferenceFcb(Fcb);
-
-    Status = KeWaitForSingleObject(&Ccb->ConnectEvent,
-                                   UserRequest,
-                                   Irp->RequestorMode,
-                                   (Ccb->FileObject->Flags & FO_ALERTABLE_IO) != 0,
-                                   TimeOut);
-    if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC) || (Status == STATUS_ALERTED))
-        Status = STATUS_CANCELLED;
-
-    DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status);
 
+Quickie:
+    ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
     return Status;
 }
 
 NTSTATUS
-NpfsWaitPipe2(PIRP Irp,
-             PNPFS_CCB Ccb)
+NTAPI
+NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
+                   IN PIRP Irp)
 {
-    PLIST_ENTRY current_entry;
-    PNPFS_FCB Fcb;
-    PNPFS_CCB ServerCcb;
-    PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
-    LARGE_INTEGER TimeOut;
+    PIO_STACK_LOCATION IoStack;
+    ULONG InLength, NameLength;
+    UNICODE_STRING SourceString, Prefix;
+    ULONG NamedPipeEnd;
+    PNP_CCB Ccb;
+    PFILE_PIPE_WAIT_FOR_BUFFER Buffer;
     NTSTATUS Status;
-#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
-    PNPFS_VCB Vcb;
-    UNICODE_STRING PipeName;
-#endif
+    NODE_TYPE_CODE NodeTypeCode;
+    PLIST_ENTRY NextEntry;
+    PNP_FCB Fcb;
+    PWCHAR OriginalBuffer;
+    PAGED_CODE();
 
-    DPRINT("NpfsWaitPipe\n");
-
-    WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    InLength = IoStack->Parameters.FileSystemControl.InputBufferLength;
 
-#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
-    /* Fail, if the CCB does not represent the root directory */
-    if (Ccb->Type != CCB_DIRECTORY)
-        return STATUS_ILLEGAL_FUNCTION;
+    SourceString.Buffer = NULL;
 
-    /* Calculate the pipe name length and allocate the buffer */
-    PipeName.Length = WaitPipe->NameLength + sizeof(WCHAR);
-    PipeName.MaximumLength = PipeName.Length + sizeof(WCHAR);
-    PipeName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
-                                            PipeName.MaximumLength,
-                                            TAG_NPFS_NAMEBLOCK);
-    if (PipeName.Buffer == NULL)
+    if (NpDecodeFileObject(IoStack->FileObject,
+                           NULL,
+                           &Ccb,
+                           &NamedPipeEnd) != NPFS_NTC_ROOT_DCB)
     {
-        DPRINT1("Could not allocate memory for the pipe name!\n");
-        return STATUS_NO_MEMORY;
+        Status = STATUS_ILLEGAL_FUNCTION;
+        goto Quickie;
     }
 
-    /* Copy the pipe name into the buffer, prepend a backslash and append a 0 character */
-    PipeName.Buffer[0] = L'\\';
-    RtlCopyMemory(&PipeName.Buffer[1],
-                  &WaitPipe->Name[0],
-                  WaitPipe->NameLength);
-    PipeName.Buffer[PipeName.Length / sizeof(WCHAR)] = 0;
-
-    DPRINT("Waiting for Pipe %wZ\n", &PipeName);
+    Buffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+    if (InLength < sizeof(*Buffer))
+    {
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
 
-    /* Get the VCB */
-    Vcb = Ccb->Fcb->Vcb;
+    NameLength = Buffer->NameLength;
+    if ((NameLength > (0xFFFF - sizeof(UNICODE_NULL))) ||
+        ((NameLength + FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name)) > InLength))
+    {
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
 
-    /* Lock the pipe list */
-    KeLockMutex(&Vcb->PipeListLock);
+    SourceString.Length = (USHORT)NameLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
+    SourceString.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                SourceString.Length,
+                                                NPFS_WRITE_BLOCK_TAG);
+    if (!SourceString.Buffer)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Quickie;
+    }
 
-    /* File a pipe with the given name */
-    Fcb = NpfsFindPipe(Vcb,
-                       &PipeName);
+    SourceString.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
+    RtlCopyMemory(&SourceString.Buffer[1], Buffer->Name, Buffer->NameLength);
 
-    /* Unlock the pipe list */
-    KeUnlockMutex(&Vcb->PipeListLock);
+    Status = STATUS_SUCCESS;
+    OriginalBuffer = SourceString.Buffer;
+    //Status = NpTranslateAlias(&SourceString);
+    if (!NT_SUCCESS(Status)) goto Quickie;
 
-    /* Release the pipe name buffer */
-    ExFreePoolWithTag(PipeName.Buffer, TAG_NPFS_NAMEBLOCK);
+    Fcb = NpFindPrefix(&SourceString, 1, &Prefix);
+    Fcb = (PNP_FCB)((ULONG_PTR)Fcb & ~1);
 
-    /* Fail if not pipe was found */
-    if (Fcb == NULL)
+    NodeTypeCode = Fcb ? Fcb->NodeType : 0;
+    if (NodeTypeCode != NPFS_NTC_FCB)
     {
-        DPRINT("No pipe found!\n");
-        return STATUS_OBJECT_NAME_NOT_FOUND;
+        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        goto Quickie;
     }
 
-    DPRINT("Fcb %p\n", Fcb);
-#else
-    Fcb = Ccb->Fcb;
-
-    if (Ccb->PipeState != 0)
+    for (NextEntry = Fcb->CcbList.Flink;
+         NextEntry != &Fcb->CcbList;
+         NextEntry = NextEntry->Flink)
     {
-        DPRINT("Pipe is not in passive (waiting) state!\n");
-        return STATUS_UNSUCCESSFUL;
+        Ccb = CONTAINING_RECORD(NextEntry, NP_CCB, CcbEntry);
+        if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) break;
     }
-#endif
 
-    /* search for listening server */
-    current_entry = Fcb->ServerCcbListHead.Flink;
-    while (current_entry != &Fcb->ServerCcbListHead)
+    if (NextEntry != &Fcb->CcbList)
     {
-        ServerCcb = CONTAINING_RECORD(current_entry,
-            NPFS_CCB,
-            CcbListEntry);
-
-        if (ServerCcb->PipeState == FILE_PIPE_LISTENING_STATE)
-        {
-            /* found a listening server CCB */
-            DPRINT("Listening server CCB found -- connecting\n");
-#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
-            NpfsDereferenceFcb(Fcb);
-#endif
-            return STATUS_SUCCESS;
-        }
-
-        current_entry = current_entry->Flink;
+        Status = STATUS_SUCCESS;
     }
-
-    /* No listening server fcb found */
-
-    /* If no timeout specified, use the default one */
-    if (WaitPipe->TimeoutSpecified)
-        TimeOut = WaitPipe->Timeout;
     else
-        TimeOut = Fcb->TimeOut;
-#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
-    NpfsDereferenceFcb(Fcb);
-#endif
-
-    /* Wait for one */
-    Status = KeWaitForSingleObject(&Ccb->ConnectEvent,
-        UserRequest,
-        Irp->RequestorMode,
-        (Ccb->FileObject->Flags & FO_ALERTABLE_IO) != 0,
-        &TimeOut);
-    if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC) || (Status == STATUS_ALERTED))
-        Status = STATUS_CANCELLED;
-
-    DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status);
+    {
+        Status = NpAddWaiter(&NpVcb->WaitQueue,
+                             Fcb->Timeout,
+                             Irp,
+                             OriginalBuffer == SourceString.Buffer ?
+                             NULL : &SourceString);
+    }
 
+Quickie:
+    if (SourceString.Buffer) ExFreePool(SourceString.Buffer);
     return Status;
 }
 
-
-/*
-* FUNCTION: Return current state of a pipe
-* ARGUMENTS:
-*     Irp   = Pointer to I/O request packet
-*     IrpSp = Pointer to current stack location of Irp
-* RETURNS:
-*     Status of operation
-*/
-
-/*
-* FUNCTION: Peek at a pipe (get information about messages)
-* ARGUMENTS:
-*     Irp = Pointer to I/O request packet
-*     IoStack = Pointer to current stack location of Irp
-* RETURNS:
-*     Status of operation
-*/
-static NTSTATUS
-NpfsPeekPipe(PIRP Irp,
-             PIO_STACK_LOCATION IoStack)
+NTSTATUS
+NTAPI
+NpCommonFileSystemControl(IN PDEVICE_OBJECT DeviceObject,
+                          IN PIRP Irp)
 {
-    ULONG OutputBufferLength;
-    ULONG ReturnLength = 0;
-    PFILE_PIPE_PEEK_BUFFER Reply;
-    //PNPFS_FCB Fcb;
-    PNPFS_CCB Ccb;
+    ULONG Fsctl;
+    BOOLEAN Overflow = FALSE;
+    LIST_ENTRY DeferredList;
     NTSTATUS Status;
-    ULONG MessageCount = 0;
-    ULONG MessageLength;
-    ULONG ReadDataAvailable;
-    PVOID BufferPtr;
+    PAGED_CODE();
 
-    DPRINT("NpfsPeekPipe\n");
+    InitializeListHead(&DeferredList);
+    Fsctl = IoGetCurrentIrpStackLocation(Irp)->Parameters.FileSystemControl.FsControlCode;
 
-    OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
-    DPRINT("OutputBufferLength: %lu\n", OutputBufferLength);
-
-    /* Validate parameters */
-    if (OutputBufferLength < (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]))
+    switch (Fsctl)
     {
-        DPRINT1("Buffer too small\n");
-        return STATUS_INVALID_PARAMETER;
-    }
+        case FSCTL_PIPE_PEEK:
+            NpAcquireExclusiveVcb();
+            Status = NpPeek(DeviceObject, Irp, &DeferredList);
+            break;
 
-    Ccb = IoStack->FileObject->FsContext2;
-    Reply = Irp->AssociatedIrp.SystemBuffer;
-    //Fcb = Ccb->Fcb;
+        case FSCTL_PIPE_INTERNAL_WRITE:
+            NpAcquireSharedVcb();
+            Status = NpInternalWrite(DeviceObject, Irp, &DeferredList);
+            break;
 
+        case FSCTL_PIPE_TRANSCEIVE:
+            NpAcquireSharedVcb();
+            Status = NpTransceive(DeviceObject, Irp, &DeferredList);
+            break;
 
-    Reply->NamedPipeState = Ccb->PipeState;
+        case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
+            NpAcquireSharedVcb();
+            Status = NpInternalTransceive(DeviceObject, Irp, &DeferredList);
+            break;
 
-    Reply->ReadDataAvailable = Ccb->ReadDataAvailable;
-    DPRINT("ReadDataAvailable: %lu\n", Ccb->ReadDataAvailable);
+        case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
+            Overflow = TRUE;
+            // on purpose
 
-    ExAcquireFastMutex(&Ccb->DataListLock);
-    BufferPtr = Ccb->ReadPtr;
-    DPRINT("BufferPtr = %p\n", BufferPtr);
-    if (Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE)
-    {
-        DPRINT("Byte Stream Mode\n");
-        Reply->MessageLength = Ccb->ReadDataAvailable;
-        DPRINT("Reply->MessageLength  %lu\n", Reply->MessageLength);
-        MessageCount = 1;
+        case FSCTL_PIPE_INTERNAL_READ:
+            NpAcquireSharedVcb();
+            Status = NpInternalRead(DeviceObject, Irp, Overflow, &DeferredList);
+            break;
 
-        if (OutputBufferLength >= (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[Ccb->ReadDataAvailable]))
-        {
-            RtlCopyMemory(Reply->Data, BufferPtr, Ccb->ReadDataAvailable);
-            ReturnLength = Ccb->ReadDataAvailable;
-        }
-    }
-    else
-    {
-        DPRINT("Message Mode\n");
-        ReadDataAvailable = Ccb->ReadDataAvailable;
+        case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
 
-        if (ReadDataAvailable > 0)
-        {
-            RtlCopyMemory(&Reply->MessageLength,
-                          BufferPtr,
-                          sizeof(Reply->MessageLength));
+            NpAcquireSharedVcb();
+            Status = NpQueryClientProcess(DeviceObject, Irp);
+            break;
 
-            while ((ReadDataAvailable > 0) && (BufferPtr < Ccb->WritePtr))
-            {
-                RtlCopyMemory(&MessageLength, BufferPtr, sizeof(MessageLength));
-
-                ASSERT(MessageLength > 0);
-
-                DPRINT("MessageLength = %lu\n", MessageLength);
-                ReadDataAvailable -= MessageLength;
-                MessageCount++;
-
-                /* If its the first message, copy the Message if the size of buffer is large enough */
-                if (MessageCount == 1)
-                {
-                    if (OutputBufferLength >= (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[MessageLength]))
-                    {
-                        RtlCopyMemory(Reply->Data,
-                                      (PVOID)((ULONG_PTR)BufferPtr + sizeof(MessageLength)),
-                                      MessageLength);
-                        ReturnLength = MessageLength;
-                    }
-                }
-
-                BufferPtr = (PVOID)((ULONG_PTR)BufferPtr + sizeof(MessageLength) + MessageLength);
-                DPRINT("BufferPtr = %p\n", BufferPtr);
-                DPRINT("ReadDataAvailable: %lu\n", ReadDataAvailable);
-            }
+        case FSCTL_PIPE_ASSIGN_EVENT:
 
-            if (ReadDataAvailable != 0)
-            {
-                DPRINT1("Possible memory corruption.\n");
-                ASSERT(FALSE);
-            }
-        }
-    }
-    ExReleaseFastMutex(&Ccb->DataListLock);
+            NpAcquireExclusiveVcb();
+            Status = NpAssignEvent(DeviceObject, Irp);
+            break;
 
-    Reply->NumberOfMessages = MessageCount;
+        case FSCTL_PIPE_DISCONNECT:
 
-    Irp->IoStatus.Information = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[ReturnLength]);
-    Irp->IoStatus.Status = STATUS_SUCCESS;
+            NpAcquireExclusiveVcb();
+            Status = NpDisconnect(DeviceObject, Irp, &DeferredList);
+            break;
 
-    Status = STATUS_SUCCESS;
+        case FSCTL_PIPE_LISTEN:
 
-    DPRINT("NpfsPeekPipe done\n");
+            NpAcquireSharedVcb();
+            Status = NpListen(DeviceObject, Irp, &DeferredList);
+            break;
 
-    return Status;
-}
+        case FSCTL_PIPE_QUERY_EVENT:
 
+            NpAcquireExclusiveVcb();
+            Status = NpQueryEvent(DeviceObject, Irp);
+            break;
 
-NTSTATUS NTAPI
-NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
-                      PIRP Irp)
-{
-    PIO_STACK_LOCATION IoStack;
-    PFILE_OBJECT FileObject;
-    NTSTATUS Status;
-    //PNPFS_VCB Vcb;
-    PNPFS_FCB Fcb;
-    PNPFS_CCB Ccb;
+        case FSCTL_PIPE_WAIT:
 
-    DPRINT("NpfsFileSystemContol(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
+            NpAcquireExclusiveVcb();
+            Status = NpWaitForNamedPipe(DeviceObject, Irp);
+            break;
 
-    //Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DPRINT("IoStack: %p\n", IoStack);
-    FileObject = IoStack->FileObject;
-    DPRINT("FileObject: %p\n", FileObject);
-    Ccb = FileObject->FsContext2;
-    DPRINT("CCB: %p\n", Ccb);
-    Fcb = Ccb->Fcb;
-    DPRINT("Pipe: %p\n", Fcb);
-    DPRINT("PipeName: %wZ\n", &Fcb->PipeName);
-
-    Irp->IoStatus.Information = 0;
-
-    switch (IoStack->Parameters.FileSystemControl.FsControlCode)
-    {
-    case FSCTL_PIPE_ASSIGN_EVENT:
-        DPRINT1("Assign event not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_DISCONNECT:
-        DPRINT("Disconnecting pipe %wZ\n", &Fcb->PipeName);
-        Status = NpfsDisconnectPipe(Ccb);
-        break;
-
-    case FSCTL_PIPE_LISTEN:
-        DPRINT("Connecting pipe %wZ\n", &Fcb->PipeName);
-        Status = NpfsConnectPipe(Irp, Ccb);
-        break;
-
-    case FSCTL_PIPE_PEEK:
-        DPRINT("Peeking pipe %wZ\n", &Fcb->PipeName);
-        Status = NpfsPeekPipe(Irp, (PIO_STACK_LOCATION)IoStack);
-        break;
-
-    case FSCTL_PIPE_QUERY_EVENT:
-        DPRINT1("Query event not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_TRANSCEIVE:
-        /* If you implement this, please remove the workaround in
-        lib/kernel32/file/npipe.c function TransactNamedPipe() */
-        DPRINT1("Transceive not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_WAIT:
-        DPRINT("Waiting for pipe %wZ\n", &Fcb->PipeName);
-        Status = NpfsWaitPipe(Irp, Ccb);
-        break;
-
-    case FSCTL_PIPE_IMPERSONATE:
-        DPRINT1("Impersonate not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_SET_CLIENT_PROCESS:
-        DPRINT1("Set client process not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
-        DPRINT1("Query client process not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_INTERNAL_READ:
-        DPRINT1("Internal read not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_INTERNAL_WRITE:
-        DPRINT1("Internal write not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
-        DPRINT1("Internal transceive not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
-        DPRINT1("Internal read overflow not implemented\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-
-    default:
-        DPRINT1("Unrecognized IoControlCode: %x\n",
-            IoStack->Parameters.FileSystemControl.FsControlCode);
-        Status = STATUS_UNSUCCESSFUL;
-    }
+        case FSCTL_PIPE_IMPERSONATE:
 
-    if (Status != STATUS_PENDING)
-    {
-        Irp->IoStatus.Status = Status;
+            NpAcquireExclusiveVcb();
+            Status = NpImpersonate(DeviceObject, Irp);
+            break;
+
+        case FSCTL_PIPE_SET_CLIENT_PROCESS:
+            NpAcquireExclusiveVcb();
+            Status = NpSetClientProcess(DeviceObject, Irp);
+            break;
 
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        default:
+            return STATUS_NOT_SUPPORTED;
     }
 
+    NpReleaseVcb();
+    NpCompleteDeferredIrps(&DeferredList);
+
     return Status;
 }
 
-
-NTSTATUS NTAPI
-NpfsFlushBuffers(PDEVICE_OBJECT DeviceObject,
-                 PIRP Irp)
+NTSTATUS
+NTAPI
+NpFsdFileSystemControl(IN PDEVICE_OBJECT DeviceObject,
+                       IN PIRP Irp)
 {
-    /* FIXME: Implement */
-    UNREFERENCED_PARAMETER(DeviceObject);
+    NTSTATUS Status;
+    PAGED_CODE();
 
-    Irp->IoStatus.Status = STATUS_SUCCESS;
-    Irp->IoStatus.Information = 0;
+    FsRtlEnterFileSystem();
 
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    Status = NpCommonFileSystemControl(DeviceObject, Irp);
 
-    return STATUS_SUCCESS;
+    FsRtlExitFileSystem();
+
+    if (Status != STATUS_PENDING)
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
+    }
+
+    return Status;
 }
 
 /* EOF */