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 KdPrint(("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;
158 #ifdef EVALUATION_TIME_LIMIT
160 #endif //EVALUATION_TIME_LIMIT
162 TmPrint(("UDFCommonCleanup\n"));
167 // First, get a pointer to the current I/O stack location
168 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
169 if(!IrpSp
) try_return(RC
= STATUS_INVALID_PARAMETER
);
171 FileObject
= IrpSp
->FileObject
;
173 // Get the FCB and CCB pointers
174 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
179 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
181 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
182 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
184 CanWait
= (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
;
185 AdPrint((" %s\n", CanWait
? "Wt" : "nw"));
188 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
190 // Steps we shall take at this point are:
191 // (a) Acquire the file (FCB) exclusively
192 // (b) Flush file data to disk
193 // (c) Talk to the FSRTL package (if we use it) about pending oplocks.
194 // (d) Notify the FSRTL package for use with pending notification IRPs
195 // (e) Unlock byte-range locks (if any were acquired by process)
196 // (f) Update time stamp values (e.g. fast-IO had been performed)
197 // (g) Inform the Cache Manager to uninitialize Cache Maps ...
198 // and other similar stuff.
200 NtReqFcb
= Fcb
->NTRequiredFCB
;
202 if (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) {
203 AdPrint(("Cleaning up Volume\n"));
204 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb
->OpenHandleCount
));
206 UDFInterlockedDecrement((PLONG
)&(Fcb
->OpenHandleCount
));
207 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBHandleCount
));
208 if(FileObject
->Flags
& FO_CACHE_SUPPORTED
) {
209 // we've cached close
210 UDFInterlockedDecrement((PLONG
)&(Fcb
->CachedOpenHandleCount
));
212 ASSERT(Fcb
->OpenHandleCount
<= (Fcb
->ReferenceCount
-1));
214 // If this handle had write access, and actually wrote something,
215 // flush the device buffers, and then set the verify bit now
216 // just to be safe (in case there is no dismount).
217 if( FileObject
->WriteAccess
&&
218 (FileObject
->Flags
& FO_FILE_MODIFIED
)) {
220 Vcb
->Vpb
->RealDevice
->Flags
|= DO_VERIFY_VOLUME
;
222 // User may decide to close locked volume without call to unlock proc
223 // So, handle this situation properly & unlock it now...
224 if (FileObject
== Vcb
->VolumeLockFileObject
) {
225 Vcb
->VolumeLockFileObject
= NULL
;
226 Vcb
->VolumeLockPID
= -1;
227 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_LOCKED
;
228 Vcb
->Vpb
->Flags
&= ~VPB_LOCKED
;
229 UDFNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_UNLOCK
);
232 MmPrint((" CcUninitializeCacheMap()\n"));
233 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
235 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) &&
236 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_OUR_DEVICE_DRIVER
)) {
237 // this call doesn't modify data buffer
238 // it just requires its presence
239 UDFResetDeviceDriver(Vcb
, Vcb
->TargetDeviceObject
, TRUE
);
241 // We must clean up the share access at this time, since we may not
242 // get a Close call for awhile if the file was mapped through this
244 IoRemoveShareAccess( FileObject
, &(NtReqFcb
->FCBShareAccess
) );
246 try_return(RC
= STATUS_SUCCESS
);
250 DirNdx
= UDFGetDirIndexByFileInfo(Fcb
->FileInfo
);
252 CurName
.Buffer
= UDFDirIndex(DirNdx
, Fcb
->FileInfo
->Index
)->FName
.Buffer
;
254 AdPrint(("Cleaning up file: %ws %8.8x\n", CurName
.Buffer
, FileObject
));
256 AdPrint(("Cleaning up file: ??? \n"));
260 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb
->OpenHandleCount
));
261 // Acquire parent object
262 if(Fcb
->FileInfo
->ParentFile
) {
263 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
264 UDFAcquireResourceExclusive(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
266 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
268 AcquiredParentFCB
= TRUE
;
269 // Acquire current object
270 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
271 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
273 // dereference object
274 UDFInterlockedDecrement((PLONG
)&(Fcb
->OpenHandleCount
));
275 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBHandleCount
));
276 if(FileObject
->Flags
& FO_CACHE_SUPPORTED
) {
277 // we've cached close
278 UDFInterlockedDecrement((PLONG
)&(Fcb
->CachedOpenHandleCount
));
280 ASSERT(Fcb
->OpenHandleCount
<= (Fcb
->ReferenceCount
-1));
281 // check if Ccb being cleaned up has DeleteOnClose flag set
282 #ifndef UDF_READ_ONLY_BUILD
283 if(Ccb
->CCBFlags
& UDF_CCB_DELETE_ON_CLOSE
) {
284 AdPrint((" DeleteOnClose\n"));
285 // Ok, now we'll become 'delete on close'...
286 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
287 Fcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
288 FileObject
->DeletePending
= TRUE
;
289 // Report this to the dir notify package for a directory.
290 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
291 FsRtlNotifyFullChangeDirectory( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
292 (PVOID
)Ccb
, NULL
, FALSE
, FALSE
,
293 0, NULL
, NULL
, NULL
);
296 #endif //UDF_READ_ONLY_BUILD
298 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
299 // Unlock all outstanding file locks.
300 FsRtlFastUnlockAll(&(NtReqFcb
->FileLock
),
302 IoGetRequestorProcess(Irp
),
306 lc
= UDFGetFileLinkCount(Fcb
->FileInfo
);
308 #ifndef UDF_READ_ONLY_BUILD
309 if( (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) &&
310 !(Fcb
->OpenHandleCount
)) {
311 // This can be useful for Streams, those were brutally deleted
312 // (together with parent object)
313 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
314 FileObject
->DeletePending
= TRUE
;
316 // we should mark all streams of the file being deleted
317 // for deletion too, if there are no more Links to
320 !UDFIsSDirDeleted(Fcb
->FileInfo
->Dloc
->SDirInfo
)) {
321 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, TRUE
); // Delete
323 // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE
324 // flag is already set & the file can't be opened
325 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
326 UDFReleaseResource(&(NtReqFcb
->MainResource
));
328 if(Fcb
->FileInfo
->ParentFile
) {
329 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
330 UDFReleaseResource(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
));
332 UDFReleaseResource(&(Vcb
->VCBResource
));
334 AcquiredParentFCB
= FALSE
;
335 UDFReleaseResource(&(Vcb
->VCBResource
));
338 // Make system to issue last Close request
339 // for our Target ...
340 UDFRemoveFromSystemDelayedQueue(Fcb
);
342 #ifdef UDF_DELAYED_CLOSE
343 // remove file from our DelayedClose queue
344 UDFRemoveFromDelayedQueue(Fcb
);
345 ASSERT(!Fcb
->IrpContextLite
);
346 #endif //UDF_DELAYED_CLOSE
348 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
350 if(Fcb
->FileInfo
->ParentFile
) {
351 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
352 UDFAcquireResourceExclusive(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
354 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
356 AcquiredParentFCB
= TRUE
;
357 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
358 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
361 // we should set file sizes to zero if there are no more
362 // links to this file
364 // Synchronize here with paging IO
365 UDFAcquireResourceExclusive(&(NtReqFcb
->PagingIoResource
),TRUE
);
366 // set file size to zero (for system cache manager)
367 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
368 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
369 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= 0;
370 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
372 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
375 #endif //UDF_READ_ONLY_BUILD
377 #ifdef UDF_DELAYED_CLOSE
378 if ((Fcb
->ReferenceCount
== 1) &&
379 /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above
380 (!(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
)) ) {
381 Fcb
->FCBFlags
|= UDF_FCB_DELAY_CLOSE
;
383 #endif //UDF_DELAYED_CLOSE
385 NextFileInfo
= Fcb
->FileInfo
;
387 #ifndef UDF_READ_ONLY_BUILD
388 // do we need to delete it now ?
389 if( (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) &&
390 !(Fcb
->OpenHandleCount
)) {
393 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
394 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
395 if(!UDFIsDirEmpty__(NextFileInfo
)) {
397 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
402 // Synchronize here with paging IO
403 BOOLEAN AcquiredPagingIo
;
404 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb
->PagingIoResource
));
405 // set file size to zero (for UdfInfo package)
406 // we should not do this for directories and linked files
407 UDFResizeFile__(Vcb
, NextFileInfo
, 0);
408 if(AcquiredPagingIo
) {
409 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
412 // mark parent object for deletion if requested
413 if((Fcb
->FCBFlags
& UDF_FCB_DELETE_PARENT
) &&
415 ASSERT(!(Fcb
->ParentFcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
416 Fcb
->ParentFcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
418 // flush file. It is required by UDFUnlinkFile__()
419 RC
= UDFFlushFile__(Vcb
, NextFileInfo
);
420 if(!NT_SUCCESS(RC
)) {
421 AdPrint(("Error flushing file !!!\n"));
424 if((RC
= UDFUnlinkFile__(Vcb
, NextFileInfo
, TRUE
)) == STATUS_CANNOT_DELETE
) {
425 // If we can't delete file with Streams due to references,
426 // mark SDir & Streams
427 // for Deletion. We shall also set DELETE_PARENT flag to
428 // force Deletion of the current file later... when curently
429 // opened Streams would be cleaned up.
431 // WARNING! We should keep SDir & Streams if there is a
433 if(NextFileInfo
->Dloc
&&
434 NextFileInfo
->Dloc
->SDirInfo
&&
435 NextFileInfo
->Dloc
->SDirInfo
->Fcb
) {
438 if(!UDFIsSDirDeleted(NextFileInfo
->Dloc
->SDirInfo
)) {
439 // RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
440 //#ifdef UDF_ALLOW_PRETEND_DELETED
441 UDFPretendFileDeleted__(Vcb
, Fcb
->FileInfo
);
442 //#endif //UDF_ALLOW_PRETEND_DELETED
447 // Getting here means that we can't delete file because of
448 // References/PemissionsDenied/Smth.Else,
449 // but not Linked+OpenedStream
451 // RC = STATUS_SUCCESS;
452 goto DiscardDelete_1
;
456 // We have got an ugly ERROR, or
457 // file is deleted, so forget about it
458 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
459 ForcedCleanUp
= TRUE
;
461 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
462 Fcb
->FCBFlags
|= UDF_FCB_DELETED
;
466 // We should prevent SetEOF operations on completly
467 // deleted data streams
469 NtReqFcb
->NtReqFCBFlags
|= UDF_NTREQ_FCB_DELETED
;
471 // Report that we have removed an entry.
472 if(UDFIsAStream(NextFileInfo
)) {
473 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
474 FILE_NOTIFY_CHANGE_STREAM_NAME
,
475 FILE_ACTION_REMOVED_STREAM
);
477 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
478 UDFIsADirectory(NextFileInfo
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
479 FILE_ACTION_REMOVED
);
482 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
484 UDFNotifyFullReportChange( Vcb
, NextFileInfo
,
485 ((Ccb
->CCBFlags
& UDF_CCB_ACCESS_TIME_SET
) ? FILE_NOTIFY_CHANGE_LAST_ACCESS
: 0) |
486 ((Ccb
->CCBFlags
& UDF_CCB_WRITE_TIME_SET
) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_LAST_WRITE
) : 0) |
488 UDFIsAStream(NextFileInfo
) ? FILE_ACTION_MODIFIED_STREAM
: FILE_ACTION_MODIFIED
);
490 #endif //UDF_READ_ONLY_BUILD
492 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
493 // Report to the dir notify package for a directory.
494 FsRtlNotifyCleanup( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
), (PVOID
)Ccb
);
497 // we can't purge Cache when more than one link exists
499 ForcedCleanUp
= FALSE
;
502 if ( (FileObject
->Flags
& FO_CACHE_SUPPORTED
) &&
503 (NtReqFcb
->SectionObject
.DataSectionObject
) ) {
504 BOOLEAN LastNonCached
= (!Fcb
->CachedOpenHandleCount
&&
505 Fcb
->OpenHandleCount
);
506 // If this was the last cached open, and there are open
507 // non-cached handles, attempt a flush and purge operation
508 // to avoid cache coherency overhead from these non-cached
509 // handles later. We ignore any I/O errors from the flush.
510 // We shall not flush deleted files
514 (!Fcb
->OpenHandleCount
&&
517 #ifndef UDF_READ_ONLY_BUILD
518 LONGLONG OldFileSize
, NewFileSize
;
520 if( (OldFileSize
= NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
) <
521 (NewFileSize
= NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
)) {
522 /* UDFZeroDataEx(NtReqFcb,
524 NewFileSize - OldFileSize,
525 TRUE, Vcb, FileObject);*/
527 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= NewFileSize
;
529 #endif //UDF_READ_ONLY_BUILD
530 MmPrint((" CcFlushCache()\n"));
531 CcFlushCache( &(NtReqFcb
->SectionObject
), NULL
, 0, &IoStatus
);
532 if(!NT_SUCCESS(IoStatus
.Status
)) {
533 MmPrint((" CcFlushCache() error: %x\n", IoStatus
.Status
));
534 RC
= IoStatus
.Status
;
537 // If file is deleted or it is last cached open, but there are
538 // some non-cached handles we should purge cache section
539 if(ForcedCleanUp
|| LastNonCached
) {
540 if(NtReqFcb
->SectionObject
.DataSectionObject
) {
541 MmPrint((" CcPurgeCacheSection()\n"));
542 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
544 /* MmPrint((" CcPurgeCacheSection()\n"));
545 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/
547 // we needn't Flush here. It will be done in UDFCloseFileInfoChain()
550 #ifndef UDF_READ_ONLY_BUILD
551 // Update FileTimes & Attrs
552 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) &&
553 !(Fcb
->FCBFlags
& (UDF_FCB_DELETE_ON_CLOSE
|
555 UDF_FCB_DIRECTORY /*|
556 UDF_FCB_READ_ONLY*/)) &&
557 !UDFIsAStreamDir(NextFileInfo
)) {
560 KeQuerySystemTime((PLARGE_INTEGER
)&NtTime
);
561 // Check if we should set ARCHIVE bit & LastWriteTime
562 if(FileObject
->Flags
& FO_FILE_MODIFIED
) {
564 PDIR_INDEX_ITEM DirNdx
;
565 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo
), NextFileInfo
->Index
);
568 if(!(Ccb
->CCBFlags
& UDF_CCB_ATTRIBUTES_SET
) &&
569 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
)) {
570 Attr
= UDFAttributesToNT(DirNdx
, NextFileInfo
->Dloc
->FileEntry
);
571 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
572 UDFAttributesToUDF(DirNdx
, NextFileInfo
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
575 if(!(Ccb
->CCBFlags
& UDF_CCB_WRITE_TIME_SET
) &&
576 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_MODIFY_TIME
)) {
577 UDFSetFileXTime(NextFileInfo
, NULL
, &NtTime
, NULL
, &NtTime
);
578 NtReqFcb
->LastWriteTime
.QuadPart
=
579 NtReqFcb
->LastAccessTime
.QuadPart
= NtTime
;
583 #ifdef EVALUATION_TIME_LIMIT
584 KeQuerySystemTime(&UDFGlobalData
.UDFCurrentTime
);
585 t
= (ULONG
)(UDFGlobalData
.UDFCurrentTime
.QuadPart
/ (10*1000*1000));
587 if(UDFGlobalData
.UDFFlags
& UDF_DATA_FLAGS_UNREGISTERED
) {
588 if(t
-TIME_JAN_1_2003
> UDF_MAX_DATE
||
589 t
-TIME_JAN_1_2003
< UDF_MIN_DATE
) {
590 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_READ_ONLY
;
593 #endif //EVALUATION_TIME_LIMIT
594 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
595 // Update sizes in DirIndex
596 if(!Fcb
->OpenHandleCount
) {
597 ASize
= UDFGetFileAllocationSize(Vcb
, NextFileInfo
);
598 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
599 UDFSetFileSizeInDirNdx(Vcb
, NextFileInfo
, &ASize
);
601 if(FileObject
->Flags
& FO_FILE_SIZE_CHANGED
) {
602 ASize
= //UDFGetFileAllocationSize(Vcb, NextFileInfo);
603 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
;
604 UDFSetFileSizeInDirNdx(Vcb
, NextFileInfo
, &ASize
);
608 if((FileObject
->Flags
& FO_FILE_FAST_IO_READ
) &&
609 !(Ccb
->CCBFlags
& UDF_CCB_ACCESS_TIME_SET
) &&
610 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ACCESS_TIME
)) {
611 UDFSetFileXTime(NextFileInfo
, NULL
, &NtTime
, NULL
, NULL
);
612 NtReqFcb
->LastAccessTime
.QuadPart
= NtTime
;
613 // ChangeTime = TRUE;
615 // ChangeTime (AttrTime)
616 if(!(Ccb
->CCBFlags
& UDF_CCB_MODIFY_TIME_SET
) &&
617 (Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ATTR_TIME
) &&
618 (ChangeTime
|| (Ccb
->CCBFlags
& (UDF_CCB_ATTRIBUTES_SET
|
619 UDF_CCB_CREATE_TIME_SET
|
620 UDF_CCB_ACCESS_TIME_SET
|
621 UDF_CCB_WRITE_TIME_SET
))) ) {
622 UDFSetFileXTime(NextFileInfo
, NULL
, NULL
, &NtTime
, NULL
);
623 NtReqFcb
->ChangeTime
.QuadPart
= NtTime
;
626 #endif //UDF_READ_ONLY_BUILD
628 if(!(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) &&
630 // flush system cache
631 MmPrint((" CcUninitializeCacheMap()\n"));
632 CcUninitializeCacheMap(FileObject
, &(UDFGlobalData
.UDFLargeZero
), NULL
);
634 MmPrint((" CcUninitializeCacheMap()\n"));
635 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
638 // release resources now.
639 // they'll be acquired in UDFCloseFileInfoChain()
640 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
641 UDFReleaseResource(&(NtReqFcb
->MainResource
));
644 if(Fcb
->FileInfo
->ParentFile
) {
645 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
646 UDFReleaseResource(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
));
648 UDFReleaseResource(&(Vcb
->VCBResource
));
650 AcquiredParentFCB
= FALSE
;
653 RC2
= UDFCloseFileInfoChain(Vcb
, NextFileInfo
, Ccb
->TreeLength
, TRUE
);
657 Ccb
->CCBFlags
|= UDF_CCB_CLEANED
;
659 // We must clean up the share access at this time, since we may not
660 // get a Close call for awhile if the file was mapped through this
662 IoRemoveShareAccess( FileObject
, &(NtReqFcb
->FCBShareAccess
) );
664 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
666 FileObject
->Flags
|= FO_CLEANUP_COMPLETE
;
673 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
674 UDFReleaseResource(&(NtReqFcb
->MainResource
));
677 if(AcquiredParentFCB
) {
678 if(Fcb
->FileInfo
->ParentFile
) {
679 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
);
680 UDFReleaseResource(&(Fcb
->FileInfo
->ParentFile
->Fcb
->NTRequiredFCB
->MainResource
));
682 UDFReleaseResource(&(Vcb
->VCBResource
));
687 UDFReleaseResource(&(Vcb
->VCBResource
));
691 if (!_SEH2_AbnormalTermination()) {
693 Irp
->IoStatus
.Status
= RC
;
694 Irp
->IoStatus
.Information
= 0;
695 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
696 // Free up the Irp Context
697 UDFReleaseIrpContext(PtrIrpContext
);
700 } _SEH2_END
; // end of "__finally" processing
702 } // end UDFCommonCleanup()
705 This routine walks through the tree to RootDir &
706 calls UDFCloseFile__() for each file instance
710 UDFCloseFileInfoChain(
712 IN PUDF_FILE_INFO fi
,
714 IN BOOLEAN VcbAcquired
717 PUDF_FILE_INFO ParentFI
;
719 PtrUDFFCB ParentFcb
= NULL
;
720 NTSTATUS RC
= STATUS_SUCCESS
;
723 // we can't process Tree until we can acquire Vcb
725 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
727 AdPrint(("UDFCloseFileInfoChain\n"));
728 for(; TreeLength
&& fi
; TreeLength
--) {
730 // close parent chain (if any)
731 // if we started path parsing not from RootDir on Create,
732 // we would never get RootDir here
733 ValidateFileInfo(fi
);
736 if(ParentFI
= fi
->ParentFile
) {
737 ParentFcb
= fi
->Fcb
->ParentFcb
;
739 ASSERT(ParentFcb
->NTRequiredFCB
);
740 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
741 UDFAcquireResourceExclusive(&(ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
742 ASSERT(ParentFcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
743 ASSERT(ParentFcb
->NTRequiredFCB
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
745 AdPrint(("Acquiring VCB...\n"));
746 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
749 // acquire current file/dir
750 // we must assure that no more threads try to reuse this object
752 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->NTRequiredFCB
);
753 UDFAcquireResourceExclusive(&(Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
754 ASSERT_REF(Fcb
->ReferenceCount
>= fi
->RefCount
);
755 if(!(Fcb
->FCBFlags
& UDF_FCB_DELETED
) &&
756 (Fcb
->FCBFlags
& UDF_FCB_VALID
))
757 UDFWriteSecurity(Vcb
, Fcb
, &(Fcb
->NTRequiredFCB
->SecurityDesc
));
758 RC2
= UDFCloseFile__(Vcb
,fi
);
761 ASSERT_REF(Fcb
->ReferenceCount
> fi
->RefCount
);
762 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->NTRequiredFCB
);
763 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->MainResource
));
766 RC2
= UDFCloseFile__(Vcb
,fi
);
772 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
773 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
775 UDFReleaseResource(&(Vcb
->VCBResource
));
781 UDFReleaseResource(&(Vcb
->VCBResource
));
785 } // end UDFCloseFileInfoChain()