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 ////////////////////////////////////////////////////////////////////
8 Module name: Cleanup.cpp
12 Contains code to handle the "Cleanup" dispatch entry point.
21 // define the file specific bug-check id
22 #define UDF_BUG_CHECK_ID UDF_FILE_CLEANUP
25 /*************************************************************************
27 * Function: UDFCleanup()
30 * The I/O Manager will invoke this routine to handle a cleanup
33 * Expected Interrupt Level (for execution) :
35 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
36 * to be deferred to a worker thread context)
38 * Return Value: STATUS_SUCCESS
40 *************************************************************************/
44 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
45 PIRP Irp
// I/O Request Packet
48 NTSTATUS RC
= STATUS_SUCCESS
;
49 PtrUDFIrpContext PtrIrpContext
= NULL
;
50 BOOLEAN AreWeTopLevel
= FALSE
;
52 TmPrint(("UDFCleanup\n"));
54 FsRtlEnterFileSystem();
58 // If we were called with our file system device object instead of a
59 // volume device object, just complete this request with STATUS_SUCCESS
60 if (UDFIsFSDevObj(DeviceObject
)) {
61 // this is a cleanup of the FSD itself
62 Irp
->IoStatus
.Status
= RC
;
63 Irp
->IoStatus
.Information
= 0;
65 if(UDFGlobalData
.AutoFormatCount
== IoGetCurrentIrpStackLocation(Irp
)->FileObject
) {
66 UDFPrint(("Deregister Autoformat\n"));
67 UDFGlobalData
.AutoFormatCount
= NULL
;
70 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
71 FsRtlExitFileSystem();
75 // set the top level context
76 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
80 // get an IRP context structure and issue the request
81 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
83 RC
= UDFCommonCleanup(PtrIrpContext
, Irp
);
85 RC
= STATUS_INSUFFICIENT_RESOURCES
;
86 Irp
->IoStatus
.Status
= RC
;
87 Irp
->IoStatus
.Information
= 0;
89 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
92 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
94 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
96 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
100 IoSetTopLevelIrp(NULL
);
103 FsRtlExitFileSystem();
106 } // end UDFCleanup()
108 /*************************************************************************
110 * Function: UDFCommonCleanup()
113 * The actual work is performed here. This routine may be invoked in one'
114 * of the two possible contexts:
115 * (a) in the context of a system worker thread
116 * (b) in the context of the original caller
118 * Expected Interrupt Level (for execution) :
122 * Return Value: Does not matter!
124 *************************************************************************/
127 PtrUDFIrpContext PtrIrpContext
,
130 IO_STATUS_BLOCK IoStatus
;
131 NTSTATUS RC
= STATUS_SUCCESS
;
133 PIO_STACK_LOCATION IrpSp
= NULL
;
134 PFILE_OBJECT FileObject
= NULL
;
135 PtrUDFFCB Fcb
= NULL
;
136 PtrUDFCCB Ccb
= NULL
;
138 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
140 BOOLEAN AcquiredVcb
= FALSE
;
141 BOOLEAN AcquiredFCB
= FALSE
;
142 BOOLEAN AcquiredParentFCB
= FALSE
;
144 // BOOLEAN CompleteIrp = TRUE;
145 // BOOLEAN PostRequest = FALSE;
146 BOOLEAN ChangeTime
= FALSE
;
148 BOOLEAN CanWait
= FALSE
;
150 BOOLEAN ForcedCleanUp
= FALSE
;
152 PUDF_FILE_INFO NextFileInfo
= NULL
;
154 UNICODE_STRING CurName
;
155 PDIR_INDEX_HDR DirNdx
;
157 // PUDF_DATALOC_INFO Dloc;
159 TmPrint(("UDFCommonCleanup\n"));
164 // First, get a pointer to the current I/O stack location
165 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
166 if(!IrpSp
) try_return(RC
= STATUS_INVALID_PARAMETER
);
168 FileObject
= IrpSp
->FileObject
;
170 // Get the FCB and CCB pointers
171 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
176 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
178 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
179 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
181 CanWait
= (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
;
182 AdPrint((" %s\n", CanWait
? "Wt" : "nw"));
185 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
187 // Steps we shall take at this point are:
188 // (a) Acquire the file (FCB) exclusively
189 // (b) Flush file data to disk
190 // (c) Talk to the FSRTL package (if we use it) about pending oplocks.
191 // (d) Notify the FSRTL package for use with pending notification IRPs
192 // (e) Unlock byte-range locks (if any were acquired by process)
193 // (f) Update time stamp values (e.g. fast-IO had been performed)
194 // (g) Inform the Cache Manager to uninitialize Cache Maps ...
195 // and other similar stuff.
197 NtReqFcb
= Fcb
->NTRequiredFCB
;
199 if (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) {
200 AdPrint(("Cleaning up Volume\n"));
201 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb
->OpenHandleCount
));
203 UDFInterlockedDecrement((PLONG
)&(Fcb
->OpenHandleCount
));
204 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBHandleCount
));
205 if(FileObject
->Flags
& FO_CACHE_SUPPORTED
) {
206 // we've cached close
207 UDFInterlockedDecrement((PLONG
)&(Fcb
->CachedOpenHandleCount
));
209 ASSERT(Fcb
->OpenHandleCount
<= (Fcb
->ReferenceCount
-1));
211 // If this handle had write access, and actually wrote something,
212 // flush the device buffers, and then set the verify bit now
213 // just to be safe (in case there is no dismount).
214 if( FileObject
->WriteAccess
&&
215 (FileObject
->Flags
& FO_FILE_MODIFIED
)) {
217 Vcb
->Vpb
->RealDevice
->Flags
|= DO_VERIFY_VOLUME
;
219 // User may decide to close locked volume without call to unlock proc
220 // So, handle this situation properly & unlock it now...
221 if (FileObject
== Vcb
->VolumeLockFileObject
) {
222 Vcb
->VolumeLockFileObject
= NULL
;
223 Vcb
->VolumeLockPID
= -1;
224 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_LOCKED
;
225 Vcb
->Vpb
->Flags
&= ~VPB_LOCKED
;
226 UDFNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_UNLOCK
);
229 MmPrint((" CcUninitializeCacheMap()\n"));
230 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
232 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) &&
233 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_OUR_DEVICE_DRIVER
)) {
234 // this call doesn't modify data buffer
235 // it just requires its presence
236 UDFResetDeviceDriver(Vcb
, Vcb
->TargetDeviceObject
, TRUE
);
238 // We must clean up the share access at this time, since we may not
239 // get a Close call for awhile if the file was mapped through this
241 IoRemoveShareAccess( FileObject
, &(NtReqFcb
->FCBShareAccess
) );
243 try_return(RC
= STATUS_SUCCESS
);
247 DirNdx
= UDFGetDirIndexByFileInfo(Fcb
->FileInfo
);
249 CurName
.Buffer
= UDFDirIndex(DirNdx
, Fcb
->FileInfo
->Index
)->FName
.Buffer
;
251 AdPrint(("Cleaning up file: %ws %8.8x\n", CurName
.Buffer
, FileObject
));
253 AdPrint(("Cleaning up file: ??? \n"));
257 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb
->OpenHandleCount
));
258 // Acquire parent object
259 if(Fcb
->FileInfo
->ParentFile
) {
260 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
261 UDFAcquireResourceExclusive(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
263 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
265 AcquiredParentFCB
= TRUE
;
266 // Acquire current object
267 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
268 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
270 // dereference object
271 UDFInterlockedDecrement((PLONG
)&(Fcb
->OpenHandleCount
));
272 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBHandleCount
));
273 if(FileObject
->Flags
& FO_CACHE_SUPPORTED
) {
274 // we've cached close
275 UDFInterlockedDecrement((PLONG
)&(Fcb
->CachedOpenHandleCount
));
277 ASSERT(Fcb
->OpenHandleCount
<= (Fcb
->ReferenceCount
-1));
278 // check if Ccb being cleaned up has DeleteOnClose flag set
279 #ifndef UDF_READ_ONLY_BUILD
280 if(Ccb
->CCBFlags
& UDF_CCB_DELETE_ON_CLOSE
) {
281 AdPrint((" DeleteOnClose\n"));
282 // Ok, now we'll become 'delete on close'...
283 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
284 Fcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
285 FileObject
->DeletePending
= TRUE
;
286 // Report this to the dir notify package for a directory.
287 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
288 FsRtlNotifyFullChangeDirectory( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
289 (PVOID
)Ccb
, NULL
, FALSE
, FALSE
,
290 0, NULL
, NULL
, NULL
);
293 #endif //UDF_READ_ONLY_BUILD
295 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
296 // Unlock all outstanding file locks.
297 FsRtlFastUnlockAll(&(NtReqFcb
->FileLock
),
299 IoGetRequestorProcess(Irp
),
303 lc
= UDFGetFileLinkCount(Fcb
->FileInfo
);
305 #ifndef UDF_READ_ONLY_BUILD
306 if( (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) &&
307 !(Fcb
->OpenHandleCount
)) {
308 // This can be useful for Streams, those were brutally deleted
309 // (together with parent object)
310 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
311 FileObject
->DeletePending
= TRUE
;
313 // we should mark all streams of the file being deleted
314 // for deletion too, if there are no more Links to
317 !UDFIsSDirDeleted(Fcb
->FileInfo
->Dloc
->SDirInfo
)) {
318 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, TRUE
); // Delete
320 // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE
321 // flag is already set & the file can't be opened
322 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
323 UDFReleaseResource(&(NtReqFcb
->MainResource
));
325 if(Fcb
->FileInfo
->ParentFile
) {
326 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
327 UDFReleaseResource(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
));
329 UDFReleaseResource(&(Vcb
->VCBResource
));
331 AcquiredParentFCB
= FALSE
;
332 UDFReleaseResource(&(Vcb
->VCBResource
));
335 // Make system to issue last Close request
336 // for our Target ...
337 UDFRemoveFromSystemDelayedQueue(Fcb
);
339 #ifdef UDF_DELAYED_CLOSE
340 // remove file from our DelayedClose queue
341 UDFRemoveFromDelayedQueue(Fcb
);
342 ASSERT(!Fcb
->IrpContextLite
);
343 #endif //UDF_DELAYED_CLOSE
345 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
347 if(Fcb
->FileInfo
->ParentFile
) {
348 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
349 UDFAcquireResourceExclusive(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
351 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
353 AcquiredParentFCB
= TRUE
;
354 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
355 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
358 // we should set file sizes to zero if there are no more
359 // links to this file
361 // Synchronize here with paging IO
362 UDFAcquireResourceExclusive(&(NtReqFcb
->PagingIoResource
),TRUE
);
363 // set file size to zero (for system cache manager)
364 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
365 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
366 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= 0;
367 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
369 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
372 #endif //UDF_READ_ONLY_BUILD
374 #ifdef UDF_DELAYED_CLOSE
375 if ((Fcb
->ReferenceCount
== 1) &&
376 /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above
377 (!(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
)) ) {
378 Fcb
->FCBFlags
|= UDF_FCB_DELAY_CLOSE
;
380 #endif //UDF_DELAYED_CLOSE
382 NextFileInfo
= Fcb
->FileInfo
;
384 #ifndef UDF_READ_ONLY_BUILD
385 // do we need to delete it now ?
386 if( (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) &&
387 !(Fcb
->OpenHandleCount
)) {
390 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
391 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
392 if(!UDFIsDirEmpty__(NextFileInfo
)) {
394 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
399 // Synchronize here with paging IO
400 BOOLEAN AcquiredPagingIo
;
401 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb
->PagingIoResource
));
402 // set file size to zero (for UdfInfo package)
403 // we should not do this for directories and linked files
404 UDFResizeFile__(Vcb
, NextFileInfo
, 0);
405 if(AcquiredPagingIo
) {
406 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
409 // mark parent object for deletion if requested
410 if((Fcb
->FCBFlags
& UDF_FCB_DELETE_PARENT
) &&
412 ASSERT(!(Fcb
->ParentFcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
413 Fcb
->ParentFcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
415 // flush file. It is required by UDFUnlinkFile__()
416 RC
= UDFFlushFile__(Vcb
, NextFileInfo
);
417 if(!NT_SUCCESS(RC
)) {
418 AdPrint(("Error flushing file !!!\n"));
421 if((RC
= UDFUnlinkFile__(Vcb
, NextFileInfo
, TRUE
)) == STATUS_CANNOT_DELETE
) {
422 // If we can't delete file with Streams due to references,
423 // mark SDir & Streams
424 // for Deletion. We shall also set DELETE_PARENT flag to
425 // force Deletion of the current file later... when curently
426 // opened Streams would be cleaned up.
428 // WARNING! We should keep SDir & Streams if there is a
430 if(NextFileInfo
->Dloc
&&
431 NextFileInfo
->Dloc
->SDirInfo
&&
432 NextFileInfo
->Dloc
->SDirInfo
->Fcb
) {
435 if(!UDFIsSDirDeleted(NextFileInfo
->Dloc
->SDirInfo
)) {
436 // RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
437 //#ifdef UDF_ALLOW_PRETEND_DELETED
438 UDFPretendFileDeleted__(Vcb
, Fcb
->FileInfo
);
439 //#endif //UDF_ALLOW_PRETEND_DELETED
444 // Getting here means that we can't delete file because of
445 // References/PemissionsDenied/Smth.Else,
446 // but not Linked+OpenedStream
448 // RC = STATUS_SUCCESS;
449 goto DiscardDelete_1
;
453 // We have got an ugly ERROR, or
454 // file is deleted, so forget about it
455 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
456 ForcedCleanUp
= TRUE
;
458 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
459 Fcb
->FCBFlags
|= UDF_FCB_DELETED
;
463 // We should prevent SetEOF operations on completly
464 // deleted data streams
466 NtReqFcb
->NtReqFCBFlags
|= UDF_NTREQ_FCB_DELETED
;
468 // Report that we have removed an entry.
469 if(UDFIsAStream(NextFileInfo
)) {
470 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
471 FILE_NOTIFY_CHANGE_STREAM_NAME
,
472 FILE_ACTION_REMOVED_STREAM
);
474 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
475 UDFIsADirectory(NextFileInfo
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
476 FILE_ACTION_REMOVED
);
479 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
481 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
482 ((Ccb
->CCBFlags
& UDF_CCB_ACCESS_TIME_SET
) ? FILE_NOTIFY_CHANGE_LAST_ACCESS
: 0) |
483 ((Ccb
->CCBFlags
& UDF_CCB_WRITE_TIME_SET
) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_LAST_WRITE
) : 0) |
485 UDFIsAStream(NextFileInfo
) ? FILE_ACTION_MODIFIED_STREAM
: FILE_ACTION_MODIFIED
);
487 #endif //UDF_READ_ONLY_BUILD
489 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
490 // Report to the dir notify package for a directory.
491 FsRtlNotifyCleanup( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
), (PVOID
)Ccb
);
494 // we can't purge Cache when more than one link exists
496 ForcedCleanUp
= FALSE
;
499 if ( (FileObject
->Flags
& FO_CACHE_SUPPORTED
) &&
500 (NtReqFcb
->SectionObject
.DataSectionObject
) ) {
501 BOOLEAN LastNonCached
= (!Fcb
->CachedOpenHandleCount
&&
502 Fcb
->OpenHandleCount
);
503 // If this was the last cached open, and there are open
504 // non-cached handles, attempt a flush and purge operation
505 // to avoid cache coherency overhead from these non-cached
506 // handles later. We ignore any I/O errors from the flush.
507 // We shall not flush deleted files
511 (!Fcb
->OpenHandleCount
&&
514 #ifndef UDF_READ_ONLY_BUILD
515 LONGLONG OldFileSize
, NewFileSize
;
517 if( (OldFileSize
= NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
) <
518 (NewFileSize
= NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
)) {
519 /* UDFZeroDataEx(NtReqFcb,
521 NewFileSize - OldFileSize,
522 TRUE, Vcb, FileObject);*/
524 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= NewFileSize
;
526 #endif //UDF_READ_ONLY_BUILD
527 MmPrint((" CcFlushCache()\n"));
528 CcFlushCache( &(NtReqFcb
->SectionObject
), NULL
, 0, &IoStatus
);
529 if(!NT_SUCCESS(IoStatus
.Status
)) {
530 MmPrint((" CcFlushCache() error: %x\n", IoStatus
.Status
));
531 RC
= IoStatus
.Status
;
534 // If file is deleted or it is last cached open, but there are
535 // some non-cached handles we should purge cache section
536 if(ForcedCleanUp
|| LastNonCached
) {
537 if(NtReqFcb
->SectionObject
.DataSectionObject
) {
538 MmPrint((" CcPurgeCacheSection()\n"));
539 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
541 /* MmPrint((" CcPurgeCacheSection()\n"));
542 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/
544 // we needn't Flush here. It will be done in UDFCloseFileInfoChain()
547 #ifndef UDF_READ_ONLY_BUILD
548 // Update FileTimes & Attrs
549 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) &&
550 !(Fcb
->FCBFlags
& (UDF_FCB_DELETE_ON_CLOSE
|
553 UDF_FCB_READ_ONLY*/)) &&
554 !UDFIsAStreamDir(NextFileInfo
)) {
557 KeQuerySystemTime((PLARGE_INTEGER
)&NtTime
);
558 // Check if we should set ARCHIVE bit & LastWriteTime
559 if(FileObject
->Flags
& FO_FILE_MODIFIED
) {
561 PDIR_INDEX_ITEM DirNdx
;
562 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo
), NextFileInfo
->Index
);
565 if(!(Ccb
->CCBFlags
& UDF_CCB_ATTRIBUTES_SET
) &&
566 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
)) {
567 Attr
= UDFAttributesToNT(DirNdx
, NextFileInfo
->Dloc
->FileEntry
);
568 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
569 UDFAttributesToUDF(DirNdx
, NextFileInfo
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
572 if(!(Ccb
->CCBFlags
& UDF_CCB_WRITE_TIME_SET
) &&
573 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_MODIFY_TIME
)) {
574 UDFSetFileXTime(NextFileInfo
, NULL
, &NtTime
, NULL
, &NtTime
);
575 NtReqFcb
->LastWriteTime
.QuadPart
=
576 NtReqFcb
->LastAccessTime
.QuadPart
= NtTime
;
580 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
581 // Update sizes in DirIndex
582 if(!Fcb
->OpenHandleCount
) {
583 ASize
= UDFGetFileAllocationSize(Vcb
, NextFileInfo
);
584 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
585 UDFSetFileSizeInDirNdx(Vcb
, NextFileInfo
, &ASize
);
587 if(FileObject
->Flags
& FO_FILE_SIZE_CHANGED
) {
588 ASize
= //UDFGetFileAllocationSize(Vcb, NextFileInfo);
589 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
;
590 UDFSetFileSizeInDirNdx(Vcb
, NextFileInfo
, &ASize
);
594 if((FileObject
->Flags
& FO_FILE_FAST_IO_READ
) &&
595 !(Ccb
->CCBFlags
& UDF_CCB_ACCESS_TIME_SET
) &&
596 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ACCESS_TIME
)) {
597 UDFSetFileXTime(NextFileInfo
, NULL
, &NtTime
, NULL
, NULL
);
598 NtReqFcb
->LastAccessTime
.QuadPart
= NtTime
;
599 // ChangeTime = TRUE;
601 // ChangeTime (AttrTime)
602 if(!(Ccb
->CCBFlags
& UDF_CCB_MODIFY_TIME_SET
) &&
603 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ATTR_TIME
) &&
604 (ChangeTime
|| (Ccb
->CCBFlags
& (UDF_CCB_ATTRIBUTES_SET
|
605 UDF_CCB_CREATE_TIME_SET
|
606 UDF_CCB_ACCESS_TIME_SET
|
607 UDF_CCB_WRITE_TIME_SET
))) ) {
608 UDFSetFileXTime(NextFileInfo
, NULL
, NULL
, &NtTime
, NULL
);
609 NtReqFcb
->ChangeTime
.QuadPart
= NtTime
;
612 #endif //UDF_READ_ONLY_BUILD
614 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) &&
616 // flush system cache
617 MmPrint((" CcUninitializeCacheMap()\n"));
618 CcUninitializeCacheMap(FileObject
, &(UDFGlobalData
.UDFLargeZero
), NULL
);
620 MmPrint((" CcUninitializeCacheMap()\n"));
621 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
624 // release resources now.
625 // they'll be acquired in UDFCloseFileInfoChain()
626 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
627 UDFReleaseResource(&(NtReqFcb
->MainResource
));
630 if(Fcb
->FileInfo
->ParentFile
) {
631 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
632 UDFReleaseResource(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
));
634 UDFReleaseResource(&(Vcb
->VCBResource
));
636 AcquiredParentFCB
= FALSE
;
639 RC2
= UDFCloseFileInfoChain(Vcb
, NextFileInfo
, Ccb
->TreeLength
, TRUE
);
643 Ccb
->CCBFlags
|= UDF_CCB_CLEANED
;
645 // We must clean up the share access at this time, since we may not
646 // get a Close call for awhile if the file was mapped through this
648 IoRemoveShareAccess( FileObject
, &(NtReqFcb
->FCBShareAccess
) );
650 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
652 FileObject
->Flags
|= FO_CLEANUP_COMPLETE
;
659 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
660 UDFReleaseResource(&(NtReqFcb
->MainResource
));
663 if(AcquiredParentFCB
) {
664 if(Fcb
->FileInfo
->ParentFile
) {
665 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
666 UDFReleaseResource(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
));
668 UDFReleaseResource(&(Vcb
->VCBResource
));
673 UDFReleaseResource(&(Vcb
->VCBResource
));
677 if (!_SEH2_AbnormalTermination()) {
679 Irp
->IoStatus
.Status
= RC
;
680 Irp
->IoStatus
.Information
= 0;
681 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
682 // Free up the Irp Context
683 UDFReleaseIrpContext(PtrIrpContext
);
686 } _SEH2_END
; // end of "__finally" processing
688 } // end UDFCommonCleanup()
691 This routine walks through the tree to RootDir &
692 calls UDFCloseFile__() for each file instance
696 UDFCloseFileInfoChain(
698 IN PUDF_FILE_INFO fi
,
700 IN BOOLEAN VcbAcquired
703 PUDF_FILE_INFO ParentFI
;
705 PtrUDFFCB ParentFcb
= NULL
;
706 NTSTATUS RC
= STATUS_SUCCESS
;
709 // we can't process Tree until we can acquire Vcb
711 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
713 AdPrint(("UDFCloseFileInfoChain\n"));
714 for(; TreeLength
&& fi
; TreeLength
--) {
716 // close parent chain (if any)
717 // if we started path parsing not from RootDir on Create,
718 // we would never get RootDir here
719 ValidateFileInfo(fi
);
722 if((ParentFI
= fi
->ParentFile
)) {
723 ParentFcb
= fi
->Fcb
->ParentFcb
;
725 ASSERT(ParentFcb
->NTRequiredFCB
);
726 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
727 UDFAcquireResourceExclusive(&(ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
728 ASSERT(ParentFcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
729 ASSERT(ParentFcb
->NTRequiredFCB
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
731 AdPrint(("Acquiring VCB...\n"));
732 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
735 // acquire current file/dir
736 // we must assure that no more threads try to reuse this object
737 if((Fcb
= fi
->Fcb
)) {
738 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->NTRequiredFCB
);
739 UDFAcquireResourceExclusive(&(Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
740 ASSERT_REF(Fcb
->ReferenceCount
>= fi
->RefCount
);
741 if(!(Fcb
->FCBFlags
& UDF_FCB_DELETED
) &&
742 (Fcb
->FCBFlags
& UDF_FCB_VALID
))
743 UDFWriteSecurity(Vcb
, Fcb
, &(Fcb
->NTRequiredFCB
->SecurityDesc
));
744 RC2
= UDFCloseFile__(Vcb
,fi
);
747 ASSERT_REF(Fcb
->ReferenceCount
> fi
->RefCount
);
748 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->NTRequiredFCB
);
749 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->MainResource
));
752 RC2
= UDFCloseFile__(Vcb
,fi
);
758 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
759 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
761 UDFReleaseResource(&(Vcb
->VCBResource
));
767 UDFReleaseResource(&(Vcb
->VCBResource
));
771 } // end UDFCloseFileInfoChain()