[FASTFAT] Fix a handle count leak on volume close. This can prevent locking a volume!
[reactos.git] / drivers / filesystems / fastfat / cleanup.c
index f05c116..d584dee 100644 (file)
@@ -8,31 +8,40 @@
 
 /* INCLUDES *****************************************************************/
 
-#define NDEBUG
 #include "vfat.h"
 
+#define NDEBUG
+#include <debug.h>
+
 /* FUNCTIONS ****************************************************************/
 
 /*
  * FUNCTION: Cleans up after a file has been closed.
  */
-static NTSTATUS
-VfatCleanupFile(PVFAT_IRP_CONTEXT IrpContext)
+static
+NTSTATUS
+VfatCleanupFile(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
     PVFATFCB pFcb;
+    PVFATCCB pCcb;
+    BOOLEAN IsVolume;
+    PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
     PFILE_OBJECT FileObject = IrpContext->FileObject;
 
     DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
            IrpContext->DeviceExt, FileObject);
 
     /* FIXME: handle file/directory deletion here */
-    pFcb = (PVFATFCB) FileObject->FsContext;
+    pFcb = (PVFATFCB)FileObject->FsContext;
     if (!pFcb)
         return STATUS_SUCCESS;
 
-    if (pFcb->Flags & FCB_IS_VOLUME)
+    IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
+    if (IsVolume)
     {
         pFcb->OpenHandleCount--;
+        DeviceExt->OpenHandleCount--;
 
         if (pFcb->OpenHandleCount != 0)
         {
@@ -41,21 +50,33 @@ VfatCleanupFile(PVFAT_IRP_CONTEXT IrpContext)
     }
     else
     {
-        if(!ExAcquireResourceExclusiveLite (&pFcb->MainResource,
-                                            (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+        if(!ExAcquireResourceExclusiveLite(&pFcb->MainResource,
+                                           BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
         {
             return STATUS_PENDING;
         }
-        if(!ExAcquireResourceExclusiveLite (&pFcb->PagingIoResource,
-                                            (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+        if(!ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource,
+                                           BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
         {
-            ExReleaseResourceLite (&pFcb->MainResource);
+            ExReleaseResourceLite(&pFcb->MainResource);
             return STATUS_PENDING;
         }
 
+        pCcb = FileObject->FsContext2;
+        if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE))
+        {
+            pFcb->Flags |= FCB_DELETE_PENDING;
+        }
+
+        /* Notify about the cleanup */
+        FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync,
+                           &(IrpContext->DeviceExt->NotifyList),
+                           FileObject->FsContext2);
+
         pFcb->OpenHandleCount--;
+        DeviceExt->OpenHandleCount--;
 
-        if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+        if (!vfatFCBIsDirectory(pFcb) &&
             FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
         {
             /* remove all locks this process have on this file */
@@ -65,29 +86,56 @@ VfatCleanupFile(PVFAT_IRP_CONTEXT IrpContext)
                                NULL);
         }
 
-        if (pFcb->Flags & FCB_IS_DIRTY)
+        if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
         {
-            VfatUpdateEntry (pFcb);
+            VfatUpdateEntry (pFcb, vfatVolumeIsFatX(DeviceExt));
         }
 
-        if (pFcb->Flags & FCB_DELETE_PENDING &&
+        if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
             pFcb->OpenHandleCount == 0)
         {
-            PFILE_OBJECT tmpFileObject;
-            tmpFileObject = pFcb->FileObject;
-            if (tmpFileObject != NULL)
+            if (vfatFCBIsDirectory(pFcb) &&
+                !VfatIsDirectoryEmpty(DeviceExt, pFcb))
             {
-                pFcb->FileObject = NULL;
-                CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
-                ObDereferenceObject(tmpFileObject);
-           }
-
-           CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, FALSE);
+                pFcb->Flags &= ~FCB_DELETE_PENDING;
+            }
+            else
+            {
+                PFILE_OBJECT tmpFileObject;
+                tmpFileObject = pFcb->FileObject;
+                if (tmpFileObject != NULL)
+                {
+                    pFcb->FileObject = NULL;
+                    CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
+                    ObDereferenceObject(tmpFileObject);
+                }
+
+                pFcb->RFCB.ValidDataLength.QuadPart = 0;
+                pFcb->RFCB.FileSize.QuadPart = 0;
+                pFcb->RFCB.AllocationSize.QuadPart = 0;
+            }
         }
 
         /* Uninitialize the cache (should be done even if caching was never initialized) */
         CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL);
 
+        if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
+            pFcb->OpenHandleCount == 0)
+        {
+            VfatDelEntry(DeviceExt, pFcb, NULL);
+
+            FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+                                        &(DeviceExt->NotifyList),
+                                        (PSTRING)&pFcb->PathNameU,
+                                        pFcb->PathNameU.Length - pFcb->LongNameU.Length,
+                                        NULL,
+                                        NULL,
+                                        vfatFCBIsDirectory(pFcb) ?
+                                        FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
+                                        FILE_ACTION_REMOVED,
+                                        NULL);
+        }
+
         if (pFcb->OpenHandleCount != 0)
         {
             IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
@@ -95,17 +143,26 @@ VfatCleanupFile(PVFAT_IRP_CONTEXT IrpContext)
 
         FileObject->Flags |= FO_CLEANUP_COMPLETE;
 
-        ExReleaseResourceLite (&pFcb->PagingIoResource);
-        ExReleaseResourceLite (&pFcb->MainResource);
+        ExReleaseResourceLite(&pFcb->PagingIoResource);
+        ExReleaseResourceLite(&pFcb->MainResource);
     }
 
+#ifdef ENABLE_SWAPOUT
+    if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
+    {
+        VfatCheckForDismount(DeviceExt, FALSE);
+    }
+#endif
+
     return STATUS_SUCCESS;
 }
 
 /*
  * FUNCTION: Cleans up after a file has been closed.
  */
-NTSTATUS VfatCleanup(PVFAT_IRP_CONTEXT IrpContext)
+NTSTATUS
+VfatCleanup(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
     NTSTATUS Status;
 
@@ -113,32 +170,27 @@ NTSTATUS VfatCleanup(PVFAT_IRP_CONTEXT IrpContext)
 
     if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
     {
-        Status = STATUS_SUCCESS;
-        goto ByeBye;
+        IrpContext->Irp->IoStatus.Information = 0;
+        return STATUS_SUCCESS;
     }
 
-    if (!ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource,
-                                         (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+    if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
+                                        BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
     {
-        return VfatQueueRequest (IrpContext);
+        return VfatMarkIrpContextForQueue(IrpContext);
     }
 
     Status = VfatCleanupFile(IrpContext);
 
-    ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
+    ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
 
     if (Status == STATUS_PENDING)
     {
-        return VfatQueueRequest(IrpContext);
+        return VfatMarkIrpContextForQueue(IrpContext);
     }
 
-ByeBye:
-    IrpContext->Irp->IoStatus.Status = Status;
     IrpContext->Irp->IoStatus.Information = 0;
-
-    IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
-    VfatFreeIrpContext(IrpContext);
-    return (Status);
+    return Status;
 }
 
 /* EOF */