1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 ////////////////////////////////////////////////////////////////////
7 Module name: Cleanup.cpp
11 Contains code to handle the "Cleanup" dispatch entry point.
20 // define the file specific bug-check id
21 #define UDF_BUG_CHECK_ID UDF_FILE_CLEANUP
24 /*************************************************************************
26 * Function: UDFCleanup()
29 * The I/O Manager will invoke this routine to handle a cleanup
32 * Expected Interrupt Level (for execution) :
34 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
35 * to be deferred to a worker thread context)
37 * Return Value: STATUS_SUCCESS
39 *************************************************************************/
43 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
44 PIRP Irp
// I/O Request Packet
47 NTSTATUS RC
= STATUS_SUCCESS
;
48 PtrUDFIrpContext PtrIrpContext
= NULL
;
49 BOOLEAN AreWeTopLevel
= FALSE
;
51 TmPrint(("UDFCleanup\n"));
53 FsRtlEnterFileSystem();
57 // If we were called with our file system device object instead of a
58 // volume device object, just complete this request with STATUS_SUCCESS
59 if (UDFIsFSDevObj(DeviceObject
)) {
60 // this is a cleanup of the FSD itself
61 Irp
->IoStatus
.Status
= RC
;
62 Irp
->IoStatus
.Information
= 0;
64 if(UDFGlobalData
.AutoFormatCount
== IoGetCurrentIrpStackLocation(Irp
)->FileObject
) {
65 KdPrint(("Deregister Autoformat\n"));
66 UDFGlobalData
.AutoFormatCount
= NULL
;
69 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
70 FsRtlExitFileSystem();
74 // set the top level context
75 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
79 // get an IRP context structure and issue the request
80 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
82 RC
= UDFCommonCleanup(PtrIrpContext
, Irp
);
84 RC
= STATUS_INSUFFICIENT_RESOURCES
;
85 Irp
->IoStatus
.Status
= RC
;
86 Irp
->IoStatus
.Information
= 0;
88 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
91 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
93 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
95 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
99 IoSetTopLevelIrp(NULL
);
102 FsRtlExitFileSystem();
105 } // end UDFCleanup()
107 /*************************************************************************
109 * Function: UDFCommonCleanup()
112 * The actual work is performed here. This routine may be invoked in one'
113 * of the two possible contexts:
114 * (a) in the context of a system worker thread
115 * (b) in the context of the original caller
117 * Expected Interrupt Level (for execution) :
121 * Return Value: Does not matter!
123 *************************************************************************/
126 PtrUDFIrpContext PtrIrpContext
,
129 IO_STATUS_BLOCK IoStatus
;
130 NTSTATUS RC
= STATUS_SUCCESS
;
132 PIO_STACK_LOCATION IrpSp
= NULL
;
133 PFILE_OBJECT FileObject
= NULL
;
134 PtrUDFFCB Fcb
= NULL
;
135 PtrUDFCCB Ccb
= NULL
;
137 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
139 BOOLEAN AcquiredVcb
= FALSE
;
140 BOOLEAN AcquiredFCB
= FALSE
;
141 BOOLEAN AcquiredParentFCB
= FALSE
;
143 // BOOLEAN CompleteIrp = TRUE;
144 // BOOLEAN PostRequest = FALSE;
145 BOOLEAN ChangeTime
= FALSE
;
147 BOOLEAN CanWait
= FALSE
;
149 BOOLEAN ForcedCleanUp
= FALSE
;
151 PUDF_FILE_INFO NextFileInfo
= NULL
;
153 UNICODE_STRING CurName
;
154 PDIR_INDEX_HDR DirNdx
;
156 // PUDF_DATALOC_INFO Dloc;
157 #ifdef EVALUATION_TIME_LIMIT
159 #endif //EVALUATION_TIME_LIMIT
161 TmPrint(("UDFCommonCleanup\n"));
166 // First, get a pointer to the current I/O stack location
167 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
168 if(!IrpSp
) try_return(RC
= STATUS_INVALID_PARAMETER
);
170 FileObject
= IrpSp
->FileObject
;
172 // Get the FCB and CCB pointers
173 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
178 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
180 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
181 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
183 CanWait
= (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
;
184 AdPrint((" %s\n", CanWait
? "Wt" : "nw"));
187 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
189 // Steps we shall take at this point are:
190 // (a) Acquire the file (FCB) exclusively
191 // (b) Flush file data to disk
192 // (c) Talk to the FSRTL package (if we use it) about pending oplocks.
193 // (d) Notify the FSRTL package for use with pending notification IRPs
194 // (e) Unlock byte-range locks (if any were acquired by process)
195 // (f) Update time stamp values (e.g. fast-IO had been performed)
196 // (g) Inform the Cache Manager to uninitialize Cache Maps ...
197 // and other similar stuff.
199 NtReqFcb
= Fcb
->NTRequiredFCB
;
201 if (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) {
202 AdPrint(("Cleaning up Volume\n"));
203 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb
->OpenHandleCount
));
205 UDFInterlockedDecrement((PLONG
)&(Fcb
->OpenHandleCount
));
206 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBHandleCount
));
207 if(FileObject
->Flags
& FO_CACHE_SUPPORTED
) {
208 // we've cached close
209 UDFInterlockedDecrement((PLONG
)&(Fcb
->CachedOpenHandleCount
));
211 ASSERT(Fcb
->OpenHandleCount
<= (Fcb
->ReferenceCount
-1));
213 // If this handle had write access, and actually wrote something,
214 // flush the device buffers, and then set the verify bit now
215 // just to be safe (in case there is no dismount).
216 if( FileObject
->WriteAccess
&&
217 (FileObject
->Flags
& FO_FILE_MODIFIED
)) {
219 Vcb
->Vpb
->RealDevice
->Flags
|= DO_VERIFY_VOLUME
;
221 // User may decide to close locked volume without call to unlock proc
222 // So, handle this situation properly & unlock it now...
223 if (FileObject
== Vcb
->VolumeLockFileObject
) {
224 Vcb
->VolumeLockFileObject
= NULL
;
225 Vcb
->VolumeLockPID
= -1;
226 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_LOCKED
;
227 Vcb
->Vpb
->Flags
&= ~VPB_LOCKED
;
228 UDFNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_UNLOCK
);
231 MmPrint((" CcUninitializeCacheMap()\n"));
232 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
234 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) &&
235 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_OUR_DEVICE_DRIVER
)) {
236 // this call doesn't modify data buffer
237 // it just requires its presence
238 UDFResetDeviceDriver(Vcb
, Vcb
->TargetDeviceObject
, TRUE
);
240 // We must clean up the share access at this time, since we may not
241 // get a Close call for awhile if the file was mapped through this
243 IoRemoveShareAccess( FileObject
, &(NtReqFcb
->FCBShareAccess
) );
245 try_return(RC
= STATUS_SUCCESS
);
249 DirNdx
= UDFGetDirIndexByFileInfo(Fcb
->FileInfo
);
251 CurName
.Buffer
= UDFDirIndex(DirNdx
, Fcb
->FileInfo
->Index
)->FName
.Buffer
;
253 AdPrint(("Cleaning up file: %ws %8.8x\n", CurName
.Buffer
, FileObject
));
255 AdPrint(("Cleaning up file: ??? \n"));
259 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb
->OpenHandleCount
));
260 // Acquire parent object
261 if(Fcb
->FileInfo
->ParentFile
) {
262 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
263 UDFAcquireResourceExclusive(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
265 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
267 AcquiredParentFCB
= TRUE
;
268 // Acquire current object
269 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
270 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
272 // dereference object
273 UDFInterlockedDecrement((PLONG
)&(Fcb
->OpenHandleCount
));
274 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBHandleCount
));
275 if(FileObject
->Flags
& FO_CACHE_SUPPORTED
) {
276 // we've cached close
277 UDFInterlockedDecrement((PLONG
)&(Fcb
->CachedOpenHandleCount
));
279 ASSERT(Fcb
->OpenHandleCount
<= (Fcb
->ReferenceCount
-1));
280 // check if Ccb being cleaned up has DeleteOnClose flag set
281 #ifndef UDF_READ_ONLY_BUILD
282 if(Ccb
->CCBFlags
& UDF_CCB_DELETE_ON_CLOSE
) {
283 AdPrint((" DeleteOnClose\n"));
284 // Ok, now we'll become 'delete on close'...
285 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
286 Fcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
287 FileObject
->DeletePending
= TRUE
;
288 // Report this to the dir notify package for a directory.
289 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
290 FsRtlNotifyFullChangeDirectory( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
291 (PVOID
)Ccb
, NULL
, FALSE
, FALSE
,
292 0, NULL
, NULL
, NULL
);
295 #endif //UDF_READ_ONLY_BUILD
297 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
298 // Unlock all outstanding file locks.
299 FsRtlFastUnlockAll(&(NtReqFcb
->FileLock
),
301 IoGetRequestorProcess(Irp
),
305 lc
= UDFGetFileLinkCount(Fcb
->FileInfo
);
307 #ifndef UDF_READ_ONLY_BUILD
308 if( (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) &&
309 !(Fcb
->OpenHandleCount
)) {
310 // This can be useful for Streams, those were brutally deleted
311 // (together with parent object)
312 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
313 FileObject
->DeletePending
= TRUE
;
315 // we should mark all streams of the file being deleted
316 // for deletion too, if there are no more Links to
319 !UDFIsSDirDeleted(Fcb
->FileInfo
->Dloc
->SDirInfo
)) {
320 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, TRUE
); // Delete
322 // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE
323 // flag is already set & the file can't be opened
324 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
325 UDFReleaseResource(&(NtReqFcb
->MainResource
));
327 if(Fcb
->FileInfo
->ParentFile
) {
328 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
329 UDFReleaseResource(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
));
331 UDFReleaseResource(&(Vcb
->VCBResource
));
333 AcquiredParentFCB
= FALSE
;
334 UDFReleaseResource(&(Vcb
->VCBResource
));
337 // Make system to issue last Close request
338 // for our Target ...
339 UDFRemoveFromSystemDelayedQueue(Fcb
);
341 #ifdef UDF_DELAYED_CLOSE
342 // remove file from our DelayedClose queue
343 UDFRemoveFromDelayedQueue(Fcb
);
344 ASSERT(!Fcb
->IrpContextLite
);
345 #endif //UDF_DELAYED_CLOSE
347 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
349 if(Fcb
->FileInfo
->ParentFile
) {
350 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
351 UDFAcquireResourceExclusive(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
353 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
355 AcquiredParentFCB
= TRUE
;
356 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
357 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
360 // we should set file sizes to zero if there are no more
361 // links to this file
363 // Synchronize here with paging IO
364 UDFAcquireResourceExclusive(&(NtReqFcb
->PagingIoResource
),TRUE
);
365 // set file size to zero (for system cache manager)
366 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
367 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
368 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= 0;
369 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
371 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
374 #endif //UDF_READ_ONLY_BUILD
376 #ifdef UDF_DELAYED_CLOSE
377 if ((Fcb
->ReferenceCount
== 1) &&
378 /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above
379 (!(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
)) ) {
380 Fcb
->FCBFlags
|= UDF_FCB_DELAY_CLOSE
;
382 #endif //UDF_DELAYED_CLOSE
384 NextFileInfo
= Fcb
->FileInfo
;
386 #ifndef UDF_READ_ONLY_BUILD
387 // do we need to delete it now ?
388 if( (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) &&
389 !(Fcb
->OpenHandleCount
)) {
392 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
393 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
394 if(!UDFIsDirEmpty__(NextFileInfo
)) {
396 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
401 // Synchronize here with paging IO
402 BOOLEAN AcquiredPagingIo
;
403 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb
->PagingIoResource
));
404 // set file size to zero (for UdfInfo package)
405 // we should not do this for directories and linked files
406 UDFResizeFile__(Vcb
, NextFileInfo
, 0);
407 if(AcquiredPagingIo
) {
408 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
411 // mark parent object for deletion if requested
412 if((Fcb
->FCBFlags
& UDF_FCB_DELETE_PARENT
) &&
414 ASSERT(!(Fcb
->ParentFcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
415 Fcb
->ParentFcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
417 // flush file. It is required by UDFUnlinkFile__()
418 RC
= UDFFlushFile__(Vcb
, NextFileInfo
);
419 if(!NT_SUCCESS(RC
)) {
420 AdPrint(("Error flushing file !!!\n"));
423 if((RC
= UDFUnlinkFile__(Vcb
, NextFileInfo
, TRUE
)) == STATUS_CANNOT_DELETE
) {
424 // If we can't delete file with Streams due to references,
425 // mark SDir & Streams
426 // for Deletion. We shall also set DELETE_PARENT flag to
427 // force Deletion of the current file later... when curently
428 // opened Streams would be cleaned up.
430 // WARNING! We should keep SDir & Streams if there is a
432 if(NextFileInfo
->Dloc
&&
433 NextFileInfo
->Dloc
->SDirInfo
&&
434 NextFileInfo
->Dloc
->SDirInfo
->Fcb
) {
437 if(!UDFIsSDirDeleted(NextFileInfo
->Dloc
->SDirInfo
)) {
438 // RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
439 //#ifdef UDF_ALLOW_PRETEND_DELETED
440 UDFPretendFileDeleted__(Vcb
, Fcb
->FileInfo
);
441 //#endif //UDF_ALLOW_PRETEND_DELETED
446 // Getting here means that we can't delete file because of
447 // References/PemissionsDenied/Smth.Else,
448 // but not Linked+OpenedStream
450 // RC = STATUS_SUCCESS;
451 goto DiscardDelete_1
;
455 // We have got an ugly ERROR, or
456 // file is deleted, so forget about it
457 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
458 ForcedCleanUp
= TRUE
;
460 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
461 Fcb
->FCBFlags
|= UDF_FCB_DELETED
;
465 // We should prevent SetEOF operations on completly
466 // deleted data streams
468 NtReqFcb
->NtReqFCBFlags
|= UDF_NTREQ_FCB_DELETED
;
470 // Report that we have removed an entry.
471 if(UDFIsAStream(NextFileInfo
)) {
472 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
473 FILE_NOTIFY_CHANGE_STREAM_NAME
,
474 FILE_ACTION_REMOVED_STREAM
);
476 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
477 UDFIsADirectory(NextFileInfo
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
478 FILE_ACTION_REMOVED
);
481 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
483 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
484 ((Ccb
->CCBFlags
& UDF_CCB_ACCESS_TIME_SET
) ? FILE_NOTIFY_CHANGE_LAST_ACCESS
: 0) |
485 ((Ccb
->CCBFlags
& UDF_CCB_WRITE_TIME_SET
) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_LAST_WRITE
) : 0) |
487 UDFIsAStream(NextFileInfo
) ? FILE_ACTION_MODIFIED_STREAM
: FILE_ACTION_MODIFIED
);
489 #endif //UDF_READ_ONLY_BUILD
491 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
492 // Report to the dir notify package for a directory.
493 FsRtlNotifyCleanup( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
), (PVOID
)Ccb
);
496 // we can't purge Cache when more than one link exists
498 ForcedCleanUp
= FALSE
;
501 if ( (FileObject
->Flags
& FO_CACHE_SUPPORTED
) &&
502 (NtReqFcb
->SectionObject
.DataSectionObject
) ) {
503 BOOLEAN LastNonCached
= (!Fcb
->CachedOpenHandleCount
&&
504 Fcb
->OpenHandleCount
);
505 // If this was the last cached open, and there are open
506 // non-cached handles, attempt a flush and purge operation
507 // to avoid cache coherency overhead from these non-cached
508 // handles later. We ignore any I/O errors from the flush.
509 // We shall not flush deleted files
513 (!Fcb
->OpenHandleCount
&&
516 #ifndef UDF_READ_ONLY_BUILD
517 LONGLONG OldFileSize
, NewFileSize
;
519 if( (OldFileSize
= NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
) <
520 (NewFileSize
= NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
)) {
521 /* UDFZeroDataEx(NtReqFcb,
523 NewFileSize - OldFileSize,
524 TRUE, Vcb, FileObject);*/
526 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= NewFileSize
;
528 #endif //UDF_READ_ONLY_BUILD
529 MmPrint((" CcFlushCache()\n"));
530 CcFlushCache( &(NtReqFcb
->SectionObject
), NULL
, 0, &IoStatus
);
531 if(!NT_SUCCESS(IoStatus
.Status
)) {
532 MmPrint((" CcFlushCache() error: %x\n", IoStatus
.Status
));
533 RC
= IoStatus
.Status
;
536 // If file is deleted or it is last cached open, but there are
537 // some non-cached handles we should purge cache section
538 if(ForcedCleanUp
|| LastNonCached
) {
539 if(NtReqFcb
->SectionObject
.DataSectionObject
) {
540 MmPrint((" CcPurgeCacheSection()\n"));
541 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
543 /* MmPrint((" CcPurgeCacheSection()\n"));
544 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/
546 // we needn't Flush here. It will be done in UDFCloseFileInfoChain()
549 #ifndef UDF_READ_ONLY_BUILD
550 // Update FileTimes & Attrs
551 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) &&
552 !(Fcb
->FCBFlags
& (UDF_FCB_DELETE_ON_CLOSE
|
554 UDF_FCB_DIRECTORY /*|
555 UDF_FCB_READ_ONLY*/)) &&
556 !UDFIsAStreamDir(NextFileInfo
)) {
559 KeQuerySystemTime((PLARGE_INTEGER
)&NtTime
);
560 // Check if we should set ARCHIVE bit & LastWriteTime
561 if(FileObject
->Flags
& FO_FILE_MODIFIED
) {
563 PDIR_INDEX_ITEM DirNdx
;
564 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo
), NextFileInfo
->Index
);
567 if(!(Ccb
->CCBFlags
& UDF_CCB_ATTRIBUTES_SET
) &&
568 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
)) {
569 Attr
= UDFAttributesToNT(DirNdx
, NextFileInfo
->Dloc
->FileEntry
);
570 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
571 UDFAttributesToUDF(DirNdx
, NextFileInfo
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
574 if(!(Ccb
->CCBFlags
& UDF_CCB_WRITE_TIME_SET
) &&
575 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_MODIFY_TIME
)) {
576 UDFSetFileXTime(NextFileInfo
, NULL
, &NtTime
, NULL
, &NtTime
);
577 NtReqFcb
->LastWriteTime
.QuadPart
=
578 NtReqFcb
->LastAccessTime
.QuadPart
= NtTime
;
582 #ifdef EVALUATION_TIME_LIMIT
583 KeQuerySystemTime(&UDFGlobalData
.UDFCurrentTime
);
584 t
= (ULONG
)(UDFGlobalData
.UDFCurrentTime
.QuadPart
/ (10*1000*1000));
586 if(UDFGlobalData
.UDFFlags
& UDF_DATA_FLAGS_UNREGISTERED
) {
587 if(t
-TIME_JAN_1_2003
> UDF_MAX_DATE
||
588 t
-TIME_JAN_1_2003
< UDF_MIN_DATE
) {
589 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_READ_ONLY
;
592 #endif //EVALUATION_TIME_LIMIT
593 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
594 // Update sizes in DirIndex
595 if(!Fcb
->OpenHandleCount
) {
596 ASize
= UDFGetFileAllocationSize(Vcb
, NextFileInfo
);
597 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
598 UDFSetFileSizeInDirNdx(Vcb
, NextFileInfo
, &ASize
);
600 if(FileObject
->Flags
& FO_FILE_SIZE_CHANGED
) {
601 ASize
= //UDFGetFileAllocationSize(Vcb, NextFileInfo);
602 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
;
603 UDFSetFileSizeInDirNdx(Vcb
, NextFileInfo
, &ASize
);
607 if((FileObject
->Flags
& FO_FILE_FAST_IO_READ
) &&
608 !(Ccb
->CCBFlags
& UDF_CCB_ACCESS_TIME_SET
) &&
609 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ACCESS_TIME
)) {
610 UDFSetFileXTime(NextFileInfo
, NULL
, &NtTime
, NULL
, NULL
);
611 NtReqFcb
->LastAccessTime
.QuadPart
= NtTime
;
612 // ChangeTime = TRUE;
614 // ChangeTime (AttrTime)
615 if(!(Ccb
->CCBFlags
& UDF_CCB_MODIFY_TIME_SET
) &&
616 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ATTR_TIME
) &&
617 (ChangeTime
|| (Ccb
->CCBFlags
& (UDF_CCB_ATTRIBUTES_SET
|
618 UDF_CCB_CREATE_TIME_SET
|
619 UDF_CCB_ACCESS_TIME_SET
|
620 UDF_CCB_WRITE_TIME_SET
))) ) {
621 UDFSetFileXTime(NextFileInfo
, NULL
, NULL
, &NtTime
, NULL
);
622 NtReqFcb
->ChangeTime
.QuadPart
= NtTime
;
625 #endif //UDF_READ_ONLY_BUILD
627 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) &&
629 // flush system cache
630 MmPrint((" CcUninitializeCacheMap()\n"));
631 CcUninitializeCacheMap(FileObject
, &(UDFGlobalData
.UDFLargeZero
), NULL
);
633 MmPrint((" CcUninitializeCacheMap()\n"));
634 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
637 // release resources now.
638 // they'll be acquired in UDFCloseFileInfoChain()
639 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
640 UDFReleaseResource(&(NtReqFcb
->MainResource
));
643 if(Fcb
->FileInfo
->ParentFile
) {
644 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
645 UDFReleaseResource(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
));
647 UDFReleaseResource(&(Vcb
->VCBResource
));
649 AcquiredParentFCB
= FALSE
;
652 RC2
= UDFCloseFileInfoChain(Vcb
, NextFileInfo
, Ccb
->TreeLength
, TRUE
);
656 Ccb
->CCBFlags
|= UDF_CCB_CLEANED
;
658 // We must clean up the share access at this time, since we may not
659 // get a Close call for awhile if the file was mapped through this
661 IoRemoveShareAccess( FileObject
, &(NtReqFcb
->FCBShareAccess
) );
663 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
665 FileObject
->Flags
|= FO_CLEANUP_COMPLETE
;
672 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
673 UDFReleaseResource(&(NtReqFcb
->MainResource
));
676 if(AcquiredParentFCB
) {
677 if(Fcb
->FileInfo
->ParentFile
) {
678 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
679 UDFReleaseResource(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
));
681 UDFReleaseResource(&(Vcb
->VCBResource
));
686 UDFReleaseResource(&(Vcb
->VCBResource
));
690 if (!_SEH2_AbnormalTermination()) {
692 Irp
->IoStatus
.Status
= RC
;
693 Irp
->IoStatus
.Information
= 0;
694 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
695 // Free up the Irp Context
696 UDFReleaseIrpContext(PtrIrpContext
);
699 } _SEH2_END
; // end of "__finally" processing
701 } // end UDFCommonCleanup()
704 This routine walks through the tree to RootDir &
705 calls UDFCloseFile__() for each file instance
709 UDFCloseFileInfoChain(
711 IN PUDF_FILE_INFO fi
,
713 IN BOOLEAN VcbAcquired
716 PUDF_FILE_INFO ParentFI
;
718 PtrUDFFCB ParentFcb
= NULL
;
719 NTSTATUS RC
= STATUS_SUCCESS
;
722 // we can't process Tree until we can acquire Vcb
724 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
726 AdPrint(("UDFCloseFileInfoChain\n"));
727 for(; TreeLength
&& fi
; TreeLength
--) {
729 // close parent chain (if any)
730 // if we started path parsing not from RootDir on Create,
731 // we would never get RootDir here
732 ValidateFileInfo(fi
);
735 if(ParentFI
= fi
->ParentFile
) {
736 ParentFcb
= fi
->Fcb
->ParentFcb
;
738 ASSERT(ParentFcb
->NTRequiredFCB
);
739 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
740 UDFAcquireResourceExclusive(&(ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
741 ASSERT(ParentFcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
742 ASSERT(ParentFcb
->NTRequiredFCB
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
744 AdPrint(("Acquiring VCB...\n"));
745 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
748 // acquire current file/dir
749 // we must assure that no more threads try to reuse this object
751 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->NTRequiredFCB
);
752 UDFAcquireResourceExclusive(&(Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
753 ASSERT_REF(Fcb
->ReferenceCount
>= fi
->RefCount
);
754 if(!(Fcb
->FCBFlags
& UDF_FCB_DELETED
) &&
755 (Fcb
->FCBFlags
& UDF_FCB_VALID
))
756 UDFWriteSecurity(Vcb
, Fcb
, &(Fcb
->NTRequiredFCB
->SecurityDesc
));
757 RC2
= UDFCloseFile__(Vcb
,fi
);
760 ASSERT_REF(Fcb
->ReferenceCount
> fi
->RefCount
);
761 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->NTRequiredFCB
);
762 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->MainResource
));
765 RC2
= UDFCloseFile__(Vcb
,fi
);
771 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
772 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
774 UDFReleaseResource(&(Vcb
->VCBResource
));
780 UDFReleaseResource(&(Vcb
->VCBResource
));
784 } // end UDFCloseFileInfoChain()