mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 21:13:52 +00:00
1195 lines
42 KiB
C++
1195 lines
42 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
|
|
// All rights reserved
|
|
// This file was released under the GPLv2 on June 2015.
|
|
////////////////////////////////////////////////////////////////////
|
|
/*************************************************************************
|
|
*
|
|
* File: Close.cpp
|
|
*
|
|
* Module: UDF File System Driver (Kernel mode execution only)
|
|
*
|
|
* Description:
|
|
* Contains code to handle the "Close" dispatch entry point.
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include "udffs.h"
|
|
|
|
// define the file specific bug-check id
|
|
#define UDF_BUG_CHECK_ID UDF_FILE_CLOSE
|
|
|
|
typedef BOOLEAN (*PCHECK_TREE_ITEM) (IN PUDF_FILE_INFO FileInfo);
|
|
#define TREE_ITEM_LIST_GRAN 32
|
|
|
|
NTSTATUS
|
|
UDFBuildTreeItemsList(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN PCHECK_TREE_ITEM CheckItemProc,
|
|
IN PUDF_DATALOC_INFO** PassedList,
|
|
IN PULONG PassedListSize,
|
|
IN PUDF_DATALOC_INFO** FoundList,
|
|
IN PULONG FoundListSize);
|
|
|
|
// callbacks, can't be __fastcall
|
|
BOOLEAN
|
|
UDFIsInDelayedCloseQueue(
|
|
PUDF_FILE_INFO FileInfo);
|
|
|
|
BOOLEAN
|
|
UDFIsLastClose(
|
|
PUDF_FILE_INFO FileInfo);
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFClose()
|
|
*
|
|
* Description:
|
|
* The I/O Manager will invoke this routine to handle a close
|
|
* request
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
|
|
* to be deferred to a worker thread context)
|
|
*
|
|
* Return Value: STATUS_SUCCESS
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
NTAPI
|
|
UDFClose(
|
|
PDEVICE_OBJECT DeviceObject, // the logical volume device object
|
|
PIRP Irp // I/O Request Packet
|
|
)
|
|
{
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
PtrUDFIrpContext PtrIrpContext = NULL;
|
|
BOOLEAN AreWeTopLevel = FALSE;
|
|
|
|
AdPrint(("UDFClose: \n"));
|
|
|
|
FsRtlEnterFileSystem();
|
|
ASSERT(DeviceObject);
|
|
ASSERT(Irp);
|
|
|
|
// If we were called with our file system device object instead of a
|
|
// volume device object, just complete this request with STATUS_SUCCESS
|
|
if (UDFIsFSDevObj(DeviceObject)) {
|
|
// this is a close of the FSD itself
|
|
Irp->IoStatus.Status = RC;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
FsRtlExitFileSystem();
|
|
return(RC);
|
|
}
|
|
|
|
// set the top level context
|
|
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
|
|
|
|
_SEH2_TRY {
|
|
|
|
// get an IRP context structure and issue the request
|
|
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
|
|
ASSERT(PtrIrpContext);
|
|
|
|
RC = UDFCommonClose(PtrIrpContext, Irp);
|
|
|
|
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
|
|
|
|
RC = UDFExceptionHandler(PtrIrpContext, Irp);
|
|
|
|
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
|
|
} _SEH2_END;
|
|
|
|
if (AreWeTopLevel) {
|
|
IoSetTopLevelIrp(NULL);
|
|
}
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
return(RC);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFCommonClose()
|
|
*
|
|
* Description:
|
|
* The actual work is performed here. This routine may be invoked in one'
|
|
* of the two possible contexts:
|
|
* (a) in the context of a system worker thread
|
|
* (b) in the context of the original caller
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: must be STATUS_SUCCESS
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
UDFCommonClose(
|
|
PtrUDFIrpContext PtrIrpContext,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
PFILE_OBJECT FileObject = NULL;
|
|
PtrUDFFCB Fcb = NULL;
|
|
PtrUDFCCB Ccb = NULL;
|
|
PVCB Vcb = NULL;
|
|
// PERESOURCE PtrResourceAcquired = NULL;
|
|
BOOLEAN AcquiredVcb = FALSE;
|
|
BOOLEAN AcquiredGD = FALSE;
|
|
PUDF_FILE_INFO fi;
|
|
ULONG i = 0;
|
|
// ULONG clean_stat = 0;
|
|
|
|
// BOOLEAN CompleteIrp = TRUE;
|
|
BOOLEAN PostRequest = FALSE;
|
|
|
|
#ifdef UDF_DBG
|
|
UNICODE_STRING CurName;
|
|
PDIR_INDEX_HDR DirNdx;
|
|
#endif
|
|
|
|
AdPrint(("UDFCommonClose: \n"));
|
|
|
|
_SEH2_TRY {
|
|
if (Irp) {
|
|
|
|
// If this is the first (IOManager) request
|
|
// First, get a pointer to the current I/O stack location
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IrpSp);
|
|
|
|
FileObject = IrpSp->FileObject;
|
|
ASSERT(FileObject);
|
|
|
|
// Get the FCB and CCB pointers
|
|
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
|
|
ASSERT(Ccb);
|
|
if(Ccb->CCBFlags & UDF_CCB_READ_ONLY) {
|
|
PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_READ_ONLY;
|
|
}
|
|
Fcb = Ccb->Fcb;
|
|
} else {
|
|
// If this is a queued call (for our dispatch)
|
|
// Get saved Fcb address
|
|
Fcb = PtrIrpContext->Fcb;
|
|
i = PtrIrpContext->TreeLength;
|
|
}
|
|
|
|
ASSERT(Fcb);
|
|
Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
|
|
ASSERT(Vcb);
|
|
ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
|
|
// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
|
|
|
|
// Steps we shall take at this point are:
|
|
// (a) Acquire the VCB shared
|
|
// (b) Acquire the FCB's CCB list exclusively
|
|
// (c) Delete the CCB structure (free memory)
|
|
// (d) If this is the last close, release the FCB structure
|
|
// (unless we keep these around for "delayed close" functionality.
|
|
// Note that it is often the case that the close dispatch entry point is invoked
|
|
// in the most inconvenient of situations (when it is not possible, for example,
|
|
// to safely acquire certain required resources without deadlocking or waiting).
|
|
// Therefore, be extremely careful in implementing this close dispatch entry point.
|
|
// Also note that we do not have the option of returning a failure code from the
|
|
// close dispatch entry point; the system expects that the close will always succeed.
|
|
|
|
UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVcb = TRUE;
|
|
|
|
// Is this is the first (IOManager) request ?
|
|
if (Irp) {
|
|
PtrIrpContext->TreeLength =
|
|
i = Ccb->TreeLength;
|
|
// remember the number of incomplete Close requests
|
|
InterlockedIncrement((PLONG)&(Fcb->CcbCount));
|
|
// we can release CCB in any case
|
|
UDFCleanUpCCB(Ccb);
|
|
FileObject->FsContext2 = NULL;
|
|
#ifdef DBG
|
|
/* } else {
|
|
ASSERT(Fcb->NTRequiredFCB);
|
|
if(Fcb->NTRequiredFCB) {
|
|
ASSERT(Fcb->NTRequiredFCB->FileObject);
|
|
if(Fcb->NTRequiredFCB->FileObject) {
|
|
ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2);
|
|
}
|
|
}*/
|
|
#endif //DBG
|
|
}
|
|
|
|
#ifdef UDF_DELAYED_CLOSE
|
|
// check if this is the last Close (no more Handles)
|
|
// and try to Delay it....
|
|
if((Fcb->FCBFlags & UDF_FCB_DELAY_CLOSE) &&
|
|
(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) &&
|
|
!(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) &&
|
|
!(Fcb->OpenHandleCount)) {
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVcb = FALSE;
|
|
if((RC = UDFQueueDelayedClose(PtrIrpContext,Fcb)) == STATUS_SUCCESS)
|
|
try_return(RC = STATUS_SUCCESS);
|
|
// do standard Close if we can't Delay this opeartion
|
|
AdPrint((" Cant queue Close Irp, status=%x\n", RC));
|
|
}
|
|
#endif //UDF_DELAYED_CLOSE
|
|
|
|
if(Irp) {
|
|
// We should post actual procesing if this is a recursive call
|
|
if((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) ||
|
|
(Fcb->NTRequiredFCB->AcqFlushCount)) {
|
|
AdPrint((" post NOT_TOP_LEVEL Irp\n"));
|
|
PostRequest = TRUE;
|
|
try_return(RC = STATUS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
// Close request is near completion, Vcb is acquired.
|
|
// Now we can safely decrease CcbCount, because no Rename
|
|
// operation can run until Vcb release.
|
|
InterlockedDecrement((PLONG)&(Fcb->CcbCount));
|
|
|
|
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
|
|
if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_READ_ONLY)
|
|
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCountRO));
|
|
|
|
if(!i || (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)) {
|
|
|
|
AdPrint(("UDF: Closing volume\n"));
|
|
AdPrint(("UDF: ReferenceCount: %x\n",Fcb->ReferenceCount));
|
|
|
|
if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE) {
|
|
ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
|
|
UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
|
|
ASSERT(Fcb->NTRequiredFCB);
|
|
UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount));
|
|
|
|
try_return(RC = STATUS_SUCCESS);
|
|
}
|
|
|
|
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
|
|
|
|
if(AcquiredVcb) {
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVcb = FALSE;
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
// Acquire GlobalDataResource
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
|
|
AcquiredGD = TRUE;
|
|
// // Acquire Vcb
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVcb = TRUE;
|
|
|
|
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
|
|
|
|
|
|
ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
|
|
UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
|
|
ASSERT(Fcb->NTRequiredFCB);
|
|
UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount));
|
|
|
|
//AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n"));
|
|
//UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);
|
|
|
|
AdPrint(("UDF: Closing volume, reset write status\n"));
|
|
RC = UDFPhSendIOCTL(IOCTL_CDRW_RESET_WRITE_STATUS, Vcb->TargetDeviceObject,
|
|
NULL, 0, NULL, 0, TRUE, NULL);
|
|
|
|
if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) ||
|
|
((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) {
|
|
// Try to KILL dismounted volume....
|
|
// w2k requires this, NT4 - recomends
|
|
AcquiredVcb = UDFCheckForDismount(PtrIrpContext, Vcb, TRUE);
|
|
}
|
|
|
|
try_return(RC = STATUS_SUCCESS);
|
|
}
|
|
|
|
fi = Fcb->FileInfo;
|
|
#ifdef UDF_DBG
|
|
if(!fi) {
|
|
BrutePoint();
|
|
}
|
|
|
|
DirNdx = UDFGetDirIndexByFileInfo(fi);
|
|
if(DirNdx) {
|
|
CurName.Buffer = UDFDirIndex(DirNdx,fi->Index)->FName.Buffer;
|
|
if(CurName.Buffer) {
|
|
AdPrint(("Closing file: %ws %8.8x\n", CurName.Buffer, FileObject));
|
|
} else {
|
|
AdPrint(("Closing file: ??? \n"));
|
|
}
|
|
}
|
|
AdPrint(("UDF: ReferenceCount: %x\n",Fcb->ReferenceCount));
|
|
#endif // UDF_DBG
|
|
// try to clean up as long chain as it is possible
|
|
UDFCleanUpFcbChain(Vcb, fi, i, TRUE);
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if(AcquiredVcb) {
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
}
|
|
if(AcquiredGD) {
|
|
UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
|
|
}
|
|
|
|
// Post IRP if required
|
|
if (PostRequest) {
|
|
|
|
// Perform the post operation & complete the IRP
|
|
// if this is first call of UDFCommonClose
|
|
// and will return STATUS_SUCCESS back to us
|
|
PtrIrpContext->Irp = NULL;
|
|
PtrIrpContext->Fcb = Fcb;
|
|
UDFPostRequest(PtrIrpContext, NULL);
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
// If this is not async close complete the IRP
|
|
if (Irp) {
|
|
/* if( FileObject ) {
|
|
if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) {
|
|
// ASSERT(!FileObject->FsContext2);
|
|
FileObject->FsContext = NULL;
|
|
#ifdef DBG
|
|
} else {
|
|
UDFNTRequiredFCB* NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext));
|
|
if(NtReqFcb->FileObject == FileObject) {
|
|
NtReqFcb->FileObject = NULL;
|
|
}
|
|
#endif //DBG
|
|
}
|
|
}*/
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
|
}
|
|
// Free up the Irp Context
|
|
if(!PostRequest)
|
|
UDFReleaseIrpContext(PtrIrpContext);
|
|
}
|
|
|
|
} _SEH2_END; // end of "__finally" processing
|
|
|
|
return STATUS_SUCCESS ;
|
|
} // end UDFCommonClose()
|
|
|
|
/*
|
|
This routine walks through the tree to RootDir & kills all unreferenced
|
|
structures....
|
|
imho, Useful feature
|
|
*/
|
|
ULONG
|
|
UDFCleanUpFcbChain(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO fi,
|
|
IN ULONG TreeLength,
|
|
IN BOOLEAN VcbAcquired
|
|
)
|
|
{
|
|
PtrUDFFCB Fcb = NULL;
|
|
PtrUDFFCB ParentFcb = NULL;
|
|
PUDF_FILE_INFO ParentFI;
|
|
UDFNTRequiredFCB* NtReqFcb;
|
|
ULONG CleanCode;
|
|
LONG RefCount, ComRefCount;
|
|
BOOLEAN Delete = FALSE;
|
|
ULONG ret_val = 0;
|
|
|
|
ValidateFileInfo(fi);
|
|
AdPrint(("UDFCleanUpFcbChain\n"));
|
|
|
|
ASSERT(TreeLength);
|
|
|
|
// we can't process Tree until we can acquire Vcb
|
|
if(!VcbAcquired)
|
|
UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
|
|
|
|
// cleanup parent chain (if any & unused)
|
|
while(fi) {
|
|
|
|
// acquire parent
|
|
if((ParentFI = fi->ParentFile)) {
|
|
ASSERT(fi->Fcb);
|
|
ParentFcb = fi->Fcb->ParentFcb;
|
|
ASSERT(ParentFcb);
|
|
ASSERT(ParentFcb->NTRequiredFCB);
|
|
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
|
UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE);
|
|
} else {
|
|
// we get to RootDir, it has no parent
|
|
if(!VcbAcquired)
|
|
UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
|
|
}
|
|
Fcb = fi->Fcb;
|
|
ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
|
|
|
|
NtReqFcb = Fcb->NTRequiredFCB;
|
|
ASSERT(NtReqFcb->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);
|
|
|
|
// acquire current file/dir
|
|
// we must assure that no more threads try to re-use this object
|
|
#ifdef UDF_DBG
|
|
_SEH2_TRY {
|
|
#endif // UDF_DBG
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
|
|
#ifdef UDF_DBG
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
if(ParentFI) {
|
|
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
|
UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
|
|
} else {
|
|
if(!VcbAcquired)
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
}
|
|
break;
|
|
} _SEH2_END;
|
|
#endif // UDF_DBG
|
|
ASSERT_REF((Fcb->ReferenceCount > fi->RefCount) || !TreeLength);
|
|
// If we haven't pass through all files opened
|
|
// in UDFCommonCreate before target file (TreeLength specfies
|
|
// the number of such files) dereference them.
|
|
// Otherwise we'll just check if the file has no references.
|
|
#ifdef UDF_DBG
|
|
if(Fcb) {
|
|
if(TreeLength) {
|
|
ASSERT(Fcb->ReferenceCount);
|
|
ASSERT(NtReqFcb->CommonRefCount);
|
|
RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
|
|
ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount));
|
|
}
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
if(TreeLength)
|
|
TreeLength--;
|
|
ASSERT(Fcb->OpenHandleCount <= Fcb->ReferenceCount);
|
|
#else
|
|
if(TreeLength) {
|
|
RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
|
|
ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount));
|
|
TreeLength--;
|
|
}
|
|
#endif
|
|
|
|
/* if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) {
|
|
AdPrint((" %ws (%x)\n",
|
|
Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount));
|
|
} else if (Fcb) {
|
|
AdPrint((" ??? (%x)\n",Fcb->ReferenceCount));
|
|
} else {
|
|
AdPrint((" ??? (??)\n"));
|
|
}*/
|
|
// ...and delete if it has gone
|
|
|
|
if(!RefCount && !Fcb->OpenHandleCount) {
|
|
// no more references... current file/dir MUST DIE!!!
|
|
BOOLEAN AutoInherited = UDFIsAStreamDir(fi) || UDFIsAStream(fi);
|
|
|
|
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
|
|
// do nothing
|
|
} else
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
if(Delete) {
|
|
/* if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
|
|
// set file size to zero (for UdfInfo package)
|
|
// we should not do this for directories
|
|
UDFResizeFile__(Vcb, fi, 0);
|
|
}*/
|
|
UDFReferenceFile__(fi);
|
|
ASSERT(Fcb->ReferenceCount < fi->RefCount);
|
|
UDFFlushFile__(Vcb, fi);
|
|
UDFUnlinkFile__(Vcb, fi, TRUE);
|
|
UDFCloseFile__(Vcb, fi);
|
|
ASSERT(Fcb->ReferenceCount == fi->RefCount);
|
|
Fcb->FCBFlags |= UDF_FCB_DELETED;
|
|
Delete = FALSE;
|
|
} else
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
if(!(Fcb->FCBFlags & UDF_FCB_DELETED)) {
|
|
UDFFlushFile__(Vcb, fi);
|
|
} else {
|
|
// BrutePoint();
|
|
}
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
// check if we should try to delete Parent for the next time
|
|
if(Fcb->FCBFlags & UDF_FCB_DELETE_PARENT)
|
|
Delete = TRUE;
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
// remove references to OS-specific structures
|
|
// to let UDF_INFO release FI & Co
|
|
fi->Fcb = NULL;
|
|
if(!ComRefCount) {
|
|
// CommonFcb is also completly dereferenced
|
|
// Kill it!
|
|
fi->Dloc->CommonFcb = NULL;
|
|
}
|
|
|
|
if((CleanCode = UDFCleanUpFile__(Vcb, fi))) {
|
|
// Check, if we can uninitialize & deallocate CommonFcb part
|
|
// kill some cross links
|
|
Fcb->FileInfo = NULL;
|
|
// release allocated resources
|
|
if(CleanCode & UDF_FREE_DLOC) {
|
|
// Obviously, it is a good time & place to release
|
|
// CommonFcb structure
|
|
|
|
// NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID;
|
|
// Unitialize byte-range locks support structure
|
|
FsRtlUninitializeFileLock(&(NtReqFcb->FileLock));
|
|
// Remove resources
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFReleaseResource(&(NtReqFcb->MainResource));
|
|
if(NtReqFcb->CommonFCBHeader.Resource) {
|
|
UDFDeleteResource(&(NtReqFcb->MainResource));
|
|
UDFDeleteResource(&(NtReqFcb->PagingIoResource));
|
|
}
|
|
NtReqFcb->CommonFCBHeader.Resource =
|
|
NtReqFcb->CommonFCBHeader.PagingIoResource = NULL;
|
|
UDFDeassignAcl(NtReqFcb, AutoInherited);
|
|
UDFPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb));
|
|
#ifdef DBG
|
|
// NtReqFcb->FileObject->FsContext2 = NULL;
|
|
// ASSERT(NtReqFcb->FileObject);
|
|
/* if(NtReqFcb->FileObject) {
|
|
ASSERT(!NtReqFcb->FileObject->FsContext2);
|
|
NtReqFcb->FileObject->FsContext = NULL;
|
|
NtReqFcb->FileObject->SectionObjectPointer = NULL;
|
|
}*/
|
|
#endif //DBG
|
|
MyFreePool__(NtReqFcb);
|
|
ret_val |= UDF_CLOSE_NTREQFCB_DELETED;
|
|
} else {
|
|
// we usually get here when the file has some opened links
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFReleaseResource(&(NtReqFcb->MainResource));
|
|
}
|
|
// remove some references & free Fcb structure
|
|
Fcb->NTRequiredFCB = NULL;
|
|
Fcb->ParentFcb = NULL;
|
|
UDFCleanUpFCB(Fcb);
|
|
MyFreePool__(fi);
|
|
ret_val |= UDF_CLOSE_FCB_DELETED;
|
|
// get pointer to parent FCB
|
|
fi = ParentFI;
|
|
// free old parent's resource...
|
|
if(fi) {
|
|
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
|
UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
|
|
} else {
|
|
if(!VcbAcquired)
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
}
|
|
} else {
|
|
// Stop cleaning up
|
|
|
|
// Restore pointers
|
|
fi->Fcb = Fcb;
|
|
fi->Dloc->CommonFcb = NtReqFcb;
|
|
// free all acquired resources
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFReleaseResource(&(NtReqFcb->MainResource));
|
|
fi = ParentFI;
|
|
if(fi) {
|
|
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
|
UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
|
|
} else {
|
|
if(!VcbAcquired)
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
}
|
|
// If we have dereferenced all parents 'associated'
|
|
// with input file & current file is still in use
|
|
// then it isn't worth walking down the tree
|
|
// 'cause in this case all the rest files are also used
|
|
if(!TreeLength)
|
|
break;
|
|
// AdPrint(("Stop on referenced File/Dir\n"));
|
|
}
|
|
} else {
|
|
// we get to referenced file/dir. Stop search & release resource
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFReleaseResource(&(NtReqFcb->MainResource));
|
|
if(ParentFI) {
|
|
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
|
UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
|
|
} else {
|
|
if(!VcbAcquired)
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
}
|
|
Delete = FALSE;
|
|
if(!TreeLength)
|
|
break;
|
|
fi = ParentFI;
|
|
}
|
|
}
|
|
if(fi) {
|
|
Fcb = fi->Fcb;
|
|
for(;TreeLength && fi;TreeLength--) {
|
|
if(Fcb) {
|
|
ParentFcb = Fcb->ParentFcb;
|
|
ASSERT(Fcb->ReferenceCount);
|
|
ASSERT(Fcb->NTRequiredFCB->CommonRefCount);
|
|
ASSERT_REF(Fcb->ReferenceCount > fi->RefCount);
|
|
UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
|
|
UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount));
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
BrutePoint();
|
|
#endif
|
|
}
|
|
Fcb = ParentFcb;
|
|
}
|
|
}
|
|
if(!VcbAcquired)
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
return ret_val;
|
|
|
|
} // end UDFCleanUpFcbChain()
|
|
|
|
VOID
|
|
UDFDoDelayedClose(
|
|
IN PtrUDFIrpContextLite NextIrpContextLite
|
|
)
|
|
{
|
|
PtrUDFIrpContext IrpContext;
|
|
|
|
AdPrint((" UDFDoDelayedClose\n"));
|
|
UDFInitializeIrpContextFromLite(&IrpContext,NextIrpContextLite);
|
|
IrpContext->Fcb->IrpContextLite = NULL;
|
|
MyFreePool__(NextIrpContextLite);
|
|
IrpContext->Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;
|
|
UDFCommonClose(IrpContext,NULL);
|
|
} // end UDFDoDelayedClose()
|
|
|
|
/*
|
|
This routine removes request from Delayed Close queue.
|
|
It operates until reach lower threshold
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
UDFDelayedClose(
|
|
PVOID unused
|
|
)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PtrUDFIrpContextLite NextIrpContextLite;
|
|
|
|
AdPrint((" UDFDelayedClose\n"));
|
|
// Acquire DelayedCloseResource
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
|
|
|
|
while (UDFGlobalData.ReduceDelayedClose &&
|
|
(UDFGlobalData.DelayedCloseCount > UDFGlobalData.MinDelayedCloseCount)) {
|
|
|
|
Entry = UDFGlobalData.DelayedCloseQueue.Flink;
|
|
|
|
if (!IsListEmpty(Entry)) {
|
|
// Extract the IrpContext.
|
|
NextIrpContextLite = CONTAINING_RECORD( Entry,
|
|
UDFIrpContextLite,
|
|
DelayedCloseLinks );
|
|
|
|
RemoveEntryList( Entry );
|
|
UDFGlobalData.DelayedCloseCount--;
|
|
UDFDoDelayedClose(NextIrpContextLite);
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
}
|
|
|
|
while (UDFGlobalData.ReduceDirDelayedClose &&
|
|
(UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MinDirDelayedCloseCount)) {
|
|
|
|
Entry = UDFGlobalData.DirDelayedCloseQueue.Flink;
|
|
|
|
if (!IsListEmpty(Entry)) {
|
|
// Extract the IrpContext.
|
|
NextIrpContextLite = CONTAINING_RECORD( Entry,
|
|
UDFIrpContextLite,
|
|
DelayedCloseLinks );
|
|
|
|
RemoveEntryList( Entry );
|
|
UDFGlobalData.DirDelayedCloseCount--;
|
|
UDFDoDelayedClose(NextIrpContextLite);
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
}
|
|
|
|
UDFGlobalData.FspCloseActive = FALSE;
|
|
UDFGlobalData.ReduceDelayedClose = FALSE;
|
|
UDFGlobalData.ReduceDirDelayedClose = FALSE;
|
|
|
|
// Release DelayedCloseResource
|
|
UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
|
|
|
|
return;
|
|
} // end UDFDelayedClose()
|
|
|
|
/*
|
|
This routine performs Close operation for all files from
|
|
Delayed Close queue.
|
|
*/
|
|
VOID
|
|
UDFCloseAllDelayed(
|
|
IN PVCB Vcb
|
|
)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PtrUDFIrpContextLite NextIrpContextLite;
|
|
BOOLEAN GlobalDataAcquired = FALSE;
|
|
|
|
AdPrint((" UDFCloseAllDelayed\n"));
|
|
// Acquire DelayedCloseResource
|
|
if (!ExIsResourceAcquiredExclusive(&UDFGlobalData.GlobalDataResource)) {
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
|
|
GlobalDataAcquired = TRUE;
|
|
}
|
|
|
|
Entry = UDFGlobalData.DelayedCloseQueue.Flink;
|
|
|
|
while (Entry != &UDFGlobalData.DelayedCloseQueue) {
|
|
// Extract the IrpContext.
|
|
NextIrpContextLite = CONTAINING_RECORD( Entry,
|
|
UDFIrpContextLite,
|
|
DelayedCloseLinks );
|
|
Entry = Entry->Flink;
|
|
if (NextIrpContextLite->Fcb->Vcb == Vcb) {
|
|
RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
|
|
UDFGlobalData.DelayedCloseCount--;
|
|
UDFDoDelayedClose(NextIrpContextLite);
|
|
}
|
|
}
|
|
|
|
Entry = UDFGlobalData.DirDelayedCloseQueue.Flink;
|
|
|
|
while (Entry != &UDFGlobalData.DirDelayedCloseQueue) {
|
|
// Extract the IrpContext.
|
|
NextIrpContextLite = CONTAINING_RECORD( Entry,
|
|
UDFIrpContextLite,
|
|
DelayedCloseLinks );
|
|
Entry = Entry->Flink;
|
|
if (NextIrpContextLite->Fcb->Vcb == Vcb) {
|
|
RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
|
|
UDFGlobalData.DirDelayedCloseCount--;
|
|
UDFDoDelayedClose(NextIrpContextLite);
|
|
}
|
|
}
|
|
|
|
// Release DelayedCloseResource
|
|
if(GlobalDataAcquired)
|
|
UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
|
|
|
|
} // end UDFCloseAllDelayed()
|
|
|
|
NTSTATUS
|
|
UDFBuildTreeItemsList(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN PCHECK_TREE_ITEM CheckItemProc,
|
|
IN PUDF_FILE_INFO** PassedList,
|
|
IN PULONG PassedListSize,
|
|
IN PUDF_FILE_INFO** FoundList,
|
|
IN PULONG FoundListSize
|
|
)
|
|
{
|
|
PDIR_INDEX_HDR hDirNdx;
|
|
PUDF_FILE_INFO SDirInfo;
|
|
ULONG i;
|
|
|
|
UDFPrint((" UDFBuildTreeItemsList():\n"));
|
|
if(!(*PassedList) || !(*FoundList)) {
|
|
|
|
(*PassedList) = (PUDF_FILE_INFO*)
|
|
MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN);
|
|
if(!(*PassedList))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
(*PassedListSize) = 0;
|
|
|
|
(*FoundList) = (PUDF_FILE_INFO*)
|
|
MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN);
|
|
if(!(*FoundList)) {
|
|
MyFreePool__(*PassedList);
|
|
*PassedList = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
(*FoundListSize) = 0;
|
|
}
|
|
|
|
// check if already passed
|
|
for(i=0;i<(*PassedListSize);i++) {
|
|
if( ((*PassedList)[i]) == FileInfo )
|
|
return STATUS_SUCCESS;
|
|
}
|
|
// remember passed object
|
|
// we should not proceed linked objects twice
|
|
(*PassedListSize)++;
|
|
if( !((*PassedListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) {
|
|
if(!MyReallocPool__((PCHAR)(*PassedList), (*PassedListSize)*sizeof(PUDF_FILE_INFO),
|
|
(PCHAR*)PassedList, ((*PassedListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_FILE_INFO))) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
(*PassedList)[(*PassedListSize)-1] = FileInfo;
|
|
|
|
// check if this object matches our conditions
|
|
if(CheckItemProc(FileInfo)) {
|
|
// remember matched object
|
|
(*FoundListSize)++;
|
|
if( !((*FoundListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) {
|
|
if(!MyReallocPool__((PCHAR)(*FoundList), (*FoundListSize)*sizeof(PUDF_DATALOC_INFO),
|
|
(PCHAR*)FoundList, ((*FoundListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_DATALOC_INFO))) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
(*FoundList)[(*FoundListSize)-1] = FileInfo;
|
|
}
|
|
|
|
// walk through SDir (if any)
|
|
if((SDirInfo = FileInfo->Dloc->SDirInfo))
|
|
UDFBuildTreeItemsList(Vcb, SDirInfo, CheckItemProc,
|
|
PassedList, PassedListSize, FoundList, FoundListSize);
|
|
|
|
// walk through subsequent objects (if any)
|
|
if((hDirNdx = FileInfo->Dloc->DirIndex)) {
|
|
|
|
// scan DirIndex
|
|
UDF_DIR_SCAN_CONTEXT ScanContext;
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
PUDF_FILE_INFO CurFileInfo;
|
|
|
|
if(UDFDirIndexInitScan(FileInfo, &ScanContext, 2)) {
|
|
while((DirNdx = UDFDirIndexScan(&ScanContext, &CurFileInfo))) {
|
|
if(!CurFileInfo)
|
|
continue;
|
|
UDFBuildTreeItemsList(Vcb, CurFileInfo, CheckItemProc,
|
|
PassedList, PassedListSize, FoundList, FoundListSize);
|
|
}
|
|
}
|
|
|
|
}
|
|
return STATUS_SUCCESS;
|
|
} // end UDFBuildTreeItemsList()
|
|
|
|
BOOLEAN
|
|
UDFIsInDelayedCloseQueue(
|
|
PUDF_FILE_INFO FileInfo)
|
|
{
|
|
ASSERT(FileInfo);
|
|
return (FileInfo->Fcb && FileInfo->Fcb->IrpContextLite);
|
|
} // end UDFIsInDelayedCloseQueue()
|
|
|
|
BOOLEAN
|
|
UDFIsLastClose(
|
|
PUDF_FILE_INFO FileInfo)
|
|
{
|
|
ASSERT(FileInfo);
|
|
PtrUDFFCB Fcb = FileInfo->Fcb;
|
|
if( Fcb &&
|
|
!Fcb->OpenHandleCount &&
|
|
Fcb->ReferenceCount &&
|
|
Fcb->NTRequiredFCB->SectionObject.DataSectionObject) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
} // UDFIsLastClose()
|
|
|
|
NTSTATUS
|
|
UDFCloseAllXXXDelayedInDir(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN BOOLEAN System
|
|
)
|
|
{
|
|
PUDF_FILE_INFO* PassedList = NULL;
|
|
ULONG PassedListSize = 0;
|
|
PUDF_FILE_INFO* FoundList = NULL;
|
|
ULONG FoundListSize = 0;
|
|
NTSTATUS RC;
|
|
ULONG i;
|
|
BOOLEAN ResAcq = FALSE;
|
|
BOOLEAN AcquiredVcb = FALSE;
|
|
UDFNTRequiredFCB* NtReqFcb;
|
|
PUDF_FILE_INFO CurFileInfo;
|
|
PFE_LIST_ENTRY CurListPtr;
|
|
PFE_LIST_ENTRY* ListPtrArray = NULL;
|
|
|
|
_SEH2_TRY {
|
|
|
|
UDFPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n"));
|
|
// Acquire DelayedCloseResource
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
|
|
ResAcq = TRUE;
|
|
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVcb = TRUE;
|
|
|
|
RC = UDFBuildTreeItemsList(Vcb, FileInfo,
|
|
System ? UDFIsLastClose : UDFIsInDelayedCloseQueue,
|
|
&PassedList, &PassedListSize, &FoundList, &FoundListSize);
|
|
|
|
if(!NT_SUCCESS(RC)) {
|
|
UDFPrint((" UDFBuildTreeItemsList(): error %x\n", RC));
|
|
try_return(RC);
|
|
}
|
|
|
|
if(!FoundList || !FoundListSize) {
|
|
try_return(RC = STATUS_SUCCESS);
|
|
}
|
|
|
|
// build array of referenced pointers
|
|
ListPtrArray = (PFE_LIST_ENTRY*)(MyAllocatePool__(NonPagedPool, FoundListSize*sizeof(PFE_LIST_ENTRY)));
|
|
if(!ListPtrArray) {
|
|
UDFPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize));
|
|
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
for(i=0;i<FoundListSize;i++) {
|
|
|
|
_SEH2_TRY {
|
|
|
|
CurFileInfo = FoundList[i];
|
|
if(!CurFileInfo->ListPtr) {
|
|
CurFileInfo->ListPtr = (PFE_LIST_ENTRY)(MyAllocatePool__(NonPagedPool, sizeof(FE_LIST_ENTRY)));
|
|
if(!CurFileInfo->ListPtr) {
|
|
UDFPrint((" Can't alloc ListPtrEntry for items %x\n", i));
|
|
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
CurFileInfo->ListPtr->FileInfo = CurFileInfo;
|
|
CurFileInfo->ListPtr->EntryRefCount = 0;
|
|
}
|
|
CurFileInfo->ListPtr->EntryRefCount++;
|
|
ListPtrArray[i] = CurFileInfo->ListPtr;
|
|
|
|
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
}
|
|
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVcb = FALSE;
|
|
|
|
if(System) {
|
|
// Remove from system queue
|
|
PtrUDFFCB Fcb;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
BOOLEAN NoDelayed = (Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) ?
|
|
TRUE : FALSE;
|
|
|
|
Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
|
|
for(i=FoundListSize;i>0;i--) {
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVcb = TRUE;
|
|
_SEH2_TRY {
|
|
|
|
CurListPtr = ListPtrArray[i-1];
|
|
CurFileInfo = CurListPtr->FileInfo;
|
|
if(CurFileInfo &&
|
|
(Fcb = CurFileInfo->Fcb)) {
|
|
NtReqFcb = Fcb->NTRequiredFCB;
|
|
ASSERT((ULONG)NtReqFcb > 0x1000);
|
|
// ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000);
|
|
if(!(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) &&
|
|
(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) {
|
|
MmPrint((" CcFlushCache()\n"));
|
|
CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &IoStatus);
|
|
}
|
|
if(NtReqFcb->SectionObject.ImageSectionObject) {
|
|
MmPrint((" MmFlushImageSection()\n"));
|
|
MmFlushImageSection(&(NtReqFcb->SectionObject), MmFlushForWrite);
|
|
}
|
|
if(NtReqFcb->SectionObject.DataSectionObject) {
|
|
MmPrint((" CcPurgeCacheSection()\n"));
|
|
CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );
|
|
}
|
|
} else {
|
|
MmPrint((" Skip item: deleted\n"));
|
|
}
|
|
CurListPtr->EntryRefCount--;
|
|
if(!CurListPtr->EntryRefCount) {
|
|
if(CurListPtr->FileInfo)
|
|
CurListPtr->FileInfo->ListPtr = NULL;
|
|
MyFreePool__(CurListPtr);
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVcb = FALSE;
|
|
}
|
|
if(!NoDelayed)
|
|
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
|
|
} else {
|
|
// Remove from internal queue
|
|
PtrUDFIrpContextLite NextIrpContextLite;
|
|
|
|
for(i=FoundListSize;i>0;i--) {
|
|
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVcb = TRUE;
|
|
|
|
CurListPtr = ListPtrArray[i-1];
|
|
CurFileInfo = CurListPtr->FileInfo;
|
|
|
|
if(CurFileInfo &&
|
|
CurFileInfo->Fcb &&
|
|
(NextIrpContextLite = CurFileInfo->Fcb->IrpContextLite)) {
|
|
RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
|
|
if (NextIrpContextLite->Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
|
|
// BrutePoint();
|
|
UDFGlobalData.DirDelayedCloseCount--;
|
|
} else {
|
|
UDFGlobalData.DelayedCloseCount--;
|
|
}
|
|
UDFDoDelayedClose(NextIrpContextLite);
|
|
}
|
|
CurListPtr->EntryRefCount--;
|
|
if(!CurListPtr->EntryRefCount) {
|
|
if(CurListPtr->FileInfo)
|
|
CurListPtr->FileInfo->ListPtr = NULL;
|
|
MyFreePool__(CurListPtr);
|
|
}
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVcb = FALSE;
|
|
}
|
|
}
|
|
RC = STATUS_SUCCESS;
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
// release Vcb
|
|
if(AcquiredVcb)
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
// Release DelayedCloseResource
|
|
if(ResAcq)
|
|
UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
|
|
|
|
if(ListPtrArray)
|
|
MyFreePool__(ListPtrArray);
|
|
if(PassedList)
|
|
MyFreePool__(PassedList);
|
|
if(FoundList)
|
|
MyFreePool__(FoundList);
|
|
} _SEH2_END;
|
|
|
|
return RC;
|
|
} // end UDFCloseAllXXXDelayedInDir(
|
|
|
|
|
|
/*
|
|
This routine adds request to Delayed Close queue.
|
|
If number of queued requests exceeds higher threshold it fires
|
|
UDFDelayedClose()
|
|
*/
|
|
NTSTATUS
|
|
UDFQueueDelayedClose(
|
|
PtrUDFIrpContext IrpContext,
|
|
PtrUDFFCB Fcb
|
|
)
|
|
{
|
|
PtrUDFIrpContextLite IrpContextLite;
|
|
BOOLEAN StartWorker = FALSE;
|
|
_SEH2_VOLATILE BOOLEAN AcquiredVcb = FALSE;
|
|
NTSTATUS RC;
|
|
|
|
AdPrint((" UDFQueueDelayedClose\n"));
|
|
|
|
_SEH2_TRY {
|
|
// Acquire DelayedCloseResource
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
|
|
|
|
UDFAcquireResourceShared(&(Fcb->Vcb->VCBResource), TRUE);
|
|
AcquiredVcb = TRUE;
|
|
|
|
if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
|
|
try_return(RC = STATUS_DELETE_PENDING);
|
|
}
|
|
|
|
if(Fcb->IrpContextLite ||
|
|
Fcb->FCBFlags & UDF_FCB_POSTED_RENAME) {
|
|
// BrutePoint();
|
|
try_return(RC = STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
if(!NT_SUCCESS(RC = UDFInitializeIrpContextLite(&IrpContextLite,IrpContext,Fcb))) {
|
|
try_return(RC);
|
|
}
|
|
|
|
if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
|
|
InsertTailList( &UDFGlobalData.DirDelayedCloseQueue,
|
|
&IrpContextLite->DelayedCloseLinks );
|
|
UDFGlobalData.DirDelayedCloseCount++;
|
|
} else {
|
|
InsertTailList( &UDFGlobalData.DelayedCloseQueue,
|
|
&IrpContextLite->DelayedCloseLinks );
|
|
UDFGlobalData.DelayedCloseCount++;
|
|
}
|
|
Fcb->IrpContextLite = IrpContextLite;
|
|
|
|
// If we are above our threshold then start the delayed
|
|
// close operation.
|
|
if(UDFGlobalData.DelayedCloseCount > UDFGlobalData.MaxDelayedCloseCount) {
|
|
|
|
UDFGlobalData.ReduceDelayedClose = TRUE;
|
|
|
|
if(!UDFGlobalData.FspCloseActive) {
|
|
|
|
UDFGlobalData.FspCloseActive = TRUE;
|
|
StartWorker = TRUE;
|
|
}
|
|
}
|
|
// If we are above our threshold then start the delayed
|
|
// close operation.
|
|
if(UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MaxDirDelayedCloseCount) {
|
|
|
|
UDFGlobalData.ReduceDirDelayedClose = TRUE;
|
|
|
|
if(!UDFGlobalData.FspCloseActive) {
|
|
|
|
UDFGlobalData.FspCloseActive = TRUE;
|
|
StartWorker = TRUE;
|
|
}
|
|
}
|
|
// Start the FspClose thread if we need to.
|
|
if(StartWorker) {
|
|
ExQueueWorkItem( &UDFGlobalData.CloseItem, CriticalWorkQueue );
|
|
}
|
|
RC = STATUS_SUCCESS;
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if(!NT_SUCCESS(RC)) {
|
|
Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;
|
|
}
|
|
if(AcquiredVcb) {
|
|
UDFReleaseResource(&(Fcb->Vcb->VCBResource));
|
|
}
|
|
// Release DelayedCloseResource
|
|
UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
|
|
} _SEH2_END;
|
|
return RC;
|
|
} // end UDFQueueDelayedClose()
|
|
|