+++ /dev/null
-////////////////////////////////////////////////////////////////////
-// 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()
-