3a3dae0c5a2ae3f80335407480559be819293425
[reactos.git] / reactos / drivers / filesystems / udfs / cleanup.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 ////////////////////////////////////////////////////////////////////
5 /*
6
7 Module name: Cleanup.cpp
8
9 Abstract:
10
11 Contains code to handle the "Cleanup" dispatch entry point.
12
13 Environment:
14
15 Kernel mode only
16 */
17
18 #include "udffs.h"
19
20 // define the file specific bug-check id
21 #define UDF_BUG_CHECK_ID UDF_FILE_CLEANUP
22
23
24 /*************************************************************************
25 *
26 * Function: UDFCleanup()
27 *
28 * Description:
29 * The I/O Manager will invoke this routine to handle a cleanup
30 * request
31 *
32 * Expected Interrupt Level (for execution) :
33 *
34 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
35 * to be deferred to a worker thread context)
36 *
37 * Return Value: STATUS_SUCCESS
38 *
39 *************************************************************************/
40 NTSTATUS
41 NTAPI
42 UDFCleanup(
43 PDEVICE_OBJECT DeviceObject, // the logical volume device object
44 PIRP Irp // I/O Request Packet
45 )
46 {
47 NTSTATUS RC = STATUS_SUCCESS;
48 PtrUDFIrpContext PtrIrpContext = NULL;
49 BOOLEAN AreWeTopLevel = FALSE;
50
51 TmPrint(("UDFCleanup\n"));
52
53 FsRtlEnterFileSystem();
54 ASSERT(DeviceObject);
55 ASSERT(Irp);
56
57 // If we were called with our file system device object instead of a
58 // volume device object, just complete this request with STATUS_SUCCESS
59 if (UDFIsFSDevObj(DeviceObject)) {
60 // this is a cleanup of the FSD itself
61 Irp->IoStatus.Status = RC;
62 Irp->IoStatus.Information = 0;
63
64 if(UDFGlobalData.AutoFormatCount == IoGetCurrentIrpStackLocation(Irp)->FileObject) {
65 KdPrint(("Deregister Autoformat\n"));
66 UDFGlobalData.AutoFormatCount = NULL;
67 }
68
69 IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 FsRtlExitFileSystem();
71 return(RC);
72 }
73
74 // set the top level context
75 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
76
77 _SEH2_TRY {
78
79 // get an IRP context structure and issue the request
80 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
81 if(PtrIrpContext) {
82 RC = UDFCommonCleanup(PtrIrpContext, Irp);
83 } else {
84 RC = STATUS_INSUFFICIENT_RESOURCES;
85 Irp->IoStatus.Status = RC;
86 Irp->IoStatus.Information = 0;
87 // complete the IRP
88 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
89 }
90
91 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
92
93 RC = UDFExceptionHandler(PtrIrpContext, Irp);
94
95 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
96 } _SEH2_END;
97
98 if (AreWeTopLevel) {
99 IoSetTopLevelIrp(NULL);
100 }
101
102 FsRtlExitFileSystem();
103
104 return(RC);
105 } // end UDFCleanup()
106
107 /*************************************************************************
108 *
109 * Function: UDFCommonCleanup()
110 *
111 * Description:
112 * The actual work is performed here. This routine may be invoked in one'
113 * of the two possible contexts:
114 * (a) in the context of a system worker thread
115 * (b) in the context of the original caller
116 *
117 * Expected Interrupt Level (for execution) :
118 *
119 * IRQL_PASSIVE_LEVEL
120 *
121 * Return Value: Does not matter!
122 *
123 *************************************************************************/
124 NTSTATUS
125 UDFCommonCleanup(
126 PtrUDFIrpContext PtrIrpContext,
127 PIRP Irp)
128 {
129 IO_STATUS_BLOCK IoStatus;
130 NTSTATUS RC = STATUS_SUCCESS;
131 NTSTATUS RC2;
132 PIO_STACK_LOCATION IrpSp = NULL;
133 PFILE_OBJECT FileObject = NULL;
134 PtrUDFFCB Fcb = NULL;
135 PtrUDFCCB Ccb = NULL;
136 PVCB Vcb = NULL;
137 PtrUDFNTRequiredFCB NtReqFcb = NULL;
138 ULONG lc = 0;
139 BOOLEAN AcquiredVcb = FALSE;
140 BOOLEAN AcquiredFCB = FALSE;
141 BOOLEAN AcquiredParentFCB = FALSE;
142
143 // BOOLEAN CompleteIrp = TRUE;
144 // BOOLEAN PostRequest = FALSE;
145 BOOLEAN ChangeTime = FALSE;
146 #ifdef UDF_DBG
147 BOOLEAN CanWait = FALSE;
148 #endif // UDF_DBG
149 BOOLEAN ForcedCleanUp = FALSE;
150
151 PUDF_FILE_INFO NextFileInfo = NULL;
152 #ifdef UDF_DBG
153 UNICODE_STRING CurName;
154 PDIR_INDEX_HDR DirNdx;
155 #endif // UDF_DBG
156 // PUDF_DATALOC_INFO Dloc;
157 #ifdef EVALUATION_TIME_LIMIT
158 ULONG t;
159 #endif //EVALUATION_TIME_LIMIT
160
161 TmPrint(("UDFCommonCleanup\n"));
162
163 // BrutePoint();
164
165 _SEH2_TRY {
166 // First, get a pointer to the current I/O stack location
167 IrpSp = IoGetCurrentIrpStackLocation(Irp);
168 if(!IrpSp) try_return(RC = STATUS_INVALID_PARAMETER);
169
170 FileObject = IrpSp->FileObject;
171
172 // Get the FCB and CCB pointers
173 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
174 ASSERT(Ccb);
175 Fcb = Ccb->Fcb;
176 ASSERT(Fcb);
177
178 Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
179 ASSERT(Vcb);
180 ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
181 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
182 #ifdef UDF_DBG
183 CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
184 AdPrint((" %s\n", CanWait ? "Wt" : "nw"));
185 ASSERT(CanWait);
186 #endif // UDF_DBG
187 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
188 AcquiredVcb = TRUE;
189 // Steps we shall take at this point are:
190 // (a) Acquire the file (FCB) exclusively
191 // (b) Flush file data to disk
192 // (c) Talk to the FSRTL package (if we use it) about pending oplocks.
193 // (d) Notify the FSRTL package for use with pending notification IRPs
194 // (e) Unlock byte-range locks (if any were acquired by process)
195 // (f) Update time stamp values (e.g. fast-IO had been performed)
196 // (g) Inform the Cache Manager to uninitialize Cache Maps ...
197 // and other similar stuff.
198 // BrutePoint();
199 NtReqFcb = Fcb->NTRequiredFCB;
200
201 if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
202 AdPrint(("Cleaning up Volume\n"));
203 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount));
204
205 UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount));
206 UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount));
207 if(FileObject->Flags & FO_CACHE_SUPPORTED) {
208 // we've cached close
209 UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount));
210 }
211 ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1));
212
213 // If this handle had write access, and actually wrote something,
214 // flush the device buffers, and then set the verify bit now
215 // just to be safe (in case there is no dismount).
216 if( FileObject->WriteAccess &&
217 (FileObject->Flags & FO_FILE_MODIFIED)) {
218
219 Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
220 }
221 // User may decide to close locked volume without call to unlock proc
222 // So, handle this situation properly & unlock it now...
223 if (FileObject == Vcb->VolumeLockFileObject) {
224 Vcb->VolumeLockFileObject = NULL;
225 Vcb->VolumeLockPID = -1;
226 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
227 Vcb->Vpb->Flags &= ~VPB_LOCKED;
228 UDFNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);
229 }
230
231 MmPrint((" CcUninitializeCacheMap()\n"));
232 CcUninitializeCacheMap(FileObject, NULL, NULL);
233 // reset device
234 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) &&
235 (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) {
236 // this call doesn't modify data buffer
237 // it just requires its presence
238 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
239 }
240 // We must clean up the share access at this time, since we may not
241 // get a Close call for awhile if the file was mapped through this
242 // File Object.
243 IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) );
244
245 try_return(RC = STATUS_SUCCESS);
246 }
247 // BrutePoint();
248 #ifdef UDF_DBG
249 DirNdx = UDFGetDirIndexByFileInfo(Fcb->FileInfo);
250 if(DirNdx) {
251 CurName.Buffer = UDFDirIndex(DirNdx, Fcb->FileInfo->Index)->FName.Buffer;
252 if(CurName.Buffer) {
253 AdPrint(("Cleaning up file: %ws %8.8x\n", CurName.Buffer, FileObject));
254 } else {
255 AdPrint(("Cleaning up file: ??? \n"));
256 }
257 }
258 #endif //UDF_DBG
259 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount));
260 // Acquire parent object
261 if(Fcb->FileInfo->ParentFile) {
262 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
263 UDFAcquireResourceExclusive(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource),TRUE);
264 } else {
265 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
266 }
267 AcquiredParentFCB = TRUE;
268 // Acquire current object
269 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
270 UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
271 AcquiredFCB = TRUE;
272 // dereference object
273 UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount));
274 UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount));
275 if(FileObject->Flags & FO_CACHE_SUPPORTED) {
276 // we've cached close
277 UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount));
278 }
279 ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1));
280 // check if Ccb being cleaned up has DeleteOnClose flag set
281 #ifndef UDF_READ_ONLY_BUILD
282 if(Ccb->CCBFlags & UDF_CCB_DELETE_ON_CLOSE) {
283 AdPrint((" DeleteOnClose\n"));
284 // Ok, now we'll become 'delete on close'...
285 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
286 Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE;
287 FileObject->DeletePending = TRUE;
288 // Report this to the dir notify package for a directory.
289 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
290 FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
291 (PVOID)Ccb, NULL, FALSE, FALSE,
292 0, NULL, NULL, NULL );
293 }
294 }
295 #endif //UDF_READ_ONLY_BUILD
296
297 if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
298 // Unlock all outstanding file locks.
299 FsRtlFastUnlockAll(&(NtReqFcb->FileLock),
300 FileObject,
301 IoGetRequestorProcess(Irp),
302 NULL);
303 }
304 // get Link count
305 lc = UDFGetFileLinkCount(Fcb->FileInfo);
306
307 #ifndef UDF_READ_ONLY_BUILD
308 if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) &&
309 !(Fcb->OpenHandleCount)) {
310 // This can be useful for Streams, those were brutally deleted
311 // (together with parent object)
312 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
313 FileObject->DeletePending = TRUE;
314
315 // we should mark all streams of the file being deleted
316 // for deletion too, if there are no more Links to
317 // main data stream
318 if((lc <= 1) &&
319 !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) {
320 RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
321 }
322 // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE
323 // flag is already set & the file can't be opened
324 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
325 UDFReleaseResource(&(NtReqFcb->MainResource));
326 AcquiredFCB = FALSE;
327 if(Fcb->FileInfo->ParentFile) {
328 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
329 UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource));
330 } else {
331 UDFReleaseResource(&(Vcb->VCBResource));
332 }
333 AcquiredParentFCB = FALSE;
334 UDFReleaseResource(&(Vcb->VCBResource));
335 AcquiredVcb = FALSE;
336
337 // Make system to issue last Close request
338 // for our Target ...
339 UDFRemoveFromSystemDelayedQueue(Fcb);
340
341 #ifdef UDF_DELAYED_CLOSE
342 // remove file from our DelayedClose queue
343 UDFRemoveFromDelayedQueue(Fcb);
344 ASSERT(!Fcb->IrpContextLite);
345 #endif //UDF_DELAYED_CLOSE
346
347 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
348 AcquiredVcb = TRUE;
349 if(Fcb->FileInfo->ParentFile) {
350 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
351 UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE);
352 } else {
353 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
354 }
355 AcquiredParentFCB = TRUE;
356 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
357 UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
358 AcquiredFCB = TRUE;
359
360 // we should set file sizes to zero if there are no more
361 // links to this file
362 if(lc <= 1) {
363 // Synchronize here with paging IO
364 UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource),TRUE);
365 // set file size to zero (for system cache manager)
366 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
367 NtReqFcb->CommonFCBHeader.FileSize.QuadPart =
368 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0;
369 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize));
370
371 UDFReleaseResource(&(NtReqFcb->PagingIoResource));
372 }
373 }
374 #endif //UDF_READ_ONLY_BUILD
375
376 #ifdef UDF_DELAYED_CLOSE
377 if ((Fcb->ReferenceCount == 1) &&
378 /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above
379 (!(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)) ) {
380 Fcb->FCBFlags |= UDF_FCB_DELAY_CLOSE;
381 }
382 #endif //UDF_DELAYED_CLOSE
383
384 NextFileInfo = Fcb->FileInfo;
385
386 #ifndef UDF_READ_ONLY_BUILD
387 // do we need to delete it now ?
388 if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) &&
389 !(Fcb->OpenHandleCount)) {
390
391 // can we do it ?
392 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
393 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
394 if(!UDFIsDirEmpty__(NextFileInfo)) {
395 // forget about it
396 Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
397 goto DiscardDelete;
398 }
399 } else
400 if (lc <= 1) {
401 // Synchronize here with paging IO
402 BOOLEAN AcquiredPagingIo;
403 AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb->PagingIoResource));
404 // set file size to zero (for UdfInfo package)
405 // we should not do this for directories and linked files
406 UDFResizeFile__(Vcb, NextFileInfo, 0);
407 if(AcquiredPagingIo) {
408 UDFReleaseResource(&(NtReqFcb->PagingIoResource));
409 }
410 }
411 // mark parent object for deletion if requested
412 if((Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) &&
413 Fcb->ParentFcb) {
414 ASSERT(!(Fcb->ParentFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
415 Fcb->ParentFcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE;
416 }
417 // flush file. It is required by UDFUnlinkFile__()
418 RC = UDFFlushFile__(Vcb, NextFileInfo);
419 if(!NT_SUCCESS(RC)) {
420 AdPrint(("Error flushing file !!!\n"));
421 }
422 // try to unlink
423 if((RC = UDFUnlinkFile__(Vcb, NextFileInfo, TRUE)) == STATUS_CANNOT_DELETE) {
424 // If we can't delete file with Streams due to references,
425 // mark SDir & Streams
426 // for Deletion. We shall also set DELETE_PARENT flag to
427 // force Deletion of the current file later... when curently
428 // opened Streams would be cleaned up.
429
430 // WARNING! We should keep SDir & Streams if there is a
431 // link to this file
432 if(NextFileInfo->Dloc &&
433 NextFileInfo->Dloc->SDirInfo &&
434 NextFileInfo->Dloc->SDirInfo->Fcb) {
435
436 BrutePoint();
437 if(!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) {
438 // RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
439 //#ifdef UDF_ALLOW_PRETEND_DELETED
440 UDFPretendFileDeleted__(Vcb, Fcb->FileInfo);
441 //#endif //UDF_ALLOW_PRETEND_DELETED
442 }
443 goto NotifyDelete;
444
445 } else {
446 // Getting here means that we can't delete file because of
447 // References/PemissionsDenied/Smth.Else,
448 // but not Linked+OpenedStream
449 BrutePoint();
450 // RC = STATUS_SUCCESS;
451 goto DiscardDelete_1;
452 }
453 } else {
454 DiscardDelete_1:
455 // We have got an ugly ERROR, or
456 // file is deleted, so forget about it
457 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
458 ForcedCleanUp = TRUE;
459 if(NT_SUCCESS(RC))
460 Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
461 Fcb->FCBFlags |= UDF_FCB_DELETED;
462 RC = STATUS_SUCCESS;
463 }
464 NotifyDelete:
465 // We should prevent SetEOF operations on completly
466 // deleted data streams
467 if(lc < 1) {
468 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED;
469 }
470 // Report that we have removed an entry.
471 if(UDFIsAStream(NextFileInfo)) {
472 UDFNotifyFullReportChange( Vcb, NextFileInfo,
473 FILE_NOTIFY_CHANGE_STREAM_NAME,
474 FILE_ACTION_REMOVED_STREAM);
475 } else {
476 UDFNotifyFullReportChange( Vcb, NextFileInfo,
477 UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
478 FILE_ACTION_REMOVED);
479 }
480 } else
481 if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
482 DiscardDelete:
483 UDFNotifyFullReportChange( Vcb, NextFileInfo,
484 ((Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) |
485 ((Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) |
486 0,
487 UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED);
488 }
489 #endif //UDF_READ_ONLY_BUILD
490
491 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
492 // Report to the dir notify package for a directory.
493 FsRtlNotifyCleanup( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb );
494 }
495
496 // we can't purge Cache when more than one link exists
497 if(lc > 1) {
498 ForcedCleanUp = FALSE;
499 }
500
501 if ( (FileObject->Flags & FO_CACHE_SUPPORTED) &&
502 (NtReqFcb->SectionObject.DataSectionObject) ) {
503 BOOLEAN LastNonCached = (!Fcb->CachedOpenHandleCount &&
504 Fcb->OpenHandleCount);
505 // If this was the last cached open, and there are open
506 // non-cached handles, attempt a flush and purge operation
507 // to avoid cache coherency overhead from these non-cached
508 // handles later. We ignore any I/O errors from the flush.
509 // We shall not flush deleted files
510 RC = STATUS_SUCCESS;
511 if( LastNonCached
512 ||
513 (!Fcb->OpenHandleCount &&
514 !ForcedCleanUp) ) {
515
516 #ifndef UDF_READ_ONLY_BUILD
517 LONGLONG OldFileSize, NewFileSize;
518
519 if( (OldFileSize = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) <
520 (NewFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) {
521 /* UDFZeroDataEx(NtReqFcb,
522 OldFileSize,
523 NewFileSize - OldFileSize,
524 TRUE, Vcb, FileObject);*/
525
526 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileSize;
527 }
528 #endif //UDF_READ_ONLY_BUILD
529 MmPrint((" CcFlushCache()\n"));
530 CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, &IoStatus );
531 if(!NT_SUCCESS(IoStatus.Status)) {
532 MmPrint((" CcFlushCache() error: %x\n", IoStatus.Status));
533 RC = IoStatus.Status;
534 }
535 }
536 // If file is deleted or it is last cached open, but there are
537 // some non-cached handles we should purge cache section
538 if(ForcedCleanUp || LastNonCached) {
539 if(NtReqFcb->SectionObject.DataSectionObject) {
540 MmPrint((" CcPurgeCacheSection()\n"));
541 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );
542 }
543 /* MmPrint((" CcPurgeCacheSection()\n"));
544 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/
545 }
546 // we needn't Flush here. It will be done in UDFCloseFileInfoChain()
547 }
548
549 #ifndef UDF_READ_ONLY_BUILD
550 // Update FileTimes & Attrs
551 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) &&
552 !(Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE |
553 UDF_FCB_DELETED /*|
554 UDF_FCB_DIRECTORY /*|
555 UDF_FCB_READ_ONLY*/)) &&
556 !UDFIsAStreamDir(NextFileInfo)) {
557 LONGLONG NtTime;
558 LONGLONG ASize;
559 KeQuerySystemTime((PLARGE_INTEGER)&NtTime);
560 // Check if we should set ARCHIVE bit & LastWriteTime
561 if(FileObject->Flags & FO_FILE_MODIFIED) {
562 ULONG Attr;
563 PDIR_INDEX_ITEM DirNdx;
564 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index);
565 ASSERT(DirNdx);
566 // Archive bit
567 if(!(Ccb->CCBFlags & UDF_CCB_ATTRIBUTES_SET) &&
568 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) {
569 Attr = UDFAttributesToNT(DirNdx, NextFileInfo->Dloc->FileEntry);
570 if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
571 UDFAttributesToUDF(DirNdx, NextFileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
572 }
573 // WriteTime
574 if(!(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) &&
575 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME)) {
576 UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, &NtTime);
577 NtReqFcb->LastWriteTime.QuadPart =
578 NtReqFcb->LastAccessTime.QuadPart = NtTime;
579 ChangeTime = TRUE;
580 }
581 }
582 #ifdef EVALUATION_TIME_LIMIT
583 KeQuerySystemTime(&UDFGlobalData.UDFCurrentTime);
584 t = (ULONG)(UDFGlobalData.UDFCurrentTime.QuadPart / (10*1000*1000));
585 t /= (60*60*24);
586 if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) {
587 if(t-TIME_JAN_1_2003 > UDF_MAX_DATE ||
588 t-TIME_JAN_1_2003 < UDF_MIN_DATE) {
589 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
590 }
591 }
592 #endif //EVALUATION_TIME_LIMIT
593 if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
594 // Update sizes in DirIndex
595 if(!Fcb->OpenHandleCount) {
596 ASize = UDFGetFileAllocationSize(Vcb, NextFileInfo);
597 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
598 UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize);
599 } else
600 if(FileObject->Flags & FO_FILE_SIZE_CHANGED) {
601 ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo);
602 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
603 UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize);
604 }
605 }
606 // AccessTime
607 if((FileObject->Flags & FO_FILE_FAST_IO_READ) &&
608 !(Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) &&
609 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ACCESS_TIME)) {
610 UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, NULL);
611 NtReqFcb->LastAccessTime.QuadPart = NtTime;
612 // ChangeTime = TRUE;
613 }
614 // ChangeTime (AttrTime)
615 if(!(Ccb->CCBFlags & UDF_CCB_MODIFY_TIME_SET) &&
616 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ATTR_TIME) &&
617 (ChangeTime || (Ccb->CCBFlags & (UDF_CCB_ATTRIBUTES_SET |
618 UDF_CCB_CREATE_TIME_SET |
619 UDF_CCB_ACCESS_TIME_SET |
620 UDF_CCB_WRITE_TIME_SET))) ) {
621 UDFSetFileXTime(NextFileInfo, NULL, NULL, &NtTime, NULL);
622 NtReqFcb->ChangeTime.QuadPart = NtTime;
623 }
624 }
625 #endif //UDF_READ_ONLY_BUILD
626
627 if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY) &&
628 ForcedCleanUp) {
629 // flush system cache
630 MmPrint((" CcUninitializeCacheMap()\n"));
631 CcUninitializeCacheMap(FileObject, &(UDFGlobalData.UDFLargeZero), NULL);
632 } else {
633 MmPrint((" CcUninitializeCacheMap()\n"));
634 CcUninitializeCacheMap(FileObject, NULL, NULL);
635 }
636
637 // release resources now.
638 // they'll be acquired in UDFCloseFileInfoChain()
639 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
640 UDFReleaseResource(&(NtReqFcb->MainResource));
641 AcquiredFCB = FALSE;
642
643 if(Fcb->FileInfo->ParentFile) {
644 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
645 UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource));
646 } else {
647 UDFReleaseResource(&(Vcb->VCBResource));
648 }
649 AcquiredParentFCB = FALSE;
650 // close the chain
651 ASSERT(AcquiredVcb);
652 RC2 = UDFCloseFileInfoChain(Vcb, NextFileInfo, Ccb->TreeLength, TRUE);
653 if(NT_SUCCESS(RC))
654 RC = RC2;
655
656 Ccb->CCBFlags |= UDF_CCB_CLEANED;
657
658 // We must clean up the share access at this time, since we may not
659 // get a Close call for awhile if the file was mapped through this
660 // File Object.
661 IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) );
662
663 NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
664
665 FileObject->Flags |= FO_CLEANUP_COMPLETE;
666
667 try_exit: NOTHING;
668
669 } _SEH2_FINALLY {
670
671 if(AcquiredFCB) {
672 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
673 UDFReleaseResource(&(NtReqFcb->MainResource));
674 }
675
676 if(AcquiredParentFCB) {
677 if(Fcb->FileInfo->ParentFile) {
678 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
679 UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource));
680 } else {
681 UDFReleaseResource(&(Vcb->VCBResource));
682 }
683 }
684
685 if(AcquiredVcb) {
686 UDFReleaseResource(&(Vcb->VCBResource));
687 AcquiredVcb = FALSE;
688 }
689
690 if (!_SEH2_AbnormalTermination()) {
691 // complete the IRP
692 Irp->IoStatus.Status = RC;
693 Irp->IoStatus.Information = 0;
694 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
695 // Free up the Irp Context
696 UDFReleaseIrpContext(PtrIrpContext);
697 }
698
699 } _SEH2_END; // end of "__finally" processing
700 return(RC);
701 } // end UDFCommonCleanup()
702
703 /*
704 This routine walks through the tree to RootDir &
705 calls UDFCloseFile__() for each file instance
706 imho, Useful feature
707 */
708 NTSTATUS
709 UDFCloseFileInfoChain(
710 IN PVCB Vcb,
711 IN PUDF_FILE_INFO fi,
712 IN ULONG TreeLength,
713 IN BOOLEAN VcbAcquired
714 )
715 {
716 PUDF_FILE_INFO ParentFI;
717 PtrUDFFCB Fcb;
718 PtrUDFFCB ParentFcb = NULL;
719 NTSTATUS RC = STATUS_SUCCESS;
720 NTSTATUS RC2;
721
722 // we can't process Tree until we can acquire Vcb
723 if(!VcbAcquired)
724 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
725
726 AdPrint(("UDFCloseFileInfoChain\n"));
727 for(; TreeLength && fi; TreeLength--) {
728
729 // close parent chain (if any)
730 // if we started path parsing not from RootDir on Create,
731 // we would never get RootDir here
732 ValidateFileInfo(fi);
733
734 // acquire parent
735 if(ParentFI = fi->ParentFile) {
736 ParentFcb = fi->Fcb->ParentFcb;
737 ASSERT(ParentFcb);
738 ASSERT(ParentFcb->NTRequiredFCB);
739 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
740 UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE);
741 ASSERT(ParentFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
742 ASSERT(ParentFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);
743 } else {
744 AdPrint(("Acquiring VCB...\n"));
745 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
746 AdPrint(("Done\n"));
747 }
748 // acquire current file/dir
749 // we must assure that no more threads try to reuse this object
750 if(Fcb = fi->Fcb) {
751 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
752 UDFAcquireResourceExclusive(&(Fcb->NTRequiredFCB->MainResource),TRUE);
753 ASSERT_REF(Fcb->ReferenceCount >= fi->RefCount);
754 if(!(Fcb->FCBFlags & UDF_FCB_DELETED) &&
755 (Fcb->FCBFlags & UDF_FCB_VALID))
756 UDFWriteSecurity(Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc));
757 RC2 = UDFCloseFile__(Vcb,fi);
758 if(!NT_SUCCESS(RC2))
759 RC = RC2;
760 ASSERT_REF(Fcb->ReferenceCount > fi->RefCount);
761 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
762 UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
763 } else {
764 BrutePoint();
765 RC2 = UDFCloseFile__(Vcb,fi);
766 if(!NT_SUCCESS(RC2))
767 RC = RC2;
768 }
769
770 if(ParentFI) {
771 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
772 UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
773 } else {
774 UDFReleaseResource(&(Vcb->VCBResource));
775 }
776 fi = ParentFI;
777 }
778
779 if(!VcbAcquired)
780 UDFReleaseResource(&(Vcb->VCBResource));
781
782 return RC;
783
784 } // end UDFCloseFileInfoChain()