reactos/drivers/filesystems/ffs/src/close.c

342 lines
6.3 KiB
C

/*
* FFS File System Driver for Windows
*
* close.c
*
* 2004.5.6 ~
*
* Lee Jae-Hong, http://www.pyrasis.com
*
* See License.txt
*
*/
#include "ntifs.h"
#include "ffsdrv.h"
/* Globals */
extern PFFS_GLOBAL FFSGlobal;
/* Definitions */
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FFSClose)
#pragma alloc_text(PAGE, FFSQueueCloseRequest)
#pragma alloc_text(PAGE, FFSDeQueueCloseRequest)
#endif
__drv_mustHoldCriticalRegion
NTSTATUS
FFSClose(
IN PFFS_IRP_CONTEXT IrpContext)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_SUCCESS;
PFFS_VCB Vcb = 0;
BOOLEAN VcbResourceAcquired = FALSE;
PFILE_OBJECT FileObject;
PFFS_FCB Fcb = 0;
BOOLEAN FcbResourceAcquired = FALSE;
PFFS_CCB Ccb;
BOOLEAN FreeVcb = FALSE;
PAGED_CODE();
_SEH2_TRY
{
ASSERT(IrpContext != NULL);
ASSERT((IrpContext->Identifier.Type == FFSICX) &&
(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
if (DeviceObject == FFSGlobal->DeviceObject)
{
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
Vcb = (PFFS_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == FFSVCB) &&
(Vcb->Identifier.Size == sizeof(FFS_VCB)));
ASSERT(IsMounted(Vcb));
if (!ExAcquireResourceExclusiveLite(
&Vcb->MainResource,
IrpContext->IsSynchronous))
{
FFSPrint((DBG_INFO, "FFSClose: PENDING ... Vcb: %xh/%xh\n",
Vcb->OpenFileHandleCount, Vcb->ReferenceCount));
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
VcbResourceAcquired = TRUE;
FileObject = IrpContext->FileObject;
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE))
{
Fcb = IrpContext->Fcb;
Ccb = IrpContext->Ccb;
}
else
{
Fcb = (PFFS_FCB)FileObject->FsContext;
if (!Fcb)
{
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
ASSERT(Fcb != NULL);
Ccb = (PFFS_CCB)FileObject->FsContext2;
}
if (Fcb->Identifier.Type == FFSVCB)
{
Vcb->ReferenceCount--;
if (!Vcb->ReferenceCount && FlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))
{
FreeVcb = TRUE;
}
if (Ccb)
{
FFSFreeCcb(Ccb);
if (FileObject)
{
FileObject->FsContext2 = Ccb = NULL;
}
}
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
if (Fcb->Identifier.Type != FFSFCB || Fcb->Identifier.Size != sizeof(FFS_FCB))
{
#if DBG
FFSPrint((DBG_ERROR, "FFSClose: Strange IRP_MJ_CLOSE by system!\n"));
ExAcquireResourceExclusiveLite(
&FFSGlobal->CountResource,
TRUE);
FFSGlobal->IRPCloseCount++;
ExReleaseResourceForThreadLite(
&FFSGlobal->CountResource,
ExGetCurrentResourceThread());
#endif
_SEH2_LEAVE;
}
ASSERT((Fcb->Identifier.Type == FFSFCB) &&
(Fcb->Identifier.Size == sizeof(FFS_FCB)));
/*
if ((!IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) &&
(!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE)))
*/
{
if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
IrpContext->IsSynchronous))
{
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
FcbResourceAcquired = TRUE;
}
if (!Ccb)
{
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
ASSERT((Ccb->Identifier.Type == FFSCCB) &&
(Ccb->Identifier.Size == sizeof(FFS_CCB)));
Fcb->ReferenceCount--;
Vcb->ReferenceCount--;
if (!Vcb->ReferenceCount && IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))
{
FreeVcb = TRUE;
}
FFSPrint((DBG_INFO, "FFSClose: OpenHandleCount: %u ReferenceCount: %u %s\n",
Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer));
if (Ccb)
{
FFSFreeCcb(Ccb);
if (FileObject)
{
FileObject->FsContext2 = Ccb = NULL;
}
}
if (!Fcb->ReferenceCount)
{
//
// Remove Fcb from Vcb->FcbList ...
//
RemoveEntryList(&Fcb->Next);
FFSFreeFcb(Fcb);
FcbResourceAcquired = FALSE;
}
Status = STATUS_SUCCESS;
}
_SEH2_FINALLY
{
if (FcbResourceAcquired)
{
ExReleaseResourceForThreadLite(
&Fcb->MainResource,
ExGetCurrentResourceThread());
}
if (VcbResourceAcquired)
{
ExReleaseResourceForThreadLite(
&Vcb->MainResource,
ExGetCurrentResourceThread());
}
if (!IrpContext->ExceptionInProgress)
{
if (Status == STATUS_PENDING)
{
FFSQueueCloseRequest(IrpContext);
#if 0
/*
Status = STATUS_SUCCESS;
if (IrpContext->Irp != NULL)
{
IrpContext->Irp->IoStatus.Status = Status;
FFSCompleteRequest(
IrpContext->Irp,
(BOOLEAN)!IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED),
(CCHAR)
(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
IrpContext->Irp = NULL;
}
*/
#endif
}
else
{
FFSCompleteIrpContext(IrpContext, Status);
if (FreeVcb)
{
ExAcquireResourceExclusiveLite(
&FFSGlobal->Resource, TRUE);
FFSClearVpbFlag(Vcb->Vpb, VPB_MOUNTED);
FFSRemoveVcb(Vcb);
ExReleaseResourceForThreadLite(
&FFSGlobal->Resource,
ExGetCurrentResourceThread());
FFSFreeVcb(Vcb);
}
}
}
} _SEH2_END;
return Status;
}
VOID
FFSQueueCloseRequest(
IN PFFS_IRP_CONTEXT IrpContext)
{
PAGED_CODE();
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == FFSICX) &&
(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
if (!IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE))
{
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE);
IrpContext->Fcb = (PFFS_FCB)IrpContext->FileObject->FsContext;
IrpContext->Ccb = (PFFS_CCB)IrpContext->FileObject->FsContext2;
IrpContext->FileObject = NULL;
}
// IsSynchronous means we can block (so we don't requeue it)
IrpContext->IsSynchronous = TRUE;
ExInitializeWorkItem(
&IrpContext->WorkQueueItem,
FFSDeQueueCloseRequest,
IrpContext);
ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
}
VOID NTAPI
FFSDeQueueCloseRequest(
IN PVOID Context)
{
PFFS_IRP_CONTEXT IrpContext;
PAGED_CODE();
IrpContext = (PFFS_IRP_CONTEXT) Context;
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == FFSICX) &&
(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
_SEH2_TRY
{
_SEH2_TRY
{
FsRtlEnterFileSystem();
FFSClose(IrpContext);
}
_SEH2_EXCEPT (FFSExceptionFilter(IrpContext, _SEH2_GetExceptionInformation()))
{
FFSExceptionHandler(IrpContext);
} _SEH2_END;
}
_SEH2_FINALLY
{
FsRtlExitFileSystem();
} _SEH2_END;
}