- Update to r53061
[reactos.git] / drivers / filesystems / npfs / create.c
index 5236e20..a05c569 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
+//#define USING_PROPER_NPFS_WAIT_SEMANTICS
+
 /* FUNCTIONS *****************************************************************/
 
-static PNPFS_FCB
-NpfsFindPipe(PNPFS_DEVICE_EXTENSION DeviceExt,
+static
+VOID
+NpfsDeleteFcb(PNPFS_FCB Fcb)
+{
+    PNPFS_VCB Vcb = Fcb->Vcb;
+
+    KeLockMutex(&Vcb->PipeListLock);
+    RemoveEntryList(&Fcb->PipeListEntry);
+    KeUnlockMutex(&Vcb->PipeListLock);
+    RtlFreeUnicodeString(&Fcb->PipeName);
+    ExFreePoolWithTag(Fcb, TAG_NPFS_FCB);
+}
+
+static
+PNPFS_CCB
+NpfsAllocateCcb(CCB_TYPE Type, PNPFS_FCB Fcb)
+{
+    PNPFS_CCB Ccb;
+
+    Ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPFS_CCB), TAG_NPFS_CCB);
+    if (!Ccb)
+    {
+        return NULL;
+    }
+
+    RtlZeroMemory(Ccb, sizeof(NPFS_CCB));
+
+    Ccb->RefCount = 1;
+    Ccb->Type = Type;
+    Ccb->Fcb = Fcb;
+    Ccb->OtherSide = NULL;
+
+    return Ccb;
+}
+
+static
+VOID
+NpfsReferenceCcb(PNPFS_CCB Ccb)
+{
+    ASSERT(Ccb->RefCount > 0);
+    InterlockedIncrement((PLONG)&Ccb->RefCount);
+}
+
+static
+VOID
+NpfsDereferenceCcb(PNPFS_CCB Ccb)
+{
+    /* Decrement reference count */
+    ASSERT(Ccb->RefCount > 0);
+    if (InterlockedDecrement((PLONG)&Ccb->RefCount) == 0)
+    {
+        /* Its zero, delete CCB */
+        ExFreePoolWithTag(Ccb, TAG_NPFS_CCB);
+    }
+}
+
+static
+VOID
+NpfsCcbSetOtherSide(PNPFS_CCB Ccb, PNPFS_CCB OtherSide)
+{
+    /* Dereference old other side */
+    if (Ccb->OtherSide) NpfsDereferenceCcb(Ccb->OtherSide);
+
+    /* Reference the new other side */
+    if (OtherSide) NpfsReferenceCcb(OtherSide);
+
+    /* Set new value */
+    Ccb->OtherSide = OtherSide;
+}
+
+PNPFS_FCB
+NpfsFindPipe(PNPFS_VCB Vcb,
              PUNICODE_STRING PipeName)
 {
     PLIST_ENTRY CurrentEntry;
     PNPFS_FCB Fcb;
 
-    CurrentEntry = DeviceExt->PipeListHead.Flink;
-    while (CurrentEntry != &DeviceExt->PipeListHead)
+    CurrentEntry = Vcb->PipeListHead.Flink;
+    while (CurrentEntry != &Vcb->PipeListHead)
     {
         Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, PipeListEntry);
         if (RtlCompareUnicodeString(PipeName,
@@ -103,53 +175,147 @@ NpfsSignalAndRemoveListeningServerInstance(PNPFS_FCB Fcb,
 }
 
 
+static VOID
+NpfsOpenFileSystem(PNPFS_FCB Fcb,
+                   PFILE_OBJECT FileObject,
+                   PIO_STATUS_BLOCK IoStatus)
+{
+    PNPFS_CCB Ccb;
+
+    DPRINT("NpfsOpenFileSystem()\n");
+
+    Ccb = NpfsAllocateCcb(CCB_DEVICE, Fcb);
+    if (Ccb == NULL)
+    {
+        IoStatus->Status = STATUS_NO_MEMORY;
+        return;
+    }
+
+    FileObject->FsContext = Fcb;
+    FileObject->FsContext2 = Ccb;
+
+    IoStatus->Information = FILE_OPENED;
+    IoStatus->Status = STATUS_SUCCESS;
+
+    return;
+}
+
+
+static VOID
+NpfsOpenRootDirectory(PNPFS_FCB Fcb,
+                      PFILE_OBJECT FileObject,
+                      PIO_STATUS_BLOCK IoStatus)
+{
+    PNPFS_CCB Ccb;
+
+    DPRINT("NpfsOpenRootDirectory()\n");
+
+    Ccb = NpfsAllocateCcb(CCB_DIRECTORY, Fcb);
+    if (Ccb == NULL)
+    {
+        IoStatus->Status = STATUS_NO_MEMORY;
+        return;
+    }
+
+    FileObject->FsContext = Fcb;
+    FileObject->FsContext2 = Ccb;
+
+    IoStatus->Information = FILE_OPENED;
+    IoStatus->Status = STATUS_SUCCESS;
+
+    return;
+}
+
+
 NTSTATUS NTAPI
 NpfsCreate(PDEVICE_OBJECT DeviceObject,
            PIRP Irp)
 {
     PEXTENDED_IO_STACK_LOCATION IoStack;
+    PUNICODE_STRING FileName;
     PFILE_OBJECT FileObject;
+    PFILE_OBJECT RelatedFileObject;
     PNPFS_FCB Fcb;
     PNPFS_CCB ClientCcb;
     PNPFS_CCB ServerCcb = NULL;
-    PNPFS_DEVICE_EXTENSION DeviceExt;
-    BOOLEAN SpecialAccess;
+    PNPFS_VCB Vcb;
     ACCESS_MASK DesiredAccess;
+    NTSTATUS Status;
+#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
+    BOOLEAN SpecialAccess;
+#endif
 
     DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
-    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
     IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
     FileObject = IoStack->FileObject;
+    RelatedFileObject = FileObject->RelatedFileObject;
+    FileName = &FileObject->FileName;
     DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess;
+
     DPRINT("FileObject %p\n", FileObject);
     DPRINT("FileName %wZ\n", &FileObject->FileName);
 
     Irp->IoStatus.Information = 0;
 
+#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
     SpecialAccess = ((DesiredAccess & SPECIFIC_RIGHTS_ALL) == FILE_READ_ATTRIBUTES);
     if (SpecialAccess)
     {
         DPRINT("NpfsCreate() open client end for special use!\n");
     }
+#endif
+
+    DPRINT("FileName->Length: %hu  RelatedFileObject: %p\n", FileName->Length, RelatedFileObject);
+
+    /* Open the file system */
+    if (FileName->Length == 0 &&
+        (RelatedFileObject == NULL || ((PNPFS_CCB)RelatedFileObject->FsContext2)->Type == CCB_DEVICE))
+    {
+        DPRINT("Open the file system\n");
+
+        NpfsOpenFileSystem(Vcb->DeviceFcb,
+                           FileObject,
+                           &Irp->IoStatus);
+
+        Status = Irp->IoStatus.Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+
+    /* Open the root directory */
+    if ((FileName->Length == 2 && FileName->Buffer[0] == L'\\' && RelatedFileObject == NULL) ||
+        (FileName->Length == 0 && ((PNPFS_CCB)RelatedFileObject->FsContext2)->Type == CCB_DIRECTORY))
+    {
+        DPRINT("Open the root directory\n");
+
+        NpfsOpenRootDirectory(Vcb->RootFcb,
+                              FileObject,
+                              &Irp->IoStatus);
+
+        Status = Irp->IoStatus.Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+
 
     /*
     * Step 1. Find the pipe we're trying to open.
     */
-    KeLockMutex(&DeviceExt->PipeListLock);
-    Fcb = NpfsFindPipe(DeviceExt,
-        &FileObject->FileName);
+    KeLockMutex(&Vcb->PipeListLock);
+    Fcb = NpfsFindPipe(Vcb, &FileObject->FileName);
     if (Fcb == NULL)
     {
         /* Not found, bail out with error. */
         DPRINT("No pipe found!\n");
-        KeUnlockMutex(&DeviceExt->PipeListLock);
+        KeUnlockMutex(&Vcb->PipeListLock);
         Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         return STATUS_OBJECT_NAME_NOT_FOUND;
     }
 
-    KeUnlockMutex(&DeviceExt->PipeListLock);
+    KeUnlockMutex(&Vcb->PipeListLock);
 
     /*
     * Acquire the lock for CCB lists. From now on no modifications to the
@@ -160,7 +326,7 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
     /*
     * Step 2. Create the client CCB.
     */
-    ClientCcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
+    ClientCcb = NpfsAllocateCcb(CCB_PIPE, Fcb);
     if (ClientCcb == NULL)
     {
         DPRINT("No memory!\n");
@@ -171,10 +337,12 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
     }
 
     ClientCcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
-    ClientCcb->Fcb = Fcb;
     ClientCcb->PipeEnd = FILE_PIPE_CLIENT_END;
-    ClientCcb->OtherSide = NULL;
+#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
     ClientCcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
+#else
+    ClientCcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
+#endif
     InitializeListHead(&ClientCcb->ReadRequestListHead);
 
     DPRINT("CCB: %p\n", ClientCcb);
@@ -182,11 +350,13 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
     /* Initialize data list. */
     if (Fcb->OutboundQuota)
     {
-        ClientCcb->Data = ExAllocatePool(PagedPool, Fcb->OutboundQuota);
+        ClientCcb->Data = ExAllocatePoolWithTag(PagedPool,
+                                                Fcb->OutboundQuota,
+                                                TAG_NPFS_CCB_DATA);
         if (ClientCcb->Data == NULL)
         {
             DPRINT("No memory!\n");
-            ExFreePool(ClientCcb);
+            NpfsDereferenceCcb(ClientCcb);
             KeUnlockMutex(&Fcb->CcbListLock);
             Irp->IoStatus.Status = STATUS_NO_MEMORY;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -205,16 +375,17 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
     ClientCcb->MaxDataLength = Fcb->OutboundQuota;
     ExInitializeFastMutex(&ClientCcb->DataListLock);
     KeInitializeEvent(&ClientCcb->ConnectEvent, SynchronizationEvent, FALSE);
-    KeInitializeEvent(&ClientCcb->ReadEvent, SynchronizationEvent, FALSE);
-    KeInitializeEvent(&ClientCcb->WriteEvent, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&ClientCcb->ReadEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&ClientCcb->WriteEvent, NotificationEvent, FALSE);
 
 
     /*
     * Step 3. Search for listening server CCB.
     */
-
+#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
     if (!SpecialAccess)
     {
+#endif
         /*
         * WARNING: Point of no return! Once we get the server CCB it's
         * possible that we completed a wait request and so we have to
@@ -254,9 +425,10 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
                 DPRINT("No listening server CCB found!\n");
                 if (ClientCcb->Data)
                 {
-                    ExFreePool(ClientCcb->Data);
-                    ClientCcb->Data = NULL;
+                    ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA);
                 }
+
+                NpfsDereferenceCcb(ClientCcb);
                 KeUnlockMutex(&Fcb->CcbListLock);
                 Irp->IoStatus.Status = STATUS_OBJECT_PATH_NOT_FOUND;
                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -269,15 +441,25 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
             /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
             NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb);
         }
+#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
     }
     else if (IsListEmpty(&Fcb->ServerCcbListHead))
     {
         DPRINT("No server fcb found!\n");
+
+        if (ClientCcb->Data)
+        {
+            ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA);
+        }
+
+        NpfsDereferenceCcb(ClientCcb);
+
         KeUnlockMutex(&Fcb->CcbListLock);
         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         return STATUS_UNSUCCESSFUL;
     }
+#endif
 
     /*
     * Step 4. Add the client CCB to a list and connect it if possible.
@@ -289,8 +471,8 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject,
     /* Connect to listening server side */
     if (ServerCcb)
     {
-        ClientCcb->OtherSide = ServerCcb;
-        ServerCcb->OtherSide = ClientCcb;
+        NpfsCcbSetOtherSide(ClientCcb, ServerCcb);
+        NpfsCcbSetOtherSide(ServerCcb, ClientCcb);
         ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
         ServerCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
         KeSetEvent(&ServerCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
@@ -317,7 +499,7 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
 {
     PEXTENDED_IO_STACK_LOCATION IoStack;
     PFILE_OBJECT FileObject;
-    PNPFS_DEVICE_EXTENSION DeviceExt;
+    PNPFS_VCB Vcb;
     PNPFS_FCB Fcb;
     PNPFS_CCB Ccb;
     PNAMED_PIPE_CREATE_PARAMETERS Buffer;
@@ -325,7 +507,7 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
 
     DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
-    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
     IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
     FileObject = IoStack->FileObject;
     DPRINT("FileObject %p\n", FileObject);
@@ -343,34 +525,23 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
         return STATUS_INVALID_PARAMETER;
     }
 
-    Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
-    if (Ccb == NULL)
-    {
-        Irp->IoStatus.Status = STATUS_NO_MEMORY;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        return STATUS_NO_MEMORY;
-    }
-
-    Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
-    KeLockMutex(&DeviceExt->PipeListLock);
+    KeLockMutex(&Vcb->PipeListLock);
 
     /*
     * First search for existing Pipe with the same name.
     */
-    Fcb = NpfsFindPipe(DeviceExt,
-        &FileObject->FileName);
+    Fcb = NpfsFindPipe(Vcb, &FileObject->FileName);
     if (Fcb != NULL)
     {
         /*
         * Found Pipe with the same name. Check if we are
         * allowed to use it.
         */
-        KeUnlockMutex(&DeviceExt->PipeListLock);
+        KeUnlockMutex(&Vcb->PipeListLock);
 
         if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
         {
             DPRINT("Out of instances.\n");
-            ExFreePool(Ccb);
             Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return STATUS_INSTANCE_NOT_AVAILABLE;
@@ -381,7 +552,6 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
             Fcb->PipeType != Buffer->NamedPipeType)
         {
             DPRINT("Asked for invalid pipe mode.\n");
-            ExFreePool(Ccb);
             Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return STATUS_ACCESS_DENIED;
@@ -390,25 +560,27 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
     else
     {
         NewPipe = TRUE;
-        Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
+        Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPFS_FCB), TAG_NPFS_FCB);
         if (Fcb == NULL)
         {
-            KeUnlockMutex(&DeviceExt->PipeListLock);
-            ExFreePool(Ccb);
+            KeUnlockMutex(&Vcb->PipeListLock);
             Irp->IoStatus.Status = STATUS_NO_MEMORY;
             Irp->IoStatus.Information = 0;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return STATUS_NO_MEMORY;
         }
 
+        Fcb->Type = FCB_PIPE;
+        Fcb->Vcb = Vcb;
         Fcb->PipeName.Length = FileObject->FileName.Length;
         Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL);
-        Fcb->PipeName.Buffer = ExAllocatePool(NonPagedPool, Fcb->PipeName.MaximumLength);
+        Fcb->PipeName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                                     Fcb->PipeName.MaximumLength,
+                                                     TAG_NPFS_NAMEBLOCK);
         if (Fcb->PipeName.Buffer == NULL)
         {
-            KeUnlockMutex(&DeviceExt->PipeListLock);
-            ExFreePool(Fcb);
-            ExFreePool(Ccb);
+            KeUnlockMutex(&Vcb->PipeListLock);
+            ExFreePoolWithTag(Fcb, TAG_NPFS_FCB);
             Irp->IoStatus.Status = STATUS_NO_MEMORY;
             Irp->IoStatus.Information = 0;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -448,18 +620,18 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
         {
             if (Buffer->InboundQuota == 0)
             {
-                Fcb->InboundQuota = DeviceExt->DefaultQuota;
+                Fcb->InboundQuota = Vcb->DefaultQuota;
             }
             else
             {
                 Fcb->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
-                if (Fcb->InboundQuota < DeviceExt->MinQuota)
+                if (Fcb->InboundQuota < Vcb->MinQuota)
                 {
-                    Fcb->InboundQuota = DeviceExt->MinQuota;
+                    Fcb->InboundQuota = Vcb->MinQuota;
                 }
-                else if (Fcb->InboundQuota > DeviceExt->MaxQuota)
+                else if (Fcb->InboundQuota > Vcb->MaxQuota)
                 {
-                    Fcb->InboundQuota = DeviceExt->MaxQuota;
+                    Fcb->InboundQuota = Vcb->MaxQuota;
                 }
             }
         }
@@ -472,18 +644,18 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
         {
             if (Buffer->OutboundQuota == 0)
             {
-                Fcb->OutboundQuota = DeviceExt->DefaultQuota;
+                Fcb->OutboundQuota = Vcb->DefaultQuota;
             }
             else
             {
                 Fcb->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
-                if (Fcb->OutboundQuota < DeviceExt->MinQuota)
+                if (Fcb->OutboundQuota < Vcb->MinQuota)
                 {
-                    Fcb->OutboundQuota = DeviceExt->MinQuota;
+                    Fcb->OutboundQuota = Vcb->MinQuota;
                 }
-                else if (Fcb->OutboundQuota > DeviceExt->MaxQuota)
+                else if (Fcb->OutboundQuota > Vcb->MaxQuota)
                 {
-                    Fcb->OutboundQuota = DeviceExt->MaxQuota;
+                    Fcb->OutboundQuota = Vcb->MaxQuota;
                 }
             }
         }
@@ -492,24 +664,37 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
             Fcb->OutboundQuota = 0;
         }
 
-        InsertTailList(&DeviceExt->PipeListHead, &Fcb->PipeListEntry);
-        KeUnlockMutex(&DeviceExt->PipeListLock);
+        InsertTailList(&Vcb->PipeListHead, &Fcb->PipeListEntry);
+        KeUnlockMutex(&Vcb->PipeListLock);
+    }
+
+    Ccb = NpfsAllocateCcb(CCB_PIPE, Fcb);
+    if (Ccb == NULL)
+    {
+        if (NewPipe)
+        {
+            NpfsDeleteFcb(Fcb);
+        }
+
+        Irp->IoStatus.Status = STATUS_NO_MEMORY;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_NO_MEMORY;
     }
 
+    Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
+
     if (Fcb->InboundQuota)
     {
-        Ccb->Data = ExAllocatePool(PagedPool, Fcb->InboundQuota);
+        Ccb->Data = ExAllocatePoolWithTag(PagedPool,
+                                          Fcb->InboundQuota,
+                                          TAG_NPFS_CCB_DATA);
         if (Ccb->Data == NULL)
         {
-            ExFreePool(Ccb);
+            NpfsDereferenceCcb(Ccb);
 
             if (NewPipe)
             {
-                KeLockMutex(&DeviceExt->PipeListLock);
-                RemoveEntryList(&Fcb->PipeListEntry);
-                KeUnlockMutex(&DeviceExt->PipeListLock);
-                RtlFreeUnicodeString(&Fcb->PipeName);
-                ExFreePool(Fcb);
+                NpfsDeleteFcb(Fcb);
             }
 
             Irp->IoStatus.Status = STATUS_NO_MEMORY;
@@ -535,13 +720,12 @@ NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
     Ccb->Fcb = Fcb;
     Ccb->PipeEnd = FILE_PIPE_SERVER_END;
     Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
-    Ccb->OtherSide = NULL;
 
     DPRINT("CCB: %p\n", Ccb);
 
     KeInitializeEvent(&Ccb->ConnectEvent, SynchronizationEvent, FALSE);
-    KeInitializeEvent(&Ccb->ReadEvent, SynchronizationEvent, FALSE);
-    KeInitializeEvent(&Ccb->WriteEvent, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&Ccb->ReadEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&Ccb->WriteEvent, NotificationEvent, FALSE);
 
     KeLockMutex(&Fcb->CcbListLock);
     InsertTailList(&Fcb->ServerCcbListHead, &Ccb->CcbListEntry);
@@ -564,7 +748,7 @@ NTSTATUS NTAPI
 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
             PIRP Irp)
 {
-    PNPFS_DEVICE_EXTENSION DeviceExt;
+    PNPFS_VCB Vcb;
     PIO_STACK_LOCATION IoStack;
     PFILE_OBJECT FileObject;
     PNPFS_CCB Ccb, OtherSide;
@@ -574,7 +758,7 @@ NpfsCleanup(PDEVICE_OBJECT DeviceObject,
     DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
     FileObject = IoStack->FileObject;
     Ccb = FileObject->FsContext2;
 
@@ -587,6 +771,24 @@ NpfsCleanup(PDEVICE_OBJECT DeviceObject,
         return STATUS_SUCCESS;
     }
 
+    if (Ccb->Type == CCB_DEVICE)
+    {
+        DPRINT("Cleanup the file system!\n");
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
+    if (Ccb->Type == CCB_DIRECTORY)
+    {
+        DPRINT("Cleanup the root directory!\n");
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
     DPRINT("CCB %p\n", Ccb);
     Fcb = Ccb->Fcb;
 
@@ -608,6 +810,8 @@ NpfsCleanup(PDEVICE_OBJECT DeviceObject,
     if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
     {
         OtherSide = Ccb->OtherSide;
+        ASSERT(OtherSide->OtherSide == Ccb);
+
         /* Lock the server first */
         if (Server)
         {
@@ -619,8 +823,11 @@ NpfsCleanup(PDEVICE_OBJECT DeviceObject,
             ExAcquireFastMutex(&OtherSide->DataListLock);
             ExAcquireFastMutex(&Ccb->DataListLock);
         }
-        //OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
-        OtherSide->OtherSide = NULL;
+
+        /* Unlink FCBs */
+        NpfsCcbSetOtherSide(OtherSide, NULL);
+        NpfsCcbSetOtherSide(Ccb, NULL);
+
         /*
         * Signaling the write event. If is possible that an other
         * thread waits for an empty buffer.
@@ -680,7 +887,7 @@ NpfsCleanup(PDEVICE_OBJECT DeviceObject,
     ExAcquireFastMutex(&Ccb->DataListLock);
     if (Ccb->Data)
     {
-        ExFreePool(Ccb->Data);
+        ExFreePoolWithTag(Ccb->Data, TAG_NPFS_CCB_DATA);
         Ccb->Data = NULL;
         Ccb->ReadPtr = NULL;
         Ccb->WritePtr = NULL;
@@ -700,9 +907,9 @@ NTSTATUS NTAPI
 NpfsClose(PDEVICE_OBJECT DeviceObject,
           PIRP Irp)
 {
-    PNPFS_DEVICE_EXTENSION DeviceExt;
     PIO_STACK_LOCATION IoStack;
     PFILE_OBJECT FileObject;
+    PNPFS_VCB Vcb;
     PNPFS_FCB Fcb;
     PNPFS_CCB Ccb;
     BOOLEAN Server;
@@ -710,7 +917,7 @@ NpfsClose(PDEVICE_OBJECT DeviceObject,
     DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
     FileObject = IoStack->FileObject;
     Ccb = FileObject->FsContext2;
 
@@ -723,6 +930,38 @@ NpfsClose(PDEVICE_OBJECT DeviceObject,
         return STATUS_SUCCESS;
     }
 
+    if (Ccb->Type == CCB_DEVICE)
+    {
+        DPRINT("Closing the file system!\n");
+
+        NpfsDereferenceCcb(Ccb);
+        FileObject->FsContext = NULL;
+        FileObject->FsContext2 = NULL;
+
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
+    if (Ccb->Type == CCB_DIRECTORY)
+    {
+        DPRINT("Closing the root directory!\n");
+
+        if (Ccb->u.Directory.SearchPattern.Buffer != NULL)
+            ExFreePoolWithTag(Ccb->u.Directory.SearchPattern.Buffer,
+                              TAG_NPFS_NAMEBLOCK);
+
+        NpfsDereferenceCcb(Ccb);
+        FileObject->FsContext = NULL;
+        FileObject->FsContext2 = NULL;
+
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
     DPRINT("CCB %p\n", Ccb);
     Fcb = Ccb->Fcb;
 
@@ -743,8 +982,13 @@ NpfsClose(PDEVICE_OBJECT DeviceObject,
     }
 
     /* Disconnect the pipes */
-    if (Ccb->OtherSide) Ccb->OtherSide->OtherSide = NULL;
-    if (Ccb) Ccb->OtherSide = NULL;
+    if (Ccb->OtherSide)
+    {
+        /* FIXME: Timo wants it rewritten */
+        /*ASSERT(Ccb->OtherSide->OtherSide == Ccb);*/
+        NpfsCcbSetOtherSide(Ccb->OtherSide, NULL);
+        NpfsCcbSetOtherSide(Ccb, NULL);
+    }
 
     ASSERT(Ccb->PipeState == FILE_PIPE_CLOSING_STATE);
 
@@ -752,18 +996,14 @@ NpfsClose(PDEVICE_OBJECT DeviceObject,
 
     RemoveEntryList(&Ccb->CcbListEntry);
 
-    ExFreePool(Ccb);
+    NpfsDereferenceCcb(Ccb);
 
     KeUnlockMutex(&Fcb->CcbListLock);
 
     if (IsListEmpty(&Fcb->ServerCcbListHead) &&
         IsListEmpty(&Fcb->ClientCcbListHead))
     {
-        RtlFreeUnicodeString(&Fcb->PipeName);
-        KeLockMutex(&DeviceExt->PipeListLock);
-        RemoveEntryList(&Fcb->PipeListEntry);
-        KeUnlockMutex(&DeviceExt->PipeListLock);
-        ExFreePool(Fcb);
+        NpfsDeleteFcb(Fcb);
         FileObject->FsContext = NULL;
     }