1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7 
8  Module name: Cleanup.cpp
9 
10  Abstract:
11 
12     Contains code to handle the "Cleanup" dispatch entry point.
13 
14  Environment:
15 
16     Kernel mode only
17 */
18 
19 #include            "udffs.h"
20 
21 // define the file specific bug-check id
22 #define         UDF_BUG_CHECK_ID                UDF_FILE_CLEANUP
23 
24 
25 /*************************************************************************
26 *
27 * Function: UDFCleanup()
28 *
29 * Description:
30 *   The I/O Manager will invoke this routine to handle a cleanup
31 *   request
32 *
33 * Expected Interrupt Level (for execution) :
34 *
35 *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
36 *   to be deferred to a worker thread context)
37 *
38 * Return Value: STATUS_SUCCESS
39 *
40 *************************************************************************/
41 NTSTATUS
42 NTAPI
UDFCleanup(PDEVICE_OBJECT DeviceObject,PIRP Irp)43 UDFCleanup(
44     PDEVICE_OBJECT  DeviceObject,  // the logical volume device object
45     PIRP            Irp            // I/O Request Packet
46     )
47 {
48     NTSTATUS                RC = STATUS_SUCCESS;
49     PtrUDFIrpContext        PtrIrpContext = NULL;
50     BOOLEAN                 AreWeTopLevel = FALSE;
51 
52     TmPrint(("UDFCleanup\n"));
53 
54     FsRtlEnterFileSystem();
55     ASSERT(DeviceObject);
56     ASSERT(Irp);
57 
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;
64 
65         if(UDFGlobalData.AutoFormatCount == IoGetCurrentIrpStackLocation(Irp)->FileObject) {
66             UDFPrint(("Deregister Autoformat\n"));
67             UDFGlobalData.AutoFormatCount = NULL;
68         }
69 
70         IoCompleteRequest(Irp, IO_NO_INCREMENT);
71         FsRtlExitFileSystem();
72         return(RC);
73     }
74 
75     // set the top level context
76     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
77 
78     _SEH2_TRY {
79 
80         // get an IRP context structure and issue the request
81         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
82         if(PtrIrpContext) {
83             RC = UDFCommonCleanup(PtrIrpContext, Irp);
84         } else {
85             RC = STATUS_INSUFFICIENT_RESOURCES;
86             Irp->IoStatus.Status = RC;
87             Irp->IoStatus.Information = 0;
88             // complete the IRP
89             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
90         }
91 
92     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
93 
94         RC = UDFExceptionHandler(PtrIrpContext, Irp);
95 
96         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
97     } _SEH2_END;
98 
99     if (AreWeTopLevel) {
100         IoSetTopLevelIrp(NULL);
101     }
102 
103     FsRtlExitFileSystem();
104 
105     return(RC);
106 } // end UDFCleanup()
107 
108 /*************************************************************************
109 *
110 * Function: UDFCommonCleanup()
111 *
112 * Description:
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
117 *
118 * Expected Interrupt Level (for execution) :
119 *
120 *  IRQL_PASSIVE_LEVEL
121 *
122 * Return Value: Does not matter!
123 *
124 *************************************************************************/
125 NTSTATUS
UDFCommonCleanup(PtrUDFIrpContext PtrIrpContext,PIRP Irp)126 UDFCommonCleanup(
127     PtrUDFIrpContext PtrIrpContext,
128     PIRP             Irp)
129 {
130     IO_STATUS_BLOCK         IoStatus;
131     NTSTATUS                RC = STATUS_SUCCESS;
132     NTSTATUS                RC2;
133     PIO_STACK_LOCATION      IrpSp = NULL;
134     PFILE_OBJECT            FileObject = NULL;
135     PtrUDFFCB               Fcb = NULL;
136     PtrUDFCCB               Ccb = NULL;
137     PVCB                    Vcb = NULL;
138     PtrUDFNTRequiredFCB     NtReqFcb = NULL;
139     ULONG                   lc = 0;
140     BOOLEAN                 AcquiredVcb = FALSE;
141     BOOLEAN                 AcquiredFCB = FALSE;
142     BOOLEAN                 AcquiredParentFCB = FALSE;
143 
144 //    BOOLEAN                 CompleteIrp = TRUE;
145 //    BOOLEAN                 PostRequest = FALSE;
146     BOOLEAN                 ChangeTime = FALSE;
147 #ifdef UDF_DBG
148     BOOLEAN                 CanWait = FALSE;
149 #endif // UDF_DBG
150     BOOLEAN                 ForcedCleanUp = FALSE;
151 
152     PUDF_FILE_INFO          NextFileInfo = NULL;
153 #ifdef UDF_DBG
154     UNICODE_STRING          CurName;
155     PDIR_INDEX_HDR          DirNdx;
156 #endif // UDF_DBG
157 //    PUDF_DATALOC_INFO       Dloc;
158 
159     TmPrint(("UDFCommonCleanup\n"));
160 
161 //    BrutePoint();
162 
163     _SEH2_TRY {
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);
167 
168         FileObject = IrpSp->FileObject;
169 
170         // Get the FCB and CCB pointers
171         Ccb = (PtrUDFCCB)(FileObject->FsContext2);
172         ASSERT(Ccb);
173         Fcb = Ccb->Fcb;
174         ASSERT(Fcb);
175 
176         Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
177         ASSERT(Vcb);
178         ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
179 //        Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
180 #ifdef UDF_DBG
181         CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
182         AdPrint(("   %s\n", CanWait ? "Wt" : "nw"));
183         ASSERT(CanWait);
184 #endif // UDF_DBG
185         UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
186         AcquiredVcb = 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.
196         //  BrutePoint();
197         NtReqFcb = Fcb->NTRequiredFCB;
198 
199         if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
200             AdPrint(("Cleaning up Volume\n"));
201             AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount));
202 
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));
208             }
209             ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1));
210 
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)) {
216 
217                 Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
218             }
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);
227             }
228 
229             MmPrint(("    CcUninitializeCacheMap()\n"));
230             CcUninitializeCacheMap(FileObject, NULL, NULL);
231             // reset device
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);
237             }
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
240             //  File Object.
241             IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) );
242 
243             try_return(RC = STATUS_SUCCESS);
244         }
245 //        BrutePoint();
246 #ifdef UDF_DBG
247         DirNdx = UDFGetDirIndexByFileInfo(Fcb->FileInfo);
248         if(DirNdx) {
249             CurName.Buffer = UDFDirIndex(DirNdx, Fcb->FileInfo->Index)->FName.Buffer;
250             if(CurName.Buffer) {
251                 AdPrint(("Cleaning up file: %ws %8.8x\n", CurName.Buffer, FileObject));
252             } else {
253                 AdPrint(("Cleaning up file: ??? \n"));
254             }
255         }
256 #endif //UDF_DBG
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);
262         } else {
263             UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
264         }
265         AcquiredParentFCB = TRUE;
266         // Acquire current object
267         UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
268         UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
269         AcquiredFCB = 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));
276         }
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 );
291             }
292         }
293 #endif //UDF_READ_ONLY_BUILD
294 
295         if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
296             //  Unlock all outstanding file locks.
297             FsRtlFastUnlockAll(&(NtReqFcb->FileLock),
298                                FileObject,
299                                IoGetRequestorProcess(Irp),
300                                NULL);
301         }
302         // get Link count
303         lc = UDFGetFileLinkCount(Fcb->FileInfo);
304 
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;
312 
313             // we should mark all streams of the file being deleted
314             // for deletion too, if there are no more Links to
315             // main data stream
316             if((lc <= 1) &&
317                !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) {
318                 RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
319             }
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));
324             AcquiredFCB = FALSE;
325             if(Fcb->FileInfo->ParentFile) {
326                 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
327                 UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource));
328             } else {
329                 UDFReleaseResource(&(Vcb->VCBResource));
330             }
331             AcquiredParentFCB = FALSE;
332             UDFReleaseResource(&(Vcb->VCBResource));
333             AcquiredVcb = FALSE;
334 
335             // Make system to issue last Close request
336             // for our Target ...
337             UDFRemoveFromSystemDelayedQueue(Fcb);
338 
339 #ifdef UDF_DELAYED_CLOSE
340             // remove file from our DelayedClose queue
341             UDFRemoveFromDelayedQueue(Fcb);
342             ASSERT(!Fcb->IrpContextLite);
343 #endif //UDF_DELAYED_CLOSE
344 
345             UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
346             AcquiredVcb = TRUE;
347             if(Fcb->FileInfo->ParentFile) {
348                 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
349                 UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE);
350             } else {
351                 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
352             }
353             AcquiredParentFCB = TRUE;
354             UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
355             UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
356             AcquiredFCB = TRUE;
357 
358             // we should set file sizes to zero if there are no more
359             // links to this file
360             if(lc <= 1) {
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));
368 
369                 UDFReleaseResource(&(NtReqFcb->PagingIoResource));
370             }
371         }
372 #endif //UDF_READ_ONLY_BUILD
373 
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;
379         }
380 #endif //UDF_DELAYED_CLOSE
381 
382         NextFileInfo = Fcb->FileInfo;
383 
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)) {
388 
389             // can we do it ?
390             if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
391                 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
392                 if(!UDFIsDirEmpty__(NextFileInfo)) {
393                     // forget about it
394                     Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
395                     goto DiscardDelete;
396                 }
397             } else
398             if (lc <= 1) {
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));
407                 }
408             }
409             // mark parent object for deletion if requested
410             if((Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) &&
411                 Fcb->ParentFcb) {
412                 ASSERT(!(Fcb->ParentFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
413                 Fcb->ParentFcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE;
414             }
415             // flush file. It is required by UDFUnlinkFile__()
416             RC = UDFFlushFile__(Vcb, NextFileInfo);
417             if(!NT_SUCCESS(RC)) {
418                 AdPrint(("Error flushing file !!!\n"));
419             }
420             // try to unlink
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.
427 
428                 // WARNING! We should keep SDir & Streams if there is a
429                 // link to this file
430                 if(NextFileInfo->Dloc &&
431                    NextFileInfo->Dloc->SDirInfo &&
432                    NextFileInfo->Dloc->SDirInfo->Fcb) {
433 
434                     BrutePoint();
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
440                     }
441                     goto NotifyDelete;
442 
443                 } else {
444                     // Getting here means that we can't delete file because of
445                     // References/PemissionsDenied/Smth.Else,
446                     // but not Linked+OpenedStream
447                     BrutePoint();
448 //                    RC = STATUS_SUCCESS;
449                     goto DiscardDelete_1;
450                 }
451             } else {
452 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;
457                 if(NT_SUCCESS(RC))
458                     Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
459                 Fcb->FCBFlags |= UDF_FCB_DELETED;
460                 RC = STATUS_SUCCESS;
461             }
462 NotifyDelete:
463             // We should prevent SetEOF operations on completly
464             // deleted data streams
465             if(lc < 1) {
466                 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED;
467             }
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);
473             } else {
474                 UDFNotifyFullReportChange( Vcb, NextFileInfo,
475                                        UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
476                                        FILE_ACTION_REMOVED);
477             }
478         } else
479         if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
480 DiscardDelete:
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) |
484                                      0,
485                                      UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED);
486         }
487 #endif //UDF_READ_ONLY_BUILD
488 
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 );
492         }
493 
494         // we can't purge Cache when more than one link exists
495         if(lc > 1) {
496             ForcedCleanUp = FALSE;
497         }
498 
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
508             RC = STATUS_SUCCESS;
509             if(  LastNonCached
510                       ||
511                 (!Fcb->OpenHandleCount &&
512                  !ForcedCleanUp) ) {
513 
514 #ifndef UDF_READ_ONLY_BUILD
515                 LONGLONG OldFileSize, NewFileSize;
516 
517                 if( (OldFileSize = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) <
518                     (NewFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) {
519 /*                    UDFZeroDataEx(NtReqFcb,
520                                   OldFileSize,
521                                   NewFileSize - OldFileSize,
522                                   TRUE, Vcb, FileObject);*/
523 
524                     NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileSize;
525                 }
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;
532                 }
533             }
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 );
540                 }
541 /*                MmPrint(("    CcPurgeCacheSection()\n"));
542                 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/
543             }
544             // we needn't Flush here. It will be done in UDFCloseFileInfoChain()
545         }
546 
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 |
551                               UDF_FCB_DELETED /*|
552                               UDF_FCB_DIRECTORY |
553                               UDF_FCB_READ_ONLY*/)) &&
554            !UDFIsAStreamDir(NextFileInfo)) {
555             LONGLONG NtTime;
556             LONGLONG ASize;
557             KeQuerySystemTime((PLARGE_INTEGER)&NtTime);
558             // Check if we should set ARCHIVE bit & LastWriteTime
559             if(FileObject->Flags & FO_FILE_MODIFIED) {
560                 ULONG Attr;
561                 PDIR_INDEX_ITEM DirNdx;
562                 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index);
563                 ASSERT(DirNdx);
564                 // Archive bit
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);
570                 }
571                 // WriteTime
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;
577                     ChangeTime = TRUE;
578                 }
579             }
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);
586                 } else
587                 if(FileObject->Flags & FO_FILE_SIZE_CHANGED) {
588                     ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo);
589                         NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
590                     UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize);
591                 }
592             }
593             // AccessTime
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;
600             }
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;
610             }
611         }
612 #endif //UDF_READ_ONLY_BUILD
613 
614         if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY) &&
615             ForcedCleanUp) {
616             // flush system cache
617             MmPrint(("    CcUninitializeCacheMap()\n"));
618             CcUninitializeCacheMap(FileObject, &(UDFGlobalData.UDFLargeZero), NULL);
619         } else {
620             MmPrint(("    CcUninitializeCacheMap()\n"));
621             CcUninitializeCacheMap(FileObject, NULL, NULL);
622         }
623 
624         // release resources now.
625         // they'll be acquired in UDFCloseFileInfoChain()
626         UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
627         UDFReleaseResource(&(NtReqFcb->MainResource));
628         AcquiredFCB = FALSE;
629 
630         if(Fcb->FileInfo->ParentFile) {
631             UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
632             UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource));
633         } else {
634             UDFReleaseResource(&(Vcb->VCBResource));
635         }
636         AcquiredParentFCB = FALSE;
637         // close the chain
638         ASSERT(AcquiredVcb);
639         RC2 = UDFCloseFileInfoChain(Vcb, NextFileInfo, Ccb->TreeLength, TRUE);
640         if(NT_SUCCESS(RC))
641             RC = RC2;
642 
643         Ccb->CCBFlags |= UDF_CCB_CLEANED;
644 
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
647         //  File Object.
648         IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) );
649 
650         NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
651 
652         FileObject->Flags |= FO_CLEANUP_COMPLETE;
653 
654 try_exit: NOTHING;
655 
656     } _SEH2_FINALLY {
657 
658         if(AcquiredFCB) {
659             UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
660             UDFReleaseResource(&(NtReqFcb->MainResource));
661         }
662 
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));
667             } else {
668                 UDFReleaseResource(&(Vcb->VCBResource));
669             }
670         }
671 
672         if(AcquiredVcb) {
673             UDFReleaseResource(&(Vcb->VCBResource));
674             AcquiredVcb = FALSE;
675         }
676 
677         if (!_SEH2_AbnormalTermination()) {
678             // complete the IRP
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);
684         }
685 
686     } _SEH2_END; // end of "__finally" processing
687     return(RC);
688 } // end UDFCommonCleanup()
689 
690 /*
691     This routine walks through the tree to RootDir &
692     calls UDFCloseFile__() for each file instance
693     imho, Useful feature
694  */
695 NTSTATUS
UDFCloseFileInfoChain(IN PVCB Vcb,IN PUDF_FILE_INFO fi,IN ULONG TreeLength,IN BOOLEAN VcbAcquired)696 UDFCloseFileInfoChain(
697     IN PVCB Vcb,
698     IN PUDF_FILE_INFO fi,
699     IN ULONG TreeLength,
700     IN BOOLEAN VcbAcquired
701     )
702 {
703     PUDF_FILE_INFO ParentFI;
704     PtrUDFFCB Fcb;
705     PtrUDFFCB ParentFcb = NULL;
706     NTSTATUS RC = STATUS_SUCCESS;
707     NTSTATUS RC2;
708 
709     // we can't process Tree until we can acquire Vcb
710     if(!VcbAcquired)
711         UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
712 
713     AdPrint(("UDFCloseFileInfoChain\n"));
714     for(; TreeLength && fi; TreeLength--) {
715 
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);
720 
721         // acquire parent
722         if((ParentFI = fi->ParentFile)) {
723             ParentFcb = fi->Fcb->ParentFcb;
724             ASSERT(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);
730         } else {
731             AdPrint(("Acquiring VCB...\n"));
732             UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
733             AdPrint(("Done\n"));
734         }
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);
745             if(!NT_SUCCESS(RC2))
746                 RC = RC2;
747             ASSERT_REF(Fcb->ReferenceCount > fi->RefCount);
748             UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
749             UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
750         } else {
751             BrutePoint();
752             RC2 = UDFCloseFile__(Vcb,fi);
753             if(!NT_SUCCESS(RC2))
754                 RC = RC2;
755         }
756 
757         if(ParentFI) {
758             UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
759             UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
760         } else {
761             UDFReleaseResource(&(Vcb->VCBResource));
762         }
763         fi = ParentFI;
764     }
765 
766     if(!VcbAcquired)
767         UDFReleaseResource(&(Vcb->VCBResource));
768 
769     return RC;
770 
771 } // end UDFCloseFileInfoChain()
772