Something went wrong. Try again.
Reactos
Something went wrong. Try again.
42 kB · 1195 lines
C++
at master
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196////////////////////////////////////////////////////////////////////// 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
NTSTATUSUDFBuildTreeItemsList( 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 __fastcallBOOLEANUDFIsInDelayedCloseQueue( PUDF_FILE_INFO FileInfo);
BOOLEANUDFIsLastClose( 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**************************************************************************/NTSTATUSNTAPIUDFClose( 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**************************************************************************/NTSTATUSUDFCommonClose( 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 */ULONGUDFCleanUpFcbChain( 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()
VOIDUDFDoDelayedClose( 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 */VOIDNTAPIUDFDelayedClose( 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. */VOIDUDFCloseAllDelayed( 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()
NTSTATUSUDFBuildTreeItemsList( 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()
BOOLEANUDFIsInDelayedCloseQueue( PUDF_FILE_INFO FileInfo){ ASSERT(FileInfo); return (FileInfo->Fcb && FileInfo->Fcb->IrpContextLite);} // end UDFIsInDelayedCloseQueue()
BOOLEANUDFIsLastClose( 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()
NTSTATUSUDFCloseAllXXXDelayedInDir( 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; _SEH2_VOLATILE BOOLEAN ResAcq = FALSE; _SEH2_VOLATILE 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_PTR)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() */NTSTATUSUDFQueueDelayedClose( 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()