[FASTFAT] Fix size checking in VfatGetFileNameInformation()
[reactos.git] / drivers / filesystems / udfs / flush.cpp
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 * File: Flush.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 * Contains code to handle the "Flush Buffers" dispatch entry point.
14 *
15 *************************************************************************/
16
17 #include "udffs.h"
18
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_FLUSH
21
22
23
24 /*************************************************************************
25 *
26 * Function: UDFFlush()
27 *
28 * Description:
29 * The I/O Manager will invoke this routine to handle a flush buffers
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/Error
38 *
39 *************************************************************************/
40 NTSTATUS
41 NTAPI
42 UDFFlush(
43 PDEVICE_OBJECT DeviceObject, // the logical volume device object
44 PIRP Irp) // I/O Request Packet
45 {
46 NTSTATUS RC = STATUS_SUCCESS;
47 PtrUDFIrpContext PtrIrpContext = NULL;
48 BOOLEAN AreWeTopLevel = FALSE;
49
50 UDFPrint(("UDFFlush: \n"));
51
52 FsRtlEnterFileSystem();
53 ASSERT(DeviceObject);
54 ASSERT(Irp);
55
56 // set the top level context
57 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
58 ASSERT(!UDFIsFSDevObj(DeviceObject));
59
60 _SEH2_TRY {
61
62 // get an IRP context structure and issue the request
63 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
64 if(PtrIrpContext) {
65 RC = UDFCommonFlush(PtrIrpContext, Irp);
66 } else {
67 RC = STATUS_INSUFFICIENT_RESOURCES;
68 Irp->IoStatus.Status = RC;
69 Irp->IoStatus.Information = 0;
70 // complete the IRP
71 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
72 }
73
74 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
75
76 RC = UDFExceptionHandler(PtrIrpContext, Irp);
77
78 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
79 } _SEH2_END;
80
81 if (AreWeTopLevel) {
82 IoSetTopLevelIrp(NULL);
83 }
84
85 FsRtlExitFileSystem();
86
87 return(RC);
88 } // end UDFFlush()
89
90
91
92 /*************************************************************************
93 *
94 * Function: UDFCommonFlush()
95 *
96 * Description:
97 * The actual work is performed here. This routine may be invoked in one'
98 * of the two possible contexts:
99 * (a) in the context of a system worker thread
100 * (b) in the context of the original caller
101 *
102 * Expected Interrupt Level (for execution) :
103 *
104 * IRQL_PASSIVE_LEVEL
105 *
106 * Return Value: STATUS_SUCCESS/Error
107 *
108 *************************************************************************/
109 NTSTATUS
110 UDFCommonFlush(
111 PtrUDFIrpContext PtrIrpContext,
112 PIRP Irp
113 )
114 {
115 NTSTATUS RC = STATUS_SUCCESS;
116 PIO_STACK_LOCATION IrpSp = NULL;
117 PFILE_OBJECT FileObject = NULL;
118 PtrUDFFCB Fcb = NULL;
119 PtrUDFCCB Ccb = NULL;
120 PVCB Vcb = NULL;
121 PtrUDFNTRequiredFCB NtReqFcb = NULL;
122 BOOLEAN AcquiredVCB = FALSE;
123 BOOLEAN AcquiredFCB = FALSE;
124 BOOLEAN PostRequest = FALSE;
125 BOOLEAN CanWait = TRUE;
126
127 UDFPrint(("UDFCommonFlush: \n"));
128
129 _SEH2_TRY {
130
131 // Get some of the parameters supplied to us
132 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
133 // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous.
134 if (!CanWait) {
135 PostRequest = TRUE;
136 try_return(RC);
137 }
138
139 // First, get a pointer to the current I/O stack location
140 IrpSp = IoGetCurrentIrpStackLocation(Irp);
141 ASSERT(IrpSp);
142
143 FileObject = IrpSp->FileObject;
144 ASSERT(FileObject);
145
146 // Get the FCB and CCB pointers
147 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
148 ASSERT(Ccb);
149 Fcb = Ccb->Fcb;
150 ASSERT(Fcb);
151 NtReqFcb = Fcb->NTRequiredFCB;
152
153 // Check the type of object passed-in. That will determine the course of
154 // action we take.
155 if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || (Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) {
156
157 if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
158 Vcb = (PVCB)(Fcb);
159 } else {
160 Vcb = Fcb->Vcb;
161 }
162 Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
163
164 #ifdef UDF_DELAYED_CLOSE
165 UDFCloseAllDelayed(Vcb);
166 #endif //UDF_DELAYED_CLOSE
167
168 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
169 AcquiredVCB = TRUE;
170 // The caller wishes to flush all files for the mounted
171 // logical volume. The flush volume routine below should simply
172 // walk through all of the open file streams, acquire the
173 // VCB resource, and request the flush operation from the Cache
174 // Manager. Basically, the sequence of operations listed below
175 // for a single file should be executed on all open files.
176
177 UDFFlushLogicalVolume(PtrIrpContext, Irp, Vcb, 0);
178
179 UDFReleaseResource(&(Vcb->VCBResource));
180 AcquiredVCB = FALSE;
181
182 try_return(RC);
183 } else
184 if (!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
185 // This is a regular file.
186 Vcb = Fcb->Vcb;
187 ASSERT(Vcb);
188 if(!ExIsResourceAcquiredExclusiveLite(&(Vcb->VCBResource)) &&
189 !ExIsResourceAcquiredSharedLite(&(Vcb->VCBResource))) {
190 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
191 AcquiredVCB = TRUE;
192 }
193 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
194 UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), TRUE);
195 AcquiredFCB = TRUE;
196
197 // Request the Cache Manager to perform a flush operation.
198 // Further, instruct the Cache Manager that we wish to flush the
199 // entire file stream.
200 UDFFlushAFile(Fcb, Ccb, &(Irp->IoStatus), 0);
201 RC = Irp->IoStatus.Status;
202
203 // Some log-based FSD implementations may wish to flush their
204 // log files at this time. Finally, we should update the time-stamp
205 // values for the file stream appropriately. This would involve
206 // obtaining the current time and modifying the appropriate directory
207 // entry fields.
208 } else {
209 Vcb = Fcb->Vcb;
210 }
211
212 try_exit: NOTHING;
213
214 } _SEH2_FINALLY {
215
216 if (AcquiredFCB) {
217 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
218 UDFReleaseResource(&(NtReqFcb->MainResource));
219 AcquiredFCB = FALSE;
220 }
221 if (AcquiredVCB) {
222 UDFReleaseResource(&(Vcb->VCBResource));
223 AcquiredVCB = FALSE;
224 }
225
226 if(!_SEH2_AbnormalTermination()) {
227 if (PostRequest) {
228 // Nothing to lock now.
229 BrutePoint();
230 RC = UDFPostRequest(PtrIrpContext, Irp);
231 } else {
232 // Some applications like this request very much
233 // (ex. WinWord). But it's not a good idea for CD-R/RW media
234 if(Vcb->FlushMedia) {
235 PIO_STACK_LOCATION PtrNextIoStackLocation = NULL;
236 NTSTATUS RC1 = STATUS_SUCCESS;
237
238 // Send the request down at this point.
239 // To do this, we must set the next IRP stack location, and
240 // maybe set a completion routine.
241 // Be careful about marking the IRP pending if the lower level
242 // driver returned pending and we do have a completion routine!
243 PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp);
244 *PtrNextIoStackLocation = *IrpSp;
245
246 // Set the completion routine to "eat-up" any
247 // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower
248 // level driver.
249 IoSetCompletionRoutine(Irp, UDFFlushCompletion, NULL, TRUE, TRUE, TRUE);
250
251 RC1 = IoCallDriver(Vcb->TargetDeviceObject, Irp);
252
253 RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1);
254
255 // Release the IRP context at this time.
256 UDFReleaseIrpContext(PtrIrpContext);
257 } else {
258 Irp->IoStatus.Status = RC;
259 Irp->IoStatus.Information = 0;
260 // Free up the Irp Context
261 UDFReleaseIrpContext(PtrIrpContext);
262 // complete the IRP
263 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
264 }
265 }
266 }
267 } _SEH2_END;
268
269 return(RC);
270 } // end UDFCommonFlush()
271
272
273 /*************************************************************************
274 *
275 * Function: UDFFlushAFile()
276 *
277 * Description:
278 * Tell the Cache Manager to perform a flush.
279 *
280 * Expected Interrupt Level (for execution) :
281 *
282 * IRQL_PASSIVE_LEVEL
283 *
284 * Return Value: None
285 *
286 *************************************************************************/
287 ULONG
288 UDFFlushAFile(
289 IN PtrUDFFCB Fcb,
290 IN PtrUDFCCB Ccb,
291 OUT PIO_STATUS_BLOCK PtrIoStatus,
292 IN ULONG FlushFlags
293 )
294 {
295 BOOLEAN SetArchive = FALSE;
296 // BOOLEAN PurgeCache = FALSE;
297 ULONG ret_val = 0;
298
299 UDFPrint(("UDFFlushAFile: \n"));
300 if(!Fcb)
301 return 0;
302
303 _SEH2_TRY {
304 if(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)
305 return 0;
306 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
307 BrutePoint();
308 } _SEH2_END;
309 #ifndef UDF_READ_ONLY_BUILD
310 // Flush Security if required
311 _SEH2_TRY {
312 UDFWriteSecurity(Fcb->Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc));
313 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
314 BrutePoint();
315 } _SEH2_END;
316 #endif //UDF_READ_ONLY_BUILD
317 // Flush SDir if any
318 _SEH2_TRY {
319 if(UDFHasAStreamDir(Fcb->FileInfo) &&
320 Fcb->FileInfo->Dloc->SDirInfo &&
321 !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) ) {
322 ret_val |=
323 UDFFlushADirectory(Fcb->Vcb, Fcb->FileInfo->Dloc->SDirInfo, PtrIoStatus, FlushFlags);
324 }
325 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
326 BrutePoint();
327 } _SEH2_END;
328 // Flush File
329 _SEH2_TRY {
330 if((Fcb->CachedOpenHandleCount || !Fcb->OpenHandleCount) &&
331 Fcb->NTRequiredFCB->SectionObject.DataSectionObject) {
332 if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED)
333 &&
334 ((Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED) ||
335 (Ccb && !(Ccb->CCBFlags & UDF_CCB_FLUSHED)) )) {
336 MmPrint((" CcFlushCache()\n"));
337 CcFlushCache(&(Fcb->NTRequiredFCB->SectionObject), NULL, 0, PtrIoStatus);
338 }
339 // notice, that we should purge cache
340 // we can't do it now, because it may cause last Close
341 // request & thus, structure deallocation
342 // PurgeCache = TRUE;
343
344 #ifndef UDF_READ_ONLY_BUILD
345 if(Ccb) {
346 if( (Ccb->FileObject->Flags & FO_FILE_MODIFIED) &&
347 !(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET)) {
348 if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME) {
349 LONGLONG NtTime;
350 KeQuerySystemTime((PLARGE_INTEGER)&NtTime);
351 UDFSetFileXTime(Fcb->FileInfo, NULL, NULL, NULL, &NtTime);
352 Fcb->NTRequiredFCB->LastWriteTime.QuadPart = NtTime;
353 }
354 SetArchive = TRUE;
355 Ccb->FileObject->Flags &= ~FO_FILE_MODIFIED;
356 }
357 if(Ccb->FileObject->Flags & FO_FILE_SIZE_CHANGED) {
358 LONGLONG ASize = UDFGetFileAllocationSize(Fcb->Vcb, Fcb->FileInfo);
359 UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, &ASize);
360 Ccb->FileObject->Flags &= ~FO_FILE_SIZE_CHANGED;
361 }
362 }
363 #endif //UDF_READ_ONLY_BUILD
364 }
365 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
366 BrutePoint();
367 } _SEH2_END;
368
369 _SEH2_TRY {
370 #ifndef UDF_READ_ONLY_BUILD
371 if(SetArchive &&
372 (Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) {
373 ULONG Attr;
374 PDIR_INDEX_ITEM DirNdx;
375 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index);
376 // Archive bit
377 Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry);
378 if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
379 UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
380 }
381 #endif //UDF_READ_ONLY_BUILD
382 UDFFlushFile__( Fcb->Vcb, Fcb->FileInfo, FlushFlags);
383 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
384 BrutePoint();
385 } _SEH2_END;
386
387 /* if(PurgeCache) {
388 _SEH2_TRY {
389 MmPrint((" CcPurgeCacheSection()\n"));
390 CcPurgeCacheSection( &(Fcb->NTRequiredFCB->SectionObject), NULL, 0, FALSE );
391 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
392 BrutePoint();
393 } _SEH2_END;
394 }*/
395
396 return ret_val;
397 } // end UDFFlushAFile()
398
399 /*************************************************************************
400 *
401 * Function: UDFFlushADirectory()
402 *
403 * Description:
404 * Tell the Cache Manager to perform a flush for all files
405 * in current directory & all subdirectories and flush all metadata
406 *
407 * Expected Interrupt Level (for execution) :
408 *
409 * IRQL_PASSIVE_LEVEL
410 *
411 * Return Value: None
412 *
413 *************************************************************************/
414 ULONG
415 UDFFlushADirectory(
416 IN PVCB Vcb,
417 IN PUDF_FILE_INFO FI,
418 OUT PIO_STATUS_BLOCK PtrIoStatus,
419 IN ULONG FlushFlags
420 )
421 {
422 UDFPrint(("UDFFlushADirectory: \n"));
423 // PDIR_INDEX_HDR hDI;
424 PDIR_INDEX_ITEM DI;
425 // BOOLEAN Referenced = FALSE;
426 ULONG ret_val = 0;
427
428 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)
429 return 0;
430
431 if(!FI || !FI->Dloc || !FI->Dloc->DirIndex) goto SkipFlushDir;
432 // hDI = FI->Dloc->DirIndex;
433
434 // Flush Security if required
435 _SEH2_TRY {
436 UDFWriteSecurity(Vcb, FI->Fcb, &(FI->Fcb->NTRequiredFCB->SecurityDesc));
437 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
438 BrutePoint();
439 } _SEH2_END;
440 // Flush SDir if any
441 _SEH2_TRY {
442 if(UDFHasAStreamDir(FI) &&
443 FI->Dloc->SDirInfo &&
444 !UDFIsSDirDeleted(FI->Dloc->SDirInfo) ) {
445 ret_val |=
446 UDFFlushADirectory(Vcb, FI->Dloc->SDirInfo, PtrIoStatus, FlushFlags);
447 }
448 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
449 BrutePoint();
450 } _SEH2_END;
451
452 // Flush Dir Tree
453 _SEH2_TRY {
454 UDF_DIR_SCAN_CONTEXT ScanContext;
455 PUDF_FILE_INFO tempFI;
456
457 if(UDFDirIndexInitScan(FI, &ScanContext, 2)) {
458 while((DI = UDFDirIndexScan(&ScanContext, &tempFI))) {
459 // Flush Dir entry
460 _SEH2_TRY {
461 if(!tempFI) continue;
462 if(UDFIsADirectory(tempFI)) {
463 UDFFlushADirectory(Vcb, tempFI, PtrIoStatus, FlushFlags);
464 } else {
465 UDFFlushAFile(tempFI->Fcb, NULL, PtrIoStatus, FlushFlags);
466 }
467 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
468 BrutePoint();
469 } _SEH2_END;
470 if(UDFFlushIsBreaking(Vcb, FlushFlags)) {
471 ret_val |= UDF_FLUSH_FLAGS_INTERRUPTED;
472 break;
473 }
474 }
475 }
476 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
477 BrutePoint();
478 } _SEH2_END;
479 SkipFlushDir:
480 // Flush Dir
481 _SEH2_TRY {
482 UDFFlushFile__( Vcb, FI, FlushFlags );
483 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
484 BrutePoint();
485 } _SEH2_END;
486
487 return ret_val;
488 } // end UDFFlushADirectory()
489
490 /*************************************************************************
491 *
492 * Function: UDFFlushLogicalVolume()
493 *
494 * Description:
495 * Flush everything beginning from root directory.
496 * Vcb must be previously acquired exclusively.
497 *
498 * Expected Interrupt Level (for execution) :
499 *
500 * IRQL_PASSIVE_LEVEL
501 *
502 * Return Value: None
503 *
504 *************************************************************************/
505 ULONG
506 UDFFlushLogicalVolume(
507 IN PtrUDFIrpContext PtrIrpContext,
508 IN PIRP Irp,
509 IN PVCB Vcb,
510 IN ULONG FlushFlags
511 )
512 {
513 ULONG ret_val = 0;
514 #ifndef UDF_READ_ONLY_BUILD
515 IO_STATUS_BLOCK IoStatus;
516
517 UDFPrint(("UDFFlushLogicalVolume: \n"));
518
519 _SEH2_TRY {
520 if(Vcb->VCBFlags & (UDF_VCB_FLAGS_RAW_DISK/* |
521 UDF_VCB_FLAGS_MEDIA_READ_ONLY*/))
522 return 0;
523 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)
524 return 0;
525 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED))
526 return 0;
527
528 // NOTE: This function may also be invoked internally as part of
529 // processing a shutdown request.
530 ASSERT(Vcb->RootDirFCB);
531 ret_val |= UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, FlushFlags);
532
533 // if(UDFFlushIsBreaking(Vcb, FlushFlags))
534 // return;
535 // flush internal cache
536 if(FlushFlags & UDF_FLUSH_FLAGS_LITE) {
537 UDFPrint((" Lite flush, keep Modified=%d.\n", Vcb->Modified));
538 } else {
539 if(Vcb->VerifyOnWrite) {
540 UDFPrint(("UDF: Flushing cache for verify\n"));
541 //WCacheFlushAll__(&(Vcb->FastCache), Vcb);
542 WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA);
543 UDFVFlush(Vcb);
544 }
545 // umount (this is internal operation, NT will "dismount" volume later)
546 UDFUmount__(Vcb);
547
548 UDFPreClrModified(Vcb);
549 WCacheFlushAll__(&(Vcb->FastCache), Vcb);
550 UDFClrModified(Vcb);
551 }
552
553 } _SEH2_FINALLY {
554 ;
555 } _SEH2_END;
556 #endif //UDF_READ_ONLY_BUILD
557
558 return ret_val;
559 } // end UDFFlushLogicalVolume()
560
561
562 /*************************************************************************
563 *
564 * Function: UDFFlushCompletion()
565 *
566 * Description:
567 * Eat up any bad errors.
568 *
569 * Expected Interrupt Level (for execution) :
570 *
571 * IRQL_PASSIVE_LEVEL
572 *
573 * Return Value: None
574 *
575 *************************************************************************/
576 NTSTATUS
577 NTAPI
578 UDFFlushCompletion(
579 PDEVICE_OBJECT PtrDeviceObject,
580 PIRP Irp,
581 PVOID Context
582 )
583 {
584 // NTSTATUS RC = STATUS_SUCCESS;
585
586 UDFPrint(("UDFFlushCompletion: \n"));
587
588 if (Irp->PendingReturned) {
589 IoMarkIrpPending(Irp);
590 }
591
592 if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
593 // cannot do much here, can we?
594 Irp->IoStatus.Status = STATUS_SUCCESS;
595 }
596
597 return(STATUS_SUCCESS);
598 } // end UDFFlushCompletion()
599
600
601 /*
602 Check if we should break FlushTree process
603 */
604 BOOLEAN
605 UDFFlushIsBreaking(
606 IN PVCB Vcb,
607 IN ULONG FlushFlags
608 )
609 {
610 BOOLEAN ret_val = FALSE;
611 // if(!(FlushFlags & UDF_FLUSH_FLAGS_BREAKABLE))
612 return FALSE;
613 UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE);
614 ret_val = (Vcb->VCBFlags & UDF_VCB_FLAGS_FLUSH_BREAK_REQ) ? TRUE : FALSE;
615 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_FLUSH_BREAK_REQ;
616 UDFReleaseResource(&(Vcb->FlushResource));
617 return ret_val;
618 } // end UDFFlushIsBreaking()
619
620 /*
621 Signal FlushTree break request. Note, this is
622 treated as recommendation only
623 */
624 VOID
625 UDFFlushTryBreak(
626 IN PVCB Vcb
627 )
628 {
629 UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE);
630 Vcb->VCBFlags |= UDF_VCB_FLAGS_FLUSH_BREAK_REQ;
631 UDFReleaseResource(&(Vcb->FlushResource));
632 } // end UDFFlushTryBreak()