- Prepare a playground for a new NPFS driver implementation.
authorAleksey Bragin <aleksey@reactos.org>
Fri, 4 May 2007 10:15:00 +0000 (10:15 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Fri, 4 May 2007 10:15:00 +0000 (10:15 +0000)
svn path=/trunk/; revision=26631

reactos/drivers/filesystems/npfs_new/create.c [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/finfo.c [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/fsctrl.c [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/npfs.c [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/npfs.h [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/npfs.rbuild [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/npfs.rc [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/rw.c [new file with mode: 0644]
reactos/drivers/filesystems/npfs_new/volume.c [new file with mode: 0644]

diff --git a/reactos/drivers/filesystems/npfs_new/create.c b/reactos/drivers/filesystems/npfs_new/create.c
new file mode 100644 (file)
index 0000000..efbfdaf
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * PROJECT:         ReactOS Drivers
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/filesystems/npfs/create.c
+ * PURPOSE:         Named pipe filesystem
+ * PROGRAMMERS:     
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "npfs.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+/* EOF */
diff --git a/reactos/drivers/filesystems/npfs_new/finfo.c b/reactos/drivers/filesystems/npfs_new/finfo.c
new file mode 100644 (file)
index 0000000..01d1404
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * PROJECT:         ReactOS Drivers
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/filesystems/npfs/finfo.c
+ * PURPOSE:         Named pipe filesystem
+ * PROGRAMMERS:     
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "npfs.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+/* EOF */
diff --git a/reactos/drivers/filesystems/npfs_new/fsctrl.c b/reactos/drivers/filesystems/npfs_new/fsctrl.c
new file mode 100644 (file)
index 0000000..5469410
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * PROJECT:         ReactOS Drivers
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/filesystems/npfs/fsctrl.c
+ * PURPOSE:         Named pipe filesystem
+ * PROGRAMMERS:     
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "npfs.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+
+/* EOF */
diff --git a/reactos/drivers/filesystems/npfs_new/npfs.c b/reactos/drivers/filesystems/npfs_new/npfs.c
new file mode 100644 (file)
index 0000000..93342df
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * PROJECT:         ReactOS Drivers
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/filesystems/npfs/npfs.c
+ * PURPOSE:         Named pipe filesystem
+ * PROGRAMMERS:     
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "npfs.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS STDCALL
+DriverEntry(PDRIVER_OBJECT DriverObject,
+                       PUNICODE_STRING RegistryPath)
+{
+       PNPFS_DEVICE_EXTENSION DeviceExtension;
+       PDEVICE_OBJECT DeviceObject;
+       UNICODE_STRING DeviceName;
+       NTSTATUS Status;
+
+       DPRINT("Named Pipe FSD 0.0.2\n");
+
+       ASSERT (sizeof(NPFS_CONTEXT) <= FIELD_OFFSET(IRP, Tail.Overlay.DriverContext));
+       ASSERT (sizeof(NPFS_WAITER_ENTRY) <= FIELD_OFFSET(IRP, Tail.Overlay.DriverContext));
+
+       DriverObject->MajorFunction[IRP_MJ_CREATE] = NpfsCreate;
+       DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] =
+               NpfsCreateNamedPipe;
+       DriverObject->MajorFunction[IRP_MJ_CLOSE] = NpfsClose;
+       DriverObject->MajorFunction[IRP_MJ_READ] = NpfsRead;
+       DriverObject->MajorFunction[IRP_MJ_WRITE] = NpfsWrite;
+       DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
+               NpfsQueryInformation;
+       DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
+               NpfsSetInformation;
+       DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
+               NpfsQueryVolumeInformation;
+       DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NpfsCleanup;
+       DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = NpfsFlushBuffers;
+       //   DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
+       //     NpfsDirectoryControl;
+       DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
+               NpfsFileSystemControl;
+       //   DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] =
+       //     NpfsQuerySecurity;
+       //   DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] =
+       //     NpfsSetSecurity;
+
+       DriverObject->DriverUnload = NULL;
+
+       RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");
+       Status = IoCreateDevice(DriverObject,
+               sizeof(NPFS_DEVICE_EXTENSION),
+               &DeviceName,
+               FILE_DEVICE_NAMED_PIPE,
+               0,
+               FALSE,
+               &DeviceObject);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("Failed to create named pipe device! (Status %x)\n", Status);
+               return Status;
+       }
+
+       /* initialize the device object */
+       DeviceObject->Flags = DO_DIRECT_IO;
+
+       /* initialize the device extension */
+       DeviceExtension = DeviceObject->DeviceExtension;
+       InitializeListHead(&DeviceExtension->PipeListHead);
+       InitializeListHead(&DeviceExtension->ThreadListHead);
+       KeInitializeMutex(&DeviceExtension->PipeListLock, 0);
+       DeviceExtension->EmptyWaiterCount = 0;
+
+       /* set the size quotas */
+       DeviceExtension->MinQuota = PAGE_SIZE;
+       DeviceExtension->DefaultQuota = 8 * PAGE_SIZE;
+       DeviceExtension->MaxQuota = 64 * PAGE_SIZE;
+
+       return STATUS_SUCCESS;
+}
+
+/* EOF */
diff --git a/reactos/drivers/filesystems/npfs_new/npfs.h b/reactos/drivers/filesystems/npfs_new/npfs.h
new file mode 100644 (file)
index 0000000..522cd34
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef __DRIVERS_FS_NP_NPFS_H
+#define __DRIVERS_FS_NP_NPFS_H
+
+#include <ntifs.h>
+#include <ndk/iotypes.h>
+
+typedef struct _NPFS_DEVICE_EXTENSION
+{
+       LIST_ENTRY PipeListHead;
+       LIST_ENTRY ThreadListHead;
+       KMUTEX PipeListLock;
+       ULONG EmptyWaiterCount;
+       ULONG MinQuota;
+       ULONG DefaultQuota;
+       ULONG MaxQuota;
+} NPFS_DEVICE_EXTENSION, *PNPFS_DEVICE_EXTENSION;
+
+typedef struct _NPFS_FCB
+{
+       FSRTL_COMMON_FCB_HEADER RFCB;
+       UNICODE_STRING PipeName;
+       LIST_ENTRY PipeListEntry;
+       KMUTEX CcbListLock;
+       LIST_ENTRY ServerCcbListHead;
+       LIST_ENTRY ClientCcbListHead;
+       LIST_ENTRY WaiterListHead;
+       LIST_ENTRY EmptyBufferListHead;
+       ULONG PipeType;
+       ULONG ReadMode;
+       ULONG WriteMode;
+       ULONG CompletionMode;
+       ULONG PipeConfiguration;
+       ULONG MaximumInstances;
+       ULONG CurrentInstances;
+       ULONG InboundQuota;
+       ULONG OutboundQuota;
+       LARGE_INTEGER TimeOut;
+} NPFS_FCB, *PNPFS_FCB;
+
+typedef struct _NPFS_CCB
+{
+       LIST_ENTRY CcbListEntry;
+       struct _NPFS_CCB* OtherSide;
+       struct ETHREAD *Thread;
+       PNPFS_FCB Fcb;
+       KEVENT ConnectEvent;
+       KEVENT ReadEvent;
+       KEVENT WriteEvent;
+       ULONG PipeEnd;
+       ULONG PipeState;
+       ULONG ReadDataAvailable;
+       ULONG WriteQuotaAvailable;
+
+       LIST_ENTRY ReadRequestListHead;
+
+       PVOID Data;
+       PVOID ReadPtr;
+       PVOID WritePtr;
+       ULONG MaxDataLength;
+
+       FAST_MUTEX DataListLock;        /* Data queue lock */
+} NPFS_CCB, *PNPFS_CCB;
+
+typedef struct _NPFS_CONTEXT
+{
+       LIST_ENTRY ListEntry;
+       PKEVENT WaitEvent;
+} NPFS_CONTEXT, *PNPFS_CONTEXT;
+
+typedef struct _NPFS_THREAD_CONTEXT
+{
+       ULONG Count;
+       KEVENT Event;
+       PNPFS_DEVICE_EXTENSION DeviceExt;
+       LIST_ENTRY ListEntry;
+       PVOID WaitObjectArray[MAXIMUM_WAIT_OBJECTS];
+       KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS];
+       PIRP WaitIrpArray[MAXIMUM_WAIT_OBJECTS];
+} NPFS_THREAD_CONTEXT, *PNPFS_THREAD_CONTEXT;
+
+typedef struct _NPFS_WAITER_ENTRY
+{
+       LIST_ENTRY Entry;
+       PNPFS_CCB Ccb;
+} NPFS_WAITER_ENTRY, *PNPFS_WAITER_ENTRY;
+
+
+extern NPAGED_LOOKASIDE_LIST NpfsPipeDataLookasideList;
+
+
+#define KeLockMutex(x) KeWaitForSingleObject(x, \
+       UserRequest, \
+       KernelMode, \
+       FALSE, \
+       NULL);
+
+#define KeUnlockMutex(x) KeReleaseMutex(x, FALSE);
+
+#define PAGE_ROUND_UP(x) ( (((ULONG_PTR)x)%PAGE_SIZE) ? ((((ULONG_PTR)x)&(~(PAGE_SIZE-1)))+PAGE_SIZE) : ((ULONG_PTR)x) )
+
+NTSTATUS STDCALL NpfsCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS STDCALL NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS STDCALL NpfsCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS STDCALL NpfsClose(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL NpfsRead(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS STDCALL NpfsWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL NpfsFlushBuffers(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL NpfsQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS STDCALL NpfsSetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL NpfsQueryVolumeInformation (PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL
+DriverEntry(PDRIVER_OBJECT DriverObject,
+                       PUNICODE_STRING RegistryPath);
+
+#endif /* __DRIVERS_FS_NP_NPFS_H */
diff --git a/reactos/drivers/filesystems/npfs_new/npfs.rbuild b/reactos/drivers/filesystems/npfs_new/npfs.rbuild
new file mode 100644 (file)
index 0000000..4606e74
--- /dev/null
@@ -0,0 +1,15 @@
+<module name="npfs" type="kernelmodedriver" installbase="system32/drivers" installname="npfs.sys">
+       <include base="npfs">.</include>
+       <define name="__USE_W32API" />
+       <define name="__NO_CTYPE_INLINES" />
+       <library>ntoskrnl</library>
+       <library>hal</library>
+       <file>create.c</file>
+       <file>finfo.c</file>
+       <file>fsctrl.c</file>
+       <file>npfs.c</file>
+       <file>rw.c</file>
+       <file>volume.c</file>
+       <file>npfs.rc</file>
+       <pch>npfs.h</pch>
+</module>
diff --git a/reactos/drivers/filesystems/npfs_new/npfs.rc b/reactos/drivers/filesystems/npfs_new/npfs.rc
new file mode 100644 (file)
index 0000000..d1c918c
--- /dev/null
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL\r
+#define REACTOS_STR_FILE_DESCRIPTION   "Named Pipe IFS Driver\0"\r
+#define REACTOS_STR_INTERNAL_NAME      "npfs\0"\r
+#define REACTOS_STR_ORIGINAL_FILENAME  "npfs.sys\0"\r
+#include <reactos/version.rc>\r
diff --git a/reactos/drivers/filesystems/npfs_new/rw.c b/reactos/drivers/filesystems/npfs_new/rw.c
new file mode 100644 (file)
index 0000000..ba011d8
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * PROJECT:         ReactOS Drivers
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/filesystems/npfs/rw.c
+ * PURPOSE:         Named pipe filesystem
+ * PROGRAMMERS:     
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "npfs.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+#ifndef NDEBUG
+VOID HexDump(PUCHAR Buffer, ULONG Length)
+{
+       CHAR Line[65];
+       UCHAR ch;
+       const char Hex[] = "0123456789ABCDEF";
+       int i, j;
+
+       DbgPrint("---------------\n");
+
+       for (i = 0; i < Length; i+= 16)
+       {
+               memset(Line, ' ', 64);
+               Line[64] = 0;
+
+               for (j = 0; j < 16 && j + i < Length; j++)
+               {
+                       ch = Buffer[i + j];
+                       Line[3*j + 0] = Hex[ch >> 4];
+                       Line[3*j + 1] = Hex[ch & 0x0f];
+                       Line[48 + j] = isprint(ch) ? ch : '.';
+               }
+               DbgPrint("%s\n", Line);
+       }
+       DbgPrint("---------------\n");
+}
+#endif
+
+static VOID STDCALL
+NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
+                                                  IN PIRP Irp)
+{
+       PNPFS_CONTEXT Context;
+       PNPFS_DEVICE_EXTENSION DeviceExt;
+       PIO_STACK_LOCATION IoStack;
+       PNPFS_CCB Ccb;
+       BOOLEAN Complete = FALSE;
+
+       DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
+
+       IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+       Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
+       DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+       IoStack = IoGetCurrentIrpStackLocation(Irp);
+       Ccb = IoStack->FileObject->FsContext2;
+
+       KeLockMutex(&DeviceExt->PipeListLock);
+       ExAcquireFastMutex(&Ccb->DataListLock);
+       switch(IoStack->MajorFunction)
+       {
+       case IRP_MJ_READ:
+               if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
+               {
+                       /* we are not the first in the list, remove an complete us */
+                       RemoveEntryList(&Context->ListEntry);
+                       Complete = TRUE;
+               }
+               else
+               {
+                       KeSetEvent(&Ccb->ReadEvent, IO_NO_INCREMENT, FALSE);
+               }
+               break;
+       default:
+               KEBUGCHECK(0);
+       }
+       ExReleaseFastMutex(&Ccb->DataListLock);
+       KeUnlockMutex(&DeviceExt->PipeListLock);
+       if (Complete)
+       {
+               Irp->IoStatus.Status = STATUS_CANCELLED;
+               Irp->IoStatus.Information = 0;
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       }
+}
+
+static VOID STDCALL
+NpfsWaiterThread(PVOID InitContext)
+{
+       PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
+       ULONG CurrentCount;
+       ULONG Count = 0;
+       PIRP Irp = NULL;
+       PIRP NextIrp;
+       NTSTATUS Status;
+       BOOLEAN Terminate = FALSE;
+       BOOLEAN Cancel = FALSE;
+       PIO_STACK_LOCATION IoStack = NULL;
+       PNPFS_CONTEXT Context;
+       PNPFS_CONTEXT NextContext;
+       PNPFS_CCB Ccb;
+
+       KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
+
+       while (1)
+       {
+               CurrentCount = ThreadContext->Count;
+               KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
+               if (Irp)
+               {
+                       if (Cancel)
+                       {
+                               Irp->IoStatus.Status = STATUS_CANCELLED;
+                               Irp->IoStatus.Information = 0;
+                               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                       }
+                       else
+                       {
+                               switch (IoStack->MajorFunction)
+                               {
+                               case IRP_MJ_READ:
+                                       NpfsRead(IoStack->DeviceObject, Irp);
+                                       break;
+                               default:
+                                       KEBUGCHECK(0);
+                               }
+                       }
+               }
+               if (Terminate)
+               {
+                       break;
+               }
+               Status = KeWaitForMultipleObjects(CurrentCount,
+                       ThreadContext->WaitObjectArray,
+                       WaitAny,
+                       Executive,
+                       KernelMode,
+                       FALSE,
+                       NULL,
+                       ThreadContext->WaitBlockArray);
+               if (!NT_SUCCESS(Status))
+               {
+                       KEBUGCHECK(0);
+               }
+               KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
+               Count = Status - STATUS_SUCCESS;
+               ASSERT (Count < CurrentCount);
+               if (Count > 0)
+               {
+                       Irp = ThreadContext->WaitIrpArray[Count];
+                       ThreadContext->Count--;
+                       ThreadContext->DeviceExt->EmptyWaiterCount++;
+                       ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
+                       ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
+
+                       Cancel = (NULL == IoSetCancelRoutine(Irp, NULL));
+                       Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
+                       IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+                       if (Cancel)
+                       {
+                               Ccb = IoStack->FileObject->FsContext2;
+                               ExAcquireFastMutex(&Ccb->DataListLock);
+                               RemoveEntryList(&Context->ListEntry);
+                               switch (IoStack->MajorFunction)
+                               {
+                               case IRP_MJ_READ:
+                                       if (!IsListEmpty(&Ccb->ReadRequestListHead))
+                                       {
+                                               /* put the next request on the wait list */
+                                               NextContext = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
+                                               ThreadContext->WaitObjectArray[ThreadContext->Count] = NextContext->WaitEvent;
+                                               NextIrp = CONTAINING_RECORD(NextContext, IRP, Tail.Overlay.DriverContext);
+                                               ThreadContext->WaitIrpArray[ThreadContext->Count] = NextIrp;
+                                               ThreadContext->Count++;
+                                               ThreadContext->DeviceExt->EmptyWaiterCount--;
+                                       }
+                                       break;
+                               default:
+                                       KEBUGCHECK(0);
+                               }
+                               ExReleaseFastMutex(&Ccb->DataListLock);
+                       }
+               }
+               else
+               {
+                       /* someone has add a new wait request */
+                       Irp = NULL;
+               }
+               if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
+               {
+                       /* it exist an other thread with empty wait slots, we can remove our thread from the list */
+                       RemoveEntryList(&ThreadContext->ListEntry);
+                       ThreadContext->DeviceExt->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
+                       Terminate = TRUE;
+               }
+       }
+       ExFreePool(ThreadContext);
+}
+
+static NTSTATUS
+NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
+                                                          IN PIRP Irp)
+{
+       PLIST_ENTRY ListEntry;
+       PNPFS_THREAD_CONTEXT ThreadContext = NULL;
+       NTSTATUS Status;
+       HANDLE hThread;
+       KIRQL oldIrql;
+
+       PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
+       PNPFS_DEVICE_EXTENSION DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+       DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+       KeLockMutex(&DeviceExt->PipeListLock);
+
+       ListEntry = DeviceExt->ThreadListHead.Flink;
+       while (ListEntry != &DeviceExt->ThreadListHead)
+       {
+               ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
+               if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
+               {
+                       break;
+               }
+               ListEntry = ListEntry->Flink;
+       }
+       if (ListEntry == &DeviceExt->ThreadListHead)
+       {
+               ThreadContext = ExAllocatePool(NonPagedPool, sizeof(NPFS_THREAD_CONTEXT));
+               if (ThreadContext == NULL)
+               {
+                       KeUnlockMutex(&DeviceExt->PipeListLock);
+                       return STATUS_NO_MEMORY;
+               }
+               ThreadContext->DeviceExt = DeviceExt;
+               KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
+               ThreadContext->Count = 1;
+               ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
+
+
+               DPRINT("Creating a new system thread for waiting read/write requests\n");
+
+               Status = PsCreateSystemThread(&hThread,
+                       THREAD_ALL_ACCESS,
+                       NULL,
+                       NULL,
+                       NULL,
+                       NpfsWaiterThread,
+                       (PVOID)ThreadContext);
+               if (!NT_SUCCESS(Status))
+               {
+                       ExFreePool(ThreadContext);
+                       KeUnlockMutex(&DeviceExt->PipeListLock);
+                       return Status;
+               }
+               InsertHeadList(&DeviceExt->ThreadListHead, &ThreadContext->ListEntry);
+               DeviceExt->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
+       }
+       IoMarkIrpPending(Irp);
+
+       IoAcquireCancelSpinLock(&oldIrql);
+       if (Irp->Cancel)
+       {
+               IoReleaseCancelSpinLock(oldIrql);
+               Status = STATUS_CANCELLED;
+       }
+       else
+       {
+               (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
+               IoReleaseCancelSpinLock(oldIrql);
+               ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
+               ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
+               ThreadContext->Count++;
+               DeviceExt->EmptyWaiterCount--;
+               KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
+               Status = STATUS_SUCCESS;
+       }
+       KeUnlockMutex(&DeviceExt->PipeListLock);
+       return Status;
+}
+
+NTSTATUS STDCALL
+NpfsRead(IN PDEVICE_OBJECT DeviceObject,
+                IN PIRP Irp)
+{
+       PFILE_OBJECT FileObject;
+       NTSTATUS Status;
+       NTSTATUS OriginalStatus = STATUS_SUCCESS;
+       PNPFS_CCB Ccb;
+       PNPFS_CONTEXT Context;
+       KEVENT Event;
+       ULONG Length;
+       ULONG Information = 0;
+       ULONG CopyLength;
+       ULONG TempLength;
+       BOOLEAN IsOriginalRequest = TRUE;
+       PVOID Buffer;
+
+       DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+       if (Irp->MdlAddress == NULL)
+       {
+               DPRINT("Irp->MdlAddress == NULL\n");
+               Status = STATUS_UNSUCCESSFUL;
+               Irp->IoStatus.Information = 0;
+               goto done;
+       }
+
+       FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
+       Ccb = FileObject->FsContext2;
+       Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
+
+       if (Ccb->OtherSide == NULL)
+       {
+               DPRINT("Pipe is NOT connected!\n");
+               if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
+                       Status = STATUS_PIPE_LISTENING;
+               else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
+                       Status = STATUS_PIPE_DISCONNECTED;
+               else
+                       Status = STATUS_UNSUCCESSFUL;
+               Irp->IoStatus.Information = 0;
+               goto done;
+       }
+
+       if (Ccb->Data == NULL)
+       {
+               DPRINT1("Pipe is NOT readable!\n");
+               Status = STATUS_UNSUCCESSFUL;
+               Irp->IoStatus.Information = 0;
+               goto done;
+       }
+
+       ExAcquireFastMutex(&Ccb->DataListLock);
+
+       if (IoIsOperationSynchronous(Irp))
+       {
+               InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
+               if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
+               {
+                       KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+                       Context->WaitEvent = &Event;
+                       ExReleaseFastMutex(&Ccb->DataListLock);
+                       Status = KeWaitForSingleObject(&Event,
+                               Executive,
+                               KernelMode,
+                               FALSE,
+                               NULL);
+                       if (!NT_SUCCESS(Status))
+                       {
+                               KEBUGCHECK(0);
+                       }
+                       ExAcquireFastMutex(&Ccb->DataListLock);
+               }
+               Irp->IoStatus.Information = 0;
+       }
+       else
+       {
+               KIRQL oldIrql;
+               if (IsListEmpty(&Ccb->ReadRequestListHead) ||
+                       Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
+               {
+                       /* this is a new request */
+                       Irp->IoStatus.Information = 0;
+                       Context->WaitEvent = &Ccb->ReadEvent;
+                       InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
+                       if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
+                       {
+                               /* there was already a request on the list */
+                               IoAcquireCancelSpinLock(&oldIrql);
+                               if (Irp->Cancel)
+                               {
+                                       IoReleaseCancelSpinLock(oldIrql);
+                                       RemoveEntryList(&Context->ListEntry);
+                                       ExReleaseFastMutex(&Ccb->DataListLock);
+                                       Status = STATUS_CANCELLED;
+                                       goto done;
+                               }
+                               (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
+                               IoReleaseCancelSpinLock(oldIrql);
+                               ExReleaseFastMutex(&Ccb->DataListLock);
+                               IoMarkIrpPending(Irp);
+                               Status = STATUS_PENDING;
+                               goto done;
+                       }
+               }
+       }
+
+       while (1)
+       {
+               Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
+               Information = Irp->IoStatus.Information;
+               Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
+               ASSERT (Information <= Length);
+               Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
+               Length -= Information;
+               Status = STATUS_SUCCESS;
+
+               while (1)
+               {
+                       if (Ccb->ReadDataAvailable == 0)
+                       {
+                               if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
+                               {
+                                       ASSERT(Ccb->OtherSide != NULL);
+                                       KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
+                               }
+                               if (Information > 0 &&
+                                       (Ccb->Fcb->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
+                                       Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
+                               {
+                                       break;
+                               }
+                               if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
+                               {
+                                       DPRINT("PipeState: %x\n", Ccb->PipeState);
+                                       Status = STATUS_PIPE_BROKEN;
+                                       break;
+                               }
+                               ExReleaseFastMutex(&Ccb->DataListLock);
+                               if (IoIsOperationSynchronous(Irp))
+                               {
+                                       /* Wait for ReadEvent to become signaled */
+
+                                       DPRINT("Waiting for readable data (%wZ)\n", &Ccb->Fcb->PipeName);
+                                       Status = KeWaitForSingleObject(&Ccb->ReadEvent,
+                                               UserRequest,
+                                               KernelMode,
+                                               FALSE,
+                                               NULL);
+                                       DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status);
+                                       ExAcquireFastMutex(&Ccb->DataListLock);
+                               }
+                               else
+                               {
+                                       Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
+
+                                       Context->WaitEvent = &Ccb->ReadEvent;
+                                       Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
+
+                                       if (NT_SUCCESS(Status))
+                                       {
+                                               Status = STATUS_PENDING;
+                                       }
+                                       ExAcquireFastMutex(&Ccb->DataListLock);
+                                       break;
+                               }
+                       }
+                       ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
+                       if (Ccb->Fcb->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
+                       {
+                               DPRINT("Byte stream mode\n");
+                               /* Byte stream mode */
+                               while (Length > 0 && Ccb->ReadDataAvailable > 0)
+                               {
+                                       CopyLength = min(Ccb->ReadDataAvailable, Length);
+                                       if ((ULONG_PTR)Ccb->ReadPtr + CopyLength <= (ULONG_PTR)Ccb->Data + Ccb->MaxDataLength)
+                                       {
+                                               memcpy(Buffer, Ccb->ReadPtr, CopyLength);
+                                               Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
+                                               if (Ccb->ReadPtr == (PVOID)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength))
+                                               {
+                                                       Ccb->ReadPtr = Ccb->Data;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               TempLength = (ULONG)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength - (ULONG_PTR)Ccb->ReadPtr);
+                                               memcpy(Buffer, Ccb->ReadPtr, TempLength);
+                                               memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Ccb->Data, CopyLength - TempLength);
+                                               Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->Data + CopyLength - TempLength);
+                                       }
+
+                                       Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
+                                       Length -= CopyLength;
+                                       Information += CopyLength;
+
+                                       Ccb->ReadDataAvailable -= CopyLength;
+                                       Ccb->WriteQuotaAvailable += CopyLength;
+                               }
+
+                               if (Length == 0)
+                               {
+                                       if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
+                                       {
+                                               KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
+                                       }
+                                       KeResetEvent(&Ccb->ReadEvent);
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               DPRINT("Message mode\n");
+
+                               /* Message mode */
+                               if (Ccb->ReadDataAvailable)
+                               {
+                                       /* Truncate the message if the receive buffer is too small */
+                                       CopyLength = min(Ccb->ReadDataAvailable, Length);
+                                       memcpy(Buffer, Ccb->Data, CopyLength);
+
+#ifndef NDEBUG
+                                       DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
+                                       HexDump((PUCHAR)Buffer, CopyLength);
+#endif
+
+                                       Information = CopyLength;
+
+                                       if (Ccb->ReadDataAvailable > Length)
+                                       {
+                                               memmove(Ccb->Data, (PVOID)((ULONG_PTR)Ccb->Data + Length),
+                                                       Ccb->ReadDataAvailable - Length);
+                                               Ccb->ReadDataAvailable -= Length;
+                                               Status = STATUS_MORE_ENTRIES;
+                                       }
+                                       else
+                                       {
+                                               KeResetEvent(&Ccb->ReadEvent);
+                                               if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
+                                               {
+                                                       KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
+                                               }
+                                               Ccb->ReadDataAvailable = 0;
+                                               Ccb->WriteQuotaAvailable = Ccb->MaxDataLength;
+                                       }
+                               }
+
+                               if (Information > 0)
+                               {
+                                       break;
+                               }
+                       }
+               }
+               Irp->IoStatus.Information = Information;
+               Irp->IoStatus.Status = Status;
+
+               ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
+
+               if (IoIsOperationSynchronous(Irp))
+               {
+                       RemoveEntryList(&Context->ListEntry);
+                       if (!IsListEmpty(&Ccb->ReadRequestListHead))
+                       {
+                               Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
+                               KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
+                       }
+                       ExReleaseFastMutex(&Ccb->DataListLock);
+                       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+                       DPRINT("NpfsRead done (Status %lx)\n", Status);
+                       return Status;
+               }
+               else
+               {
+                       if (IsOriginalRequest)
+                       {
+                               IsOriginalRequest = FALSE;
+                               OriginalStatus = Status;
+                       }
+                       if (Status == STATUS_PENDING)
+                       {
+                               ExReleaseFastMutex(&Ccb->DataListLock);
+                               DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
+                               return OriginalStatus;
+                       }
+                       RemoveEntryList(&Context->ListEntry);
+                       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                       if (IsListEmpty(&Ccb->ReadRequestListHead))
+                       {
+                               ExReleaseFastMutex(&Ccb->DataListLock);
+                               DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
+                               return OriginalStatus;
+                       }
+                       Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
+                       Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
+               }
+       }
+
+done:
+       Irp->IoStatus.Status = Status;
+
+       if (Status != STATUS_PENDING)
+       {
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       }
+       DPRINT("NpfsRead done (Status %lx)\n", Status);
+
+       return Status;
+}
+
+NTSTATUS STDCALL
+NpfsWrite(PDEVICE_OBJECT DeviceObject,
+                 PIRP Irp)
+{
+       PIO_STACK_LOCATION IoStack;
+       PFILE_OBJECT FileObject;
+       PNPFS_FCB Fcb = NULL;
+       PNPFS_CCB Ccb = NULL;
+       PNPFS_CCB ReaderCcb;
+       PUCHAR Buffer;
+       NTSTATUS Status = STATUS_SUCCESS;
+       ULONG Length;
+       ULONG Offset;
+       ULONG Information;
+       ULONG CopyLength;
+       ULONG TempLength;
+
+       DPRINT("NpfsWrite()\n");
+
+       IoStack = IoGetCurrentIrpStackLocation(Irp);
+       FileObject = IoStack->FileObject;
+       DPRINT("FileObject %p\n", FileObject);
+       DPRINT("Pipe name %wZ\n", &FileObject->FileName);
+
+       Ccb = FileObject->FsContext2;
+       ReaderCcb = Ccb->OtherSide;
+       Fcb = Ccb->Fcb;
+
+       Length = IoStack->Parameters.Write.Length;
+       Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
+       Information = 0;
+
+       if (Irp->MdlAddress == NULL)
+       {
+               DPRINT("Irp->MdlAddress == NULL\n");
+               Status = STATUS_UNSUCCESSFUL;
+               Length = 0;
+               goto done;
+       }
+
+       if (ReaderCcb == NULL)
+       {
+               DPRINT("Pipe is NOT connected!\n");
+               if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
+                       Status = STATUS_PIPE_LISTENING;
+               else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
+                       Status = STATUS_PIPE_DISCONNECTED;
+               else
+                       Status = STATUS_UNSUCCESSFUL;
+               Length = 0;
+               goto done;
+       }
+
+       if (ReaderCcb->Data == NULL)
+       {
+               DPRINT("Pipe is NOT writable!\n");
+               Status = STATUS_UNSUCCESSFUL;
+               Length = 0;
+               goto done;
+       }
+
+       Status = STATUS_SUCCESS;
+       Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+       ExAcquireFastMutex(&ReaderCcb->DataListLock);
+#ifndef NDEBUG
+       DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
+       HexDump(Buffer, Length);
+#endif
+
+       while(1)
+       {
+               if (ReaderCcb->WriteQuotaAvailable == 0)
+               {
+                       KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
+                       if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
+                       {
+                               Status = STATUS_PIPE_BROKEN;
+                               ExReleaseFastMutex(&ReaderCcb->DataListLock);
+                               goto done;
+                       }
+                       ExReleaseFastMutex(&ReaderCcb->DataListLock);
+
+                       DPRINT("Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer);
+                       Status = KeWaitForSingleObject(&Ccb->WriteEvent,
+                               UserRequest,
+                               KernelMode,
+                               FALSE,
+                               NULL);
+                       DPRINT("Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status);
+
+                       /*
+                       * It's possible that the event was signaled because the
+                       * other side of pipe was closed.
+                       */
+                       if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
+                       {
+                               DPRINT("PipeState: %x\n", Ccb->PipeState);
+                               Status = STATUS_PIPE_BROKEN;
+                               // ExReleaseFastMutex(&ReaderCcb->DataListLock);
+                               goto done;
+                       }
+
+                       ExAcquireFastMutex(&ReaderCcb->DataListLock);
+               }
+
+               if (Fcb->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
+               {
+                       DPRINT("Byte stream mode\n");
+                       while (Length > 0 && ReaderCcb->WriteQuotaAvailable > 0)
+                       {
+                               CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
+                               if ((ULONG_PTR)ReaderCcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
+                               {
+                                       memcpy(ReaderCcb->WritePtr, Buffer, CopyLength);
+                                       ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + CopyLength);
+                                       if ((ULONG_PTR)ReaderCcb->WritePtr == (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
+                                       {
+                                               ReaderCcb->WritePtr = ReaderCcb->Data;
+                                       }
+                               }
+                               else
+                               {
+                                       TempLength = (ULONG)((ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength - (ULONG_PTR)ReaderCcb->WritePtr);
+                                       memcpy(ReaderCcb->WritePtr, Buffer, TempLength);
+                                       memcpy(ReaderCcb->Data, Buffer + TempLength, CopyLength - TempLength);
+                                       ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->Data + CopyLength - TempLength);
+                               }
+
+                               Buffer += CopyLength;
+                               Length -= CopyLength;
+                               Information += CopyLength;
+
+                               ReaderCcb->ReadDataAvailable += CopyLength;
+                               ReaderCcb->WriteQuotaAvailable -= CopyLength;
+                       }
+
+                       if (Length == 0)
+                       {
+                               KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
+                               KeResetEvent(&Ccb->WriteEvent);
+                               break;
+                       }
+               }
+               else
+               {
+                       DPRINT("Message mode\n");
+                       if (Length > 0)
+                       {
+                               CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
+                               memcpy(ReaderCcb->Data, Buffer, CopyLength);
+
+                               Information = CopyLength;
+                               ReaderCcb->ReadDataAvailable = CopyLength;
+                               ReaderCcb->WriteQuotaAvailable = 0;
+                       }
+
+                       if (Information > 0)
+                       {
+                               KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
+                               KeResetEvent(&Ccb->WriteEvent);
+                               break;
+                       }
+               }
+       }
+
+       ExReleaseFastMutex(&ReaderCcb->DataListLock);
+
+done:
+       Irp->IoStatus.Status = Status;
+       Irp->IoStatus.Information = Information;
+
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+       DPRINT("NpfsWrite done (Status %lx)\n", Status);
+
+       return Status;
+}
+
+/* EOF */
diff --git a/reactos/drivers/filesystems/npfs_new/volume.c b/reactos/drivers/filesystems/npfs_new/volume.c
new file mode 100644 (file)
index 0000000..59d7b5c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * PROJECT:         ReactOS Drivers
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/filesystems/npfs/volume.c
+ * PURPOSE:         Named pipe filesystem
+ * PROGRAMMERS:     
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "npfs.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS ****************************************************************/
+
+
+/* EOF */