1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "Close" dispatch entry point.
15 *************************************************************************/
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_CLOSE
22 typedef BOOLEAN (*PCHECK_TREE_ITEM
) (IN PUDF_FILE_INFO FileInfo
);
23 #define TREE_ITEM_LIST_GRAN 32
26 UDFBuildTreeItemsList(
28 IN PUDF_FILE_INFO FileInfo
,
29 IN PCHECK_TREE_ITEM CheckItemProc
,
30 IN PUDF_DATALOC_INFO
** PassedList
,
31 IN PULONG PassedListSize
,
32 IN PUDF_DATALOC_INFO
** FoundList
,
33 IN PULONG FoundListSize
);
35 // callbacks, can't be __fastcall
37 UDFIsInDelayedCloseQueue(
38 PUDF_FILE_INFO FileInfo
);
42 PUDF_FILE_INFO FileInfo
);
44 /*************************************************************************
46 * Function: UDFClose()
49 * The I/O Manager will invoke this routine to handle a close
52 * Expected Interrupt Level (for execution) :
54 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
55 * to be deferred to a worker thread context)
57 * Return Value: STATUS_SUCCESS
59 *************************************************************************/
63 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
64 PIRP Irp
// I/O Request Packet
67 NTSTATUS RC
= STATUS_SUCCESS
;
68 PtrUDFIrpContext PtrIrpContext
= NULL
;
69 BOOLEAN AreWeTopLevel
= FALSE
;
71 AdPrint(("UDFClose: \n"));
73 FsRtlEnterFileSystem();
77 // If we were called with our file system device object instead of a
78 // volume device object, just complete this request with STATUS_SUCCESS
79 if (UDFIsFSDevObj(DeviceObject
)) {
80 // this is a close of the FSD itself
81 Irp
->IoStatus
.Status
= RC
;
82 Irp
->IoStatus
.Information
= 0;
84 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
85 FsRtlExitFileSystem();
89 // set the top level context
90 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
94 // get an IRP context structure and issue the request
95 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
96 ASSERT(PtrIrpContext
);
98 RC
= UDFCommonClose(PtrIrpContext
, Irp
);
100 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
102 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
104 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
108 IoSetTopLevelIrp(NULL
);
111 FsRtlExitFileSystem();
119 /*************************************************************************
121 * Function: UDFCommonClose()
124 * The actual work is performed here. This routine may be invoked in one'
125 * of the two possible contexts:
126 * (a) in the context of a system worker thread
127 * (b) in the context of the original caller
129 * Expected Interrupt Level (for execution) :
133 * Return Value: must be STATUS_SUCCESS
135 *************************************************************************/
138 PtrUDFIrpContext PtrIrpContext
,
142 NTSTATUS RC
= STATUS_SUCCESS
;
143 PIO_STACK_LOCATION IrpSp
= NULL
;
144 PFILE_OBJECT FileObject
= NULL
;
145 PtrUDFFCB Fcb
= NULL
;
146 PtrUDFCCB Ccb
= NULL
;
148 // PERESOURCE PtrResourceAcquired = NULL;
149 BOOLEAN AcquiredVcb
= FALSE
;
150 BOOLEAN AcquiredGD
= FALSE
;
153 // ULONG clean_stat = 0;
155 // BOOLEAN CompleteIrp = TRUE;
156 BOOLEAN PostRequest
= FALSE
;
159 UNICODE_STRING CurName
;
160 PDIR_INDEX_HDR DirNdx
;
163 AdPrint(("UDFCommonClose: \n"));
168 // If this is the first (IOManager) request
169 // First, get a pointer to the current I/O stack location
170 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
173 FileObject
= IrpSp
->FileObject
;
176 // Get the FCB and CCB pointers
177 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
179 if(Ccb
->CCBFlags
& UDF_CCB_READ_ONLY
) {
180 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_READ_ONLY
;
184 // If this is a queued call (for our dispatch)
185 // Get saved Fcb address
186 Fcb
= PtrIrpContext
->Fcb
;
187 i
= PtrIrpContext
->TreeLength
;
191 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
193 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
194 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
196 // Steps we shall take at this point are:
197 // (a) Acquire the VCB shared
198 // (b) Acquire the FCB's CCB list exclusively
199 // (c) Delete the CCB structure (free memory)
200 // (d) If this is the last close, release the FCB structure
201 // (unless we keep these around for "delayed close" functionality.
202 // Note that it is often the case that the close dispatch entry point is invoked
203 // in the most inconvenient of situations (when it is not possible, for example,
204 // to safely acquire certain required resources without deadlocking or waiting).
205 // Therefore, be extremely careful in implementing this close dispatch entry point.
206 // Also note that we do not have the option of returning a failure code from the
207 // close dispatch entry point; the system expects that the close will always succeed.
209 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
212 // Is this is the first (IOManager) request ?
214 PtrIrpContext
->TreeLength
=
216 // remember the number of incomplete Close requests
217 InterlockedIncrement((PLONG
)&(Fcb
->CcbCount
));
218 // we can release CCB in any case
220 FileObject
->FsContext2
= NULL
;
223 ASSERT(Fcb->NTRequiredFCB);
224 if(Fcb->NTRequiredFCB) {
225 ASSERT(Fcb->NTRequiredFCB->FileObject);
226 if(Fcb->NTRequiredFCB->FileObject) {
227 ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2);
233 #ifdef UDF_DELAYED_CLOSE
234 // check if this is the last Close (no more Handles)
235 // and try to Delay it....
236 if((Fcb
->FCBFlags
& UDF_FCB_DELAY_CLOSE
) &&
237 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) &&
238 !(Vcb
->VCBFlags
& UDF_VCB_FLAGS_NO_DELAYED_CLOSE
) &&
239 !(Fcb
->OpenHandleCount
)) {
240 UDFReleaseResource(&(Vcb
->VCBResource
));
242 if((RC
= UDFQueueDelayedClose(PtrIrpContext
,Fcb
)) == STATUS_SUCCESS
)
243 try_return(RC
= STATUS_SUCCESS
);
244 // do standard Close if we can't Delay this opeartion
245 AdPrint((" Cant queue Close Irp, status=%x\n", RC
));
247 #endif //UDF_DELAYED_CLOSE
250 // We should post actual procesing if this is a recursive call
251 if((PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_NOT_TOP_LEVEL
) ||
252 (Fcb
->NTRequiredFCB
->AcqFlushCount
)) {
253 AdPrint((" post NOT_TOP_LEVEL Irp\n"));
255 try_return(RC
= STATUS_SUCCESS
);
259 // Close request is near completion, Vcb is acquired.
260 // Now we can safely decrease CcbCount, because no Rename
261 // operation can run until Vcb release.
262 InterlockedDecrement((PLONG
)&(Fcb
->CcbCount
));
264 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
265 if(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_READ_ONLY
)
266 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCountRO
));
268 if(!i
|| (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
)) {
270 AdPrint(("UDF: Closing volume\n"));
271 AdPrint(("UDF: ReferenceCount: %x\n",Fcb
->ReferenceCount
));
273 if (Vcb
->VCBOpenCount
> UDF_RESIDUAL_REFERENCE
) {
274 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
275 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
276 ASSERT(Fcb
->NTRequiredFCB
);
277 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
279 try_return(RC
= STATUS_SUCCESS
);
282 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
285 UDFReleaseResource(&(Vcb
->VCBResource
));
290 // Acquire GlobalDataResource
291 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
294 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
297 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
300 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
301 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
302 ASSERT(Fcb
->NTRequiredFCB
);
303 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
305 //AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n"));
306 //UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);
308 AdPrint(("UDF: Closing volume, reset write status\n"));
309 RC
= UDFPhSendIOCTL(IOCTL_CDRW_RESET_WRITE_STATUS
, Vcb
->TargetDeviceObject
,
310 NULL
, 0, NULL
, 0, TRUE
, NULL
);
312 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
) ||
313 ((!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) && (Vcb
->VCBOpenCount
<= UDF_RESIDUAL_REFERENCE
))) {
314 // Try to KILL dismounted volume....
315 // w2k requires this, NT4 - recomends
316 AcquiredVcb
= UDFCheckForDismount(PtrIrpContext
, Vcb
, TRUE
);
319 try_return(RC
= STATUS_SUCCESS
);
328 DirNdx
= UDFGetDirIndexByFileInfo(fi
);
330 CurName
.Buffer
= UDFDirIndex(DirNdx
,fi
->Index
)->FName
.Buffer
;
332 AdPrint(("Closing file: %ws %8.8x\n", CurName
.Buffer
, FileObject
));
334 AdPrint(("Closing file: ??? \n"));
337 AdPrint(("UDF: ReferenceCount: %x\n",Fcb
->ReferenceCount
));
339 // try to clean up as long chain as it is possible
340 UDFCleanUpFcbChain(Vcb
, fi
, i
, TRUE
);
347 UDFReleaseResource(&(Vcb
->VCBResource
));
350 UDFReleaseResource(&(UDFGlobalData
.GlobalDataResource
));
353 // Post IRP if required
356 // Perform the post operation & complete the IRP
357 // if this is first call of UDFCommonClose
358 // and will return STATUS_SUCCESS back to us
359 PtrIrpContext
->Irp
= NULL
;
360 PtrIrpContext
->Fcb
= Fcb
;
361 UDFPostRequest(PtrIrpContext
, NULL
);
364 if (!_SEH2_AbnormalTermination()) {
365 // If this is not async close complete the IRP
367 /* if( FileObject ) {
368 if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) {
369 // ASSERT(!FileObject->FsContext2);
370 FileObject->FsContext = NULL;
373 UDFNTRequiredFCB* NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext));
374 if(NtReqFcb->FileObject == FileObject) {
375 NtReqFcb->FileObject = NULL;
380 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
381 Irp
->IoStatus
.Information
= 0;
382 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
384 // Free up the Irp Context
386 UDFReleaseIrpContext(PtrIrpContext
);
389 } _SEH2_END
; // end of "__finally" processing
391 return STATUS_SUCCESS
;
392 } // end UDFCommonClose()
395 This routine walks through the tree to RootDir & kills all unreferenced
402 IN PUDF_FILE_INFO fi
,
404 IN BOOLEAN VcbAcquired
407 PtrUDFFCB Fcb
= NULL
;
408 PtrUDFFCB ParentFcb
= NULL
;
409 PUDF_FILE_INFO ParentFI
;
410 UDFNTRequiredFCB
* NtReqFcb
;
412 LONG RefCount
, ComRefCount
;
413 BOOLEAN Delete
= FALSE
;
416 ValidateFileInfo(fi
);
417 AdPrint(("UDFCleanUpFcbChain\n"));
421 // we can't process Tree until we can acquire Vcb
423 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
425 // cleanup parent chain (if any & unused)
429 if((ParentFI
= fi
->ParentFile
)) {
431 ParentFcb
= fi
->Fcb
->ParentFcb
;
433 ASSERT(ParentFcb
->NTRequiredFCB
);
434 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
435 UDFAcquireResourceExclusive(&(ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
437 // we get to RootDir, it has no parent
439 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
442 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
444 NtReqFcb
= Fcb
->NTRequiredFCB
;
445 ASSERT(NtReqFcb
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
447 // acquire current file/dir
448 // we must assure that no more threads try to re-use this object
452 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
453 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
455 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
458 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
459 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
462 UDFReleaseResource(&(Vcb
->VCBResource
));
467 ASSERT_REF((Fcb
->ReferenceCount
> fi
->RefCount
) || !TreeLength
);
468 // If we haven't pass through all files opened
469 // in UDFCommonCreate before target file (TreeLength specfies
470 // the number of such files) dereference them.
471 // Otherwise we'll just check if the file has no references.
475 ASSERT(Fcb
->ReferenceCount
);
476 ASSERT(NtReqFcb
->CommonRefCount
);
477 RefCount
= UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
478 ComRefCount
= UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
485 ASSERT(Fcb
->OpenHandleCount
<= Fcb
->ReferenceCount
);
488 RefCount
= UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
489 ComRefCount
= UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
494 /* if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) {
495 AdPrint((" %ws (%x)\n",
496 Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount));
498 AdPrint((" ??? (%x)\n",Fcb->ReferenceCount));
500 AdPrint((" ??? (??)\n"));
502 // ...and delete if it has gone
504 if(!RefCount
&& !Fcb
->OpenHandleCount
) {
505 // no more references... current file/dir MUST DIE!!!
506 BOOLEAN AutoInherited
= UDFIsAStreamDir(fi
) || UDFIsAStream(fi
);
508 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) {
511 #ifndef UDF_READ_ONLY_BUILD
513 /* if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
514 // set file size to zero (for UdfInfo package)
515 // we should not do this for directories
516 UDFResizeFile__(Vcb, fi, 0);
518 UDFReferenceFile__(fi
);
519 ASSERT(Fcb
->ReferenceCount
< fi
->RefCount
);
520 UDFFlushFile__(Vcb
, fi
);
521 UDFUnlinkFile__(Vcb
, fi
, TRUE
);
522 UDFCloseFile__(Vcb
, fi
);
523 ASSERT(Fcb
->ReferenceCount
== fi
->RefCount
);
524 Fcb
->FCBFlags
|= UDF_FCB_DELETED
;
527 #endif //UDF_READ_ONLY_BUILD
528 if(!(Fcb
->FCBFlags
& UDF_FCB_DELETED
)) {
529 UDFFlushFile__(Vcb
, fi
);
533 #ifndef UDF_READ_ONLY_BUILD
534 // check if we should try to delete Parent for the next time
535 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_PARENT
)
537 #endif //UDF_READ_ONLY_BUILD
539 // remove references to OS-specific structures
540 // to let UDF_INFO release FI & Co
543 // CommonFcb is also completly dereferenced
545 fi
->Dloc
->CommonFcb
= NULL
;
548 if((CleanCode
= UDFCleanUpFile__(Vcb
, fi
))) {
549 // Check, if we can uninitialize & deallocate CommonFcb part
550 // kill some cross links
551 Fcb
->FileInfo
= NULL
;
552 // release allocated resources
553 if(CleanCode
& UDF_FREE_DLOC
) {
554 // Obviously, it is a good time & place to release
555 // CommonFcb structure
557 // NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID;
558 // Unitialize byte-range locks support structure
559 FsRtlUninitializeFileLock(&(NtReqFcb
->FileLock
));
561 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
562 UDFReleaseResource(&(NtReqFcb
->MainResource
));
563 if(NtReqFcb
->CommonFCBHeader
.Resource
) {
564 UDFDeleteResource(&(NtReqFcb
->MainResource
));
565 UDFDeleteResource(&(NtReqFcb
->PagingIoResource
));
567 NtReqFcb
->CommonFCBHeader
.Resource
=
568 NtReqFcb
->CommonFCBHeader
.PagingIoResource
= NULL
;
569 UDFDeassignAcl(NtReqFcb
, AutoInherited
);
570 UDFPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb
));
572 // NtReqFcb->FileObject->FsContext2 = NULL;
573 // ASSERT(NtReqFcb->FileObject);
574 /* if(NtReqFcb->FileObject) {
575 ASSERT(!NtReqFcb->FileObject->FsContext2);
576 NtReqFcb->FileObject->FsContext = NULL;
577 NtReqFcb->FileObject->SectionObjectPointer = NULL;
580 MyFreePool__(NtReqFcb
);
581 ret_val
|= UDF_CLOSE_NTREQFCB_DELETED
;
583 // we usually get here when the file has some opened links
584 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
585 UDFReleaseResource(&(NtReqFcb
->MainResource
));
587 // remove some references & free Fcb structure
588 Fcb
->NTRequiredFCB
= NULL
;
589 Fcb
->ParentFcb
= NULL
;
592 ret_val
|= UDF_CLOSE_FCB_DELETED
;
593 // get pointer to parent FCB
595 // free old parent's resource...
597 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
598 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
601 UDFReleaseResource(&(Vcb
->VCBResource
));
608 fi
->Dloc
->CommonFcb
= NtReqFcb
;
609 // free all acquired resources
610 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
611 UDFReleaseResource(&(NtReqFcb
->MainResource
));
614 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
615 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
618 UDFReleaseResource(&(Vcb
->VCBResource
));
620 // If we have dereferenced all parents 'associated'
621 // with input file & current file is still in use
622 // then it isn't worth walking down the tree
623 // 'cause in this case all the rest files are also used
626 // AdPrint(("Stop on referenced File/Dir\n"));
629 // we get to referenced file/dir. Stop search & release resource
630 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
631 UDFReleaseResource(&(NtReqFcb
->MainResource
));
633 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
634 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
637 UDFReleaseResource(&(Vcb
->VCBResource
));
647 for(;TreeLength
&& fi
;TreeLength
--) {
649 ParentFcb
= Fcb
->ParentFcb
;
650 ASSERT(Fcb
->ReferenceCount
);
651 ASSERT(Fcb
->NTRequiredFCB
->CommonRefCount
);
652 ASSERT_REF(Fcb
->ReferenceCount
> fi
->RefCount
);
653 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
654 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
664 UDFReleaseResource(&(Vcb
->VCBResource
));
667 } // end UDFCleanUpFcbChain()
671 IN PtrUDFIrpContextLite NextIrpContextLite
674 PtrUDFIrpContext IrpContext
;
676 AdPrint((" UDFDoDelayedClose\n"));
677 UDFInitializeIrpContextFromLite(&IrpContext
,NextIrpContextLite
);
678 IrpContext
->Fcb
->IrpContextLite
= NULL
;
679 MyFreePool__(NextIrpContextLite
);
680 IrpContext
->Fcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
681 UDFCommonClose(IrpContext
,NULL
);
682 } // end UDFDoDelayedClose()
685 This routine removes request from Delayed Close queue.
686 It operates until reach lower threshold
694 PtrUDFIrpContextLite NextIrpContextLite
;
696 AdPrint((" UDFDelayedClose\n"));
697 // Acquire DelayedCloseResource
698 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
700 while (UDFGlobalData
.ReduceDelayedClose
&&
701 (UDFGlobalData
.DelayedCloseCount
> UDFGlobalData
.MinDelayedCloseCount
)) {
703 Entry
= UDFGlobalData
.DelayedCloseQueue
.Flink
;
705 if (!IsListEmpty(Entry
)) {
706 // Extract the IrpContext.
707 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
711 RemoveEntryList( Entry
);
712 UDFGlobalData
.DelayedCloseCount
--;
713 UDFDoDelayedClose(NextIrpContextLite
);
719 while (UDFGlobalData
.ReduceDirDelayedClose
&&
720 (UDFGlobalData
.DirDelayedCloseCount
> UDFGlobalData
.MinDirDelayedCloseCount
)) {
722 Entry
= UDFGlobalData
.DirDelayedCloseQueue
.Flink
;
724 if (!IsListEmpty(Entry
)) {
725 // Extract the IrpContext.
726 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
730 RemoveEntryList( Entry
);
731 UDFGlobalData
.DirDelayedCloseCount
--;
732 UDFDoDelayedClose(NextIrpContextLite
);
738 UDFGlobalData
.FspCloseActive
= FALSE
;
739 UDFGlobalData
.ReduceDelayedClose
= FALSE
;
740 UDFGlobalData
.ReduceDirDelayedClose
= FALSE
;
742 // Release DelayedCloseResource
743 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
746 } // end UDFDelayedClose()
749 This routine performs Close operation for all files from
758 PtrUDFIrpContextLite NextIrpContextLite
;
759 BOOLEAN GlobalDataAcquired
= FALSE
;
761 AdPrint((" UDFCloseAllDelayed\n"));
762 // Acquire DelayedCloseResource
763 if (!ExIsResourceAcquiredExclusive(&UDFGlobalData
.GlobalDataResource
)) {
764 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
765 GlobalDataAcquired
= TRUE
;
768 Entry
= UDFGlobalData
.DelayedCloseQueue
.Flink
;
770 while (Entry
!= &UDFGlobalData
.DelayedCloseQueue
) {
771 // Extract the IrpContext.
772 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
775 Entry
= Entry
->Flink
;
776 if (NextIrpContextLite
->Fcb
->Vcb
== Vcb
) {
777 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
778 UDFGlobalData
.DelayedCloseCount
--;
779 UDFDoDelayedClose(NextIrpContextLite
);
783 Entry
= UDFGlobalData
.DirDelayedCloseQueue
.Flink
;
785 while (Entry
!= &UDFGlobalData
.DirDelayedCloseQueue
) {
786 // Extract the IrpContext.
787 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
790 Entry
= Entry
->Flink
;
791 if (NextIrpContextLite
->Fcb
->Vcb
== Vcb
) {
792 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
793 UDFGlobalData
.DirDelayedCloseCount
--;
794 UDFDoDelayedClose(NextIrpContextLite
);
798 // Release DelayedCloseResource
799 if(GlobalDataAcquired
)
800 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
802 } // end UDFCloseAllDelayed()
805 UDFBuildTreeItemsList(
807 IN PUDF_FILE_INFO FileInfo
,
808 IN PCHECK_TREE_ITEM CheckItemProc
,
809 IN PUDF_FILE_INFO
** PassedList
,
810 IN PULONG PassedListSize
,
811 IN PUDF_FILE_INFO
** FoundList
,
812 IN PULONG FoundListSize
815 PDIR_INDEX_HDR hDirNdx
;
816 PUDF_FILE_INFO SDirInfo
;
819 UDFPrint((" UDFBuildTreeItemsList():\n"));
820 if(!(*PassedList
) || !(*FoundList
)) {
822 (*PassedList
) = (PUDF_FILE_INFO
*)
823 MyAllocatePool__(NonPagedPool
, sizeof(PUDF_FILE_INFO
)*TREE_ITEM_LIST_GRAN
);
825 return STATUS_INSUFFICIENT_RESOURCES
;
826 (*PassedListSize
) = 0;
828 (*FoundList
) = (PUDF_FILE_INFO
*)
829 MyAllocatePool__(NonPagedPool
, sizeof(PUDF_FILE_INFO
)*TREE_ITEM_LIST_GRAN
);
831 MyFreePool__(*PassedList
);
833 return STATUS_INSUFFICIENT_RESOURCES
;
835 (*FoundListSize
) = 0;
838 // check if already passed
839 for(i
=0;i
<(*PassedListSize
);i
++) {
840 if( ((*PassedList
)[i
]) == FileInfo
)
841 return STATUS_SUCCESS
;
843 // remember passed object
844 // we should not proceed linked objects twice
846 if( !((*PassedListSize
) & (TREE_ITEM_LIST_GRAN
- 1)) ) {
847 if(!MyReallocPool__((PCHAR
)(*PassedList
), (*PassedListSize
)*sizeof(PUDF_FILE_INFO
),
848 (PCHAR
*)PassedList
, ((*PassedListSize
)+TREE_ITEM_LIST_GRAN
)*sizeof(PUDF_FILE_INFO
))) {
849 return STATUS_INSUFFICIENT_RESOURCES
;
852 (*PassedList
)[(*PassedListSize
)-1] = FileInfo
;
854 // check if this object matches our conditions
855 if(CheckItemProc(FileInfo
)) {
856 // remember matched object
858 if( !((*FoundListSize
) & (TREE_ITEM_LIST_GRAN
- 1)) ) {
859 if(!MyReallocPool__((PCHAR
)(*FoundList
), (*FoundListSize
)*sizeof(PUDF_DATALOC_INFO
),
860 (PCHAR
*)FoundList
, ((*FoundListSize
)+TREE_ITEM_LIST_GRAN
)*sizeof(PUDF_DATALOC_INFO
))) {
861 return STATUS_INSUFFICIENT_RESOURCES
;
864 (*FoundList
)[(*FoundListSize
)-1] = FileInfo
;
867 // walk through SDir (if any)
868 if((SDirInfo
= FileInfo
->Dloc
->SDirInfo
))
869 UDFBuildTreeItemsList(Vcb
, SDirInfo
, CheckItemProc
,
870 PassedList
, PassedListSize
, FoundList
, FoundListSize
);
872 // walk through subsequent objects (if any)
873 if((hDirNdx
= FileInfo
->Dloc
->DirIndex
)) {
876 UDF_DIR_SCAN_CONTEXT ScanContext
;
877 PDIR_INDEX_ITEM DirNdx
;
878 PUDF_FILE_INFO CurFileInfo
;
880 if(UDFDirIndexInitScan(FileInfo
, &ScanContext
, 2)) {
881 while((DirNdx
= UDFDirIndexScan(&ScanContext
, &CurFileInfo
))) {
884 UDFBuildTreeItemsList(Vcb
, CurFileInfo
, CheckItemProc
,
885 PassedList
, PassedListSize
, FoundList
, FoundListSize
);
890 return STATUS_SUCCESS
;
891 } // end UDFBuildTreeItemsList()
894 UDFIsInDelayedCloseQueue(
895 PUDF_FILE_INFO FileInfo
)
898 return (FileInfo
->Fcb
&& FileInfo
->Fcb
->IrpContextLite
);
899 } // end UDFIsInDelayedCloseQueue()
903 PUDF_FILE_INFO FileInfo
)
906 PtrUDFFCB Fcb
= FileInfo
->Fcb
;
908 !Fcb
->OpenHandleCount
&&
909 Fcb
->ReferenceCount
&&
910 Fcb
->NTRequiredFCB
->SectionObject
.DataSectionObject
) {
914 } // UDFIsLastClose()
917 UDFCloseAllXXXDelayedInDir(
919 IN PUDF_FILE_INFO FileInfo
,
923 PUDF_FILE_INFO
* PassedList
= NULL
;
924 ULONG PassedListSize
= 0;
925 PUDF_FILE_INFO
* FoundList
= NULL
;
926 ULONG FoundListSize
= 0;
929 BOOLEAN ResAcq
= FALSE
;
930 BOOLEAN AcquiredVcb
= FALSE
;
931 UDFNTRequiredFCB
* NtReqFcb
;
932 PUDF_FILE_INFO CurFileInfo
;
933 PFE_LIST_ENTRY CurListPtr
;
934 PFE_LIST_ENTRY
* ListPtrArray
= NULL
;
938 UDFPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n"));
939 // Acquire DelayedCloseResource
940 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
943 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
946 RC
= UDFBuildTreeItemsList(Vcb
, FileInfo
,
947 System
? UDFIsLastClose
: UDFIsInDelayedCloseQueue
,
948 &PassedList
, &PassedListSize
, &FoundList
, &FoundListSize
);
950 if(!NT_SUCCESS(RC
)) {
951 UDFPrint((" UDFBuildTreeItemsList(): error %x\n", RC
));
955 if(!FoundList
|| !FoundListSize
) {
956 try_return(RC
= STATUS_SUCCESS
);
959 // build array of referenced pointers
960 ListPtrArray
= (PFE_LIST_ENTRY
*)(MyAllocatePool__(NonPagedPool
, FoundListSize
*sizeof(PFE_LIST_ENTRY
)));
962 UDFPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize
));
963 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
966 for(i
=0;i
<FoundListSize
;i
++) {
970 CurFileInfo
= FoundList
[i
];
971 if(!CurFileInfo
->ListPtr
) {
972 CurFileInfo
->ListPtr
= (PFE_LIST_ENTRY
)(MyAllocatePool__(NonPagedPool
, sizeof(FE_LIST_ENTRY
)));
973 if(!CurFileInfo
->ListPtr
) {
974 UDFPrint((" Can't alloc ListPtrEntry for items %x\n", i
));
975 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
977 CurFileInfo
->ListPtr
->FileInfo
= CurFileInfo
;
978 CurFileInfo
->ListPtr
->EntryRefCount
= 0;
980 CurFileInfo
->ListPtr
->EntryRefCount
++;
981 ListPtrArray
[i
] = CurFileInfo
->ListPtr
;
983 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
988 UDFReleaseResource(&(Vcb
->VCBResource
));
992 // Remove from system queue
994 IO_STATUS_BLOCK IoStatus
;
995 BOOLEAN NoDelayed
= (Vcb
->VCBFlags
& UDF_VCB_FLAGS_NO_DELAYED_CLOSE
) ?
998 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
999 for(i
=FoundListSize
;i
>0;i
--) {
1000 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1004 CurListPtr
= ListPtrArray
[i
-1];
1005 CurFileInfo
= CurListPtr
->FileInfo
;
1007 (Fcb
= CurFileInfo
->Fcb
)) {
1008 NtReqFcb
= Fcb
->NTRequiredFCB
;
1009 ASSERT((ULONG
)NtReqFcb
> 0x1000);
1010 // ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000);
1011 if(!(NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_DELETED
) &&
1012 (NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_MODIFIED
)) {
1013 MmPrint((" CcFlushCache()\n"));
1014 CcFlushCache(&(NtReqFcb
->SectionObject
), NULL
, 0, &IoStatus
);
1016 if(NtReqFcb
->SectionObject
.ImageSectionObject
) {
1017 MmPrint((" MmFlushImageSection()\n"));
1018 MmFlushImageSection(&(NtReqFcb
->SectionObject
), MmFlushForWrite
);
1020 if(NtReqFcb
->SectionObject
.DataSectionObject
) {
1021 MmPrint((" CcPurgeCacheSection()\n"));
1022 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
1025 MmPrint((" Skip item: deleted\n"));
1027 CurListPtr
->EntryRefCount
--;
1028 if(!CurListPtr
->EntryRefCount
) {
1029 if(CurListPtr
->FileInfo
)
1030 CurListPtr
->FileInfo
->ListPtr
= NULL
;
1031 MyFreePool__(CurListPtr
);
1033 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1036 UDFReleaseResource(&(Vcb
->VCBResource
));
1037 AcquiredVcb
= FALSE
;
1040 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
1042 // Remove from internal queue
1043 PtrUDFIrpContextLite NextIrpContextLite
;
1045 for(i
=FoundListSize
;i
>0;i
--) {
1047 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1050 CurListPtr
= ListPtrArray
[i
-1];
1051 CurFileInfo
= CurListPtr
->FileInfo
;
1055 (NextIrpContextLite
= CurFileInfo
->Fcb
->IrpContextLite
)) {
1056 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
1057 if (NextIrpContextLite
->Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1059 UDFGlobalData
.DirDelayedCloseCount
--;
1061 UDFGlobalData
.DelayedCloseCount
--;
1063 UDFDoDelayedClose(NextIrpContextLite
);
1065 CurListPtr
->EntryRefCount
--;
1066 if(!CurListPtr
->EntryRefCount
) {
1067 if(CurListPtr
->FileInfo
)
1068 CurListPtr
->FileInfo
->ListPtr
= NULL
;
1069 MyFreePool__(CurListPtr
);
1071 UDFReleaseResource(&(Vcb
->VCBResource
));
1072 AcquiredVcb
= FALSE
;
1075 RC
= STATUS_SUCCESS
;
1082 UDFReleaseResource(&(Vcb
->VCBResource
));
1083 // Release DelayedCloseResource
1085 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
1088 MyFreePool__(ListPtrArray
);
1090 MyFreePool__(PassedList
);
1092 MyFreePool__(FoundList
);
1096 } // end UDFCloseAllXXXDelayedInDir(
1100 This routine adds request to Delayed Close queue.
1101 If number of queued requests exceeds higher threshold it fires
1105 UDFQueueDelayedClose(
1106 PtrUDFIrpContext IrpContext
,
1110 PtrUDFIrpContextLite IrpContextLite
;
1111 BOOLEAN StartWorker
= FALSE
;
1112 _SEH2_VOLATILE BOOLEAN AcquiredVcb
= FALSE
;
1115 AdPrint((" UDFQueueDelayedClose\n"));
1118 // Acquire DelayedCloseResource
1119 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
1121 UDFAcquireResourceShared(&(Fcb
->Vcb
->VCBResource
), TRUE
);
1124 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
1125 try_return(RC
= STATUS_DELETE_PENDING
);
1128 if(Fcb
->IrpContextLite
||
1129 Fcb
->FCBFlags
& UDF_FCB_POSTED_RENAME
) {
1131 try_return(RC
= STATUS_UNSUCCESSFUL
);
1134 if(!NT_SUCCESS(RC
= UDFInitializeIrpContextLite(&IrpContextLite
,IrpContext
,Fcb
))) {
1138 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1139 InsertTailList( &UDFGlobalData
.DirDelayedCloseQueue
,
1140 &IrpContextLite
->DelayedCloseLinks
);
1141 UDFGlobalData
.DirDelayedCloseCount
++;
1143 InsertTailList( &UDFGlobalData
.DelayedCloseQueue
,
1144 &IrpContextLite
->DelayedCloseLinks
);
1145 UDFGlobalData
.DelayedCloseCount
++;
1147 Fcb
->IrpContextLite
= IrpContextLite
;
1149 // If we are above our threshold then start the delayed
1151 if(UDFGlobalData
.DelayedCloseCount
> UDFGlobalData
.MaxDelayedCloseCount
) {
1153 UDFGlobalData
.ReduceDelayedClose
= TRUE
;
1155 if(!UDFGlobalData
.FspCloseActive
) {
1157 UDFGlobalData
.FspCloseActive
= TRUE
;
1161 // If we are above our threshold then start the delayed
1163 if(UDFGlobalData
.DirDelayedCloseCount
> UDFGlobalData
.MaxDirDelayedCloseCount
) {
1165 UDFGlobalData
.ReduceDirDelayedClose
= TRUE
;
1167 if(!UDFGlobalData
.FspCloseActive
) {
1169 UDFGlobalData
.FspCloseActive
= TRUE
;
1173 // Start the FspClose thread if we need to.
1175 ExQueueWorkItem( &UDFGlobalData
.CloseItem
, CriticalWorkQueue
);
1177 RC
= STATUS_SUCCESS
;
1183 if(!NT_SUCCESS(RC
)) {
1184 Fcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
1187 UDFReleaseResource(&(Fcb
->Vcb
->VCBResource
));
1189 // Release DelayedCloseResource
1190 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
1193 } // end UDFQueueDelayedClose()