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