3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File Flush buffers routine for Fat called by the
20 // The Bug check file id for this module
23 #define BugCheckFileId (FAT_BUG_CHECK_FLUSH)
26 // The local debug trace level
29 #define Dbg (DEBUG_TRACE_FLUSH)
32 #pragma alloc_text(PAGE, FatCommonFlushBuffers)
33 #pragma alloc_text(PAGE, FatFlushDirectory)
34 #pragma alloc_text(PAGE, FatFlushFat)
35 #pragma alloc_text(PAGE, FatFlushFile)
36 #pragma alloc_text(PAGE, FatFlushVolume)
37 #pragma alloc_text(PAGE, FatFsdFlushBuffers)
38 #pragma alloc_text(PAGE, FatFlushDirentForFile)
39 #pragma alloc_text(PAGE, FatFlushFatEntries)
40 #pragma alloc_text(PAGE, FatHijackIrpAndFlushDevice)
44 // Local procedure prototypes
49 FatFlushCompletionRoutine (
50 IN PDEVICE_OBJECT DeviceObject
,
57 FatHijackCompletionRoutine (
58 IN PDEVICE_OBJECT DeviceObject
,
67 IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject
,
75 This routine implements the FSD part of Flush buffers.
79 VolumeDeviceObject - Supplies the volume device object where the
80 file being flushed exists
82 Irp - Supplies the Irp being processed
86 NTSTATUS - The FSD status for the IRP
92 PIRP_CONTEXT IrpContext
= NULL
;
98 DebugTrace(+1, Dbg
, "FatFsdFlushBuffers\n", 0);
101 // Call the common Cleanup routine, with blocking allowed if synchronous
104 FsRtlEnterFileSystem();
106 TopLevel
= FatIsIrpTopLevel( Irp
);
110 IrpContext
= FatCreateIrpContext( Irp
, CanFsdWait( Irp
) );
112 Status
= FatCommonFlushBuffers( IrpContext
, Irp
);
114 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
117 // We had some trouble trying to perform the requested
118 // operation, so we'll abort the I/O request with
119 // the error status that we get back from the
123 Status
= FatProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
126 if (TopLevel
) { IoSetTopLevelIrp( NULL
); }
128 FsRtlExitFileSystem();
131 // And return to our caller
134 DebugTrace(-1, Dbg
, "FatFsdFlushBuffers -> %08lx\n", Status
);
136 UNREFERENCED_PARAMETER( VolumeDeviceObject
);
143 FatCommonFlushBuffers (
144 IN PIRP_CONTEXT IrpContext
,
152 This is the common routine for flushing a buffer.
156 Irp - Supplies the Irp to process
160 NTSTATUS - The return status for the operation
167 PIO_STACK_LOCATION IrpSp
;
169 PFILE_OBJECT FileObject
;
171 TYPE_OF_OPEN TypeOfOpen
;
176 BOOLEAN VcbAcquired
= FALSE
;
177 BOOLEAN FcbAcquired
= FALSE
;
182 PBCB DirentBcb
= NULL
;
186 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
188 DebugTrace(+1, Dbg
, "FatCommonFlushBuffers\n", 0);
189 DebugTrace( 0, Dbg
, "Irp = %08lx\n", Irp
);
190 DebugTrace( 0, Dbg
, "->FileObject = %08lx\n", IrpSp
->FileObject
);
193 // Extract and decode the file object
196 FileObject
= IrpSp
->FileObject
;
197 TypeOfOpen
= FatDecodeFileObject( FileObject
, &Vcb
, &Fcb
, &Ccb
);
200 // CcFlushCache is always synchronous, so if we can't wait enqueue
201 // the irp to the Fsp.
204 if ( !FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) ) {
206 Status
= FatFsdPostRequest( IrpContext
, Irp
);
208 DebugTrace(-1, Dbg
, "FatCommonFlushBuffers -> %08lx\n", Status
);
212 Status
= STATUS_SUCCESS
;
217 // Case on the type of open that we are trying to flush
220 switch (TypeOfOpen
) {
222 case VirtualVolumeFile
:
226 DebugTrace(0, Dbg
, "Flush that does nothing\n", 0);
231 DebugTrace(0, Dbg
, "Flush User File Open\n", 0);
233 (VOID
)FatAcquireExclusiveFcb( IrpContext
, Fcb
);
237 FatVerifyFcb( IrpContext
, Fcb
);
240 // If the file is cached then flush its cache
243 Status
= FatFlushFile( IrpContext
, Fcb
, Flush
);
246 // Also update and flush the file's dirent in the parent directory if the
247 // file flush worked.
250 if (NT_SUCCESS( Status
)) {
253 // Insure that we get the filesize to disk correctly. This is
254 // benign if it was already good.
256 // (why do we need to do this?)
259 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
261 FatUpdateDirentFromFcb( IrpContext
, FileObject
, Fcb
, Ccb
);
264 // Flush the volume file to get any allocation information
268 if (FlagOn(Fcb
->FcbState
, FCB_STATE_FLUSH_FAT
)) {
270 Status
= FatFlushFat( IrpContext
, Vcb
);
272 ClearFlag(Fcb
->FcbState
, FCB_STATE_FLUSH_FAT
);
276 // Set the write through bit so that these modifications
277 // will be completed with the request.
280 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
285 case UserDirectoryOpen
:
288 // If the user had opened the root directory then we'll
289 // oblige by flushing the volume.
292 if (NodeType(Fcb
) != FAT_NTC_ROOT_DCB
) {
294 DebugTrace(0, Dbg
, "Flush a directory does nothing\n", 0);
300 DebugTrace(0, Dbg
, "Flush User Volume Open, or root dcb\n", 0);
303 // Acquire exclusive access to the Vcb.
308 Finished
= FatAcquireExclusiveVcb( IrpContext
, Vcb
);
315 // Mark the volume clean and then flush the volume file,
316 // and then all directories
319 Status
= FatFlushVolume( IrpContext
, Vcb
, Flush
);
322 // If the volume was dirty, do the processing that the delayed
323 // callback would have done.
326 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
)) {
329 // Cancel any pending clean volumes.
332 (VOID
)KeCancelTimer( &Vcb
->CleanVolumeTimer
);
333 (VOID
)KeRemoveQueueDpc( &Vcb
->CleanVolumeDpc
);
336 // The volume is now clean, note it.
339 if (!FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_MOUNTED_DIRTY
)) {
341 FatMarkVolume( IrpContext
, Vcb
, VolumeClean
);
342 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
);
346 // Unlock the volume if it is removable.
349 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVABLE_MEDIA
) &&
350 !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
)) {
352 FatToggleMediaEjectDisable( IrpContext
, Vcb
, FALSE
);
360 FatBugCheck( TypeOfOpen
, 0, 0 );
363 FatUnpinBcb( IrpContext
, DirentBcb
);
365 FatUnpinRepinnedBcbs( IrpContext
);
369 DebugUnwind( FatCommonFlushBuffers
);
371 FatUnpinBcb( IrpContext
, DirentBcb
);
373 if (VcbAcquired
) { FatReleaseVcb( IrpContext
, Vcb
); }
375 if (FcbAcquired
) { FatReleaseFcb( IrpContext
, Fcb
); }
378 // If this is a normal termination then pass the request on
379 // to the target device object.
382 if (!_SEH2_AbnormalTermination()) {
384 NTSTATUS DriverStatus
;
385 PIO_STACK_LOCATION NextIrpSp
;
388 // Get the next stack location, and copy over the stack location
391 NextIrpSp
= IoGetNextIrpStackLocation( Irp
);
396 // Set up the completion routine
399 IoSetCompletionRoutine( Irp
,
400 FatFlushCompletionRoutine
,
401 ULongToPtr( Status
),
410 DriverStatus
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
412 Status
= (DriverStatus
== STATUS_INVALID_DEVICE_REQUEST
) ?
413 Status
: DriverStatus
;
416 // Free the IrpContext and return to the caller.
419 FatCompleteRequest( IrpContext
, FatNull
, STATUS_SUCCESS
);
422 DebugTrace(-1, Dbg
, "FatCommonFlushBuffers -> %08lx\n", Status
);
431 IN PIRP_CONTEXT IrpContext
,
433 IN FAT_FLUSH_TYPE FlushType
440 This routine non-recursively flushes a dcb tree.
444 Dcb - Supplies the Dcb being flushed
446 FlushType - Specifies the kind of flushing to perform
460 PBCB DirentBcb
= NULL
;
463 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
465 BOOLEAN ClearWriteThroughOnExit
= FALSE
;
466 BOOLEAN ClearWaitOnExit
= FALSE
;
470 ASSERT( FatVcbAcquiredExclusive(IrpContext
, Dcb
->Vcb
) );
472 DebugTrace(+1, Dbg
, "FatFlushDirectory, Dcb = %08lx\n", Dcb
);
475 // First flush all the files, then the directories, to make sure all the
476 // file sizes and times get sets correctly on disk.
478 // We also have to check here if the "Ea Data. Sf" fcb really
479 // corressponds to an existing file.
482 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
484 ClearWriteThroughOnExit
= TRUE
;
485 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
488 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
490 ClearWaitOnExit
= TRUE
;
491 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
497 while (Fcb
!= NULL
) {
499 NextFcb
= FatGetNextFcbTopDown(IrpContext
, Fcb
, Dcb
);
501 if ( (NodeType( Fcb
) == FAT_NTC_FCB
) &&
502 (Vcb
->EaFcb
!= Fcb
) &&
503 !IsFileDeleted(IrpContext
, Fcb
)) {
505 (VOID
)FatAcquireExclusiveFcb( IrpContext
, Fcb
);
507 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
);
510 // Exception handler to catch and commute errors encountered
511 // doing the flush dance. We may encounter corruption, and
512 // should continue flushing the volume as much as possible.
518 // Standard handler to release resources, etc.
524 // Make sure the Fcb is OK.
529 FatVerifyFcb( IrpContext
, Fcb
);
531 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
532 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
534 FatResetExceptionState( IrpContext
);
538 // If this Fcb is not good skip it. Note that a 'continue'
539 // here would be very expensive as we inside a try{} body.
542 if (Fcb
->FcbCondition
!= FcbGood
) {
548 // In case a handle was never closed and the FS and AS are more
549 // than a cluster different, do this truncate.
552 if ( FlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
) ) {
554 FatTruncateFileAllocation( IrpContext
,
556 Fcb
->Header
.FileSize
.LowPart
);
560 // Also compare the file's dirent in the parent directory
561 // with the size information in the Fcb and update
562 // it if neccessary. Note that we don't mark the Bcb dirty
563 // because we will be flushing the file object presently, and
564 // Mm knows what's really dirty.
567 FatGetDirentFromFcbOrDcb( IrpContext
,
572 if (Dirent
->FileSize
!= Fcb
->Header
.FileSize
.LowPart
) {
574 Dirent
->FileSize
= Fcb
->Header
.FileSize
.LowPart
;
578 // We must unpin the Bcb before the flush since we recursively tear up
579 // the tree if Mm decides that the data section is no longer referenced
580 // and the final close comes in for this file. If this parent has no
581 // more children as a result, we will try to initiate teardown on it
582 // and Cc will deadlock against the active count of this Bcb.
585 FatUnpinBcb( IrpContext
, DirentBcb
);
588 // Now flush the file. Note that this may make the Fcb
589 // go away if Mm dereferences its file object.
592 Status
= FatFlushFile( IrpContext
, Fcb
, FlushType
);
594 if (!NT_SUCCESS(Status
)) {
596 ReturnStatus
= Status
;
602 FatUnpinBcb( IrpContext
, DirentBcb
);
605 // Since we have the Vcb exclusive we know that if any closes
606 // come in it is because the CcPurgeCacheSection caused the
610 if ( !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
) ) {
612 FatReleaseFcb( (IRPCONTEXT
), Fcb
);
616 } _SEH2_EXCEPT( (ReturnStatus
= FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode())) ?
617 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
619 FatResetExceptionState( IrpContext
);
627 // OK, now flush the directories.
632 while (Fcb
!= NULL
) {
634 NextFcb
= FatGetNextFcbTopDown(IrpContext
, Fcb
, Dcb
);
636 if ( (NodeType( Fcb
) != FAT_NTC_FCB
) &&
637 !IsFileDeleted(IrpContext
, Fcb
) ) {
640 // Make sure the Fcb is OK.
645 FatVerifyFcb( IrpContext
, Fcb
);
647 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
648 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
650 FatResetExceptionState( IrpContext
);
653 if (Fcb
->FcbCondition
== FcbGood
) {
655 Status
= FatFlushFile( IrpContext
, Fcb
, FlushType
);
657 if (!NT_SUCCESS(Status
)) {
659 ReturnStatus
= Status
;
669 FatUnpinRepinnedBcbs( IrpContext
);
671 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
673 ReturnStatus
= IrpContext
->ExceptionStatus
;
676 if (ClearWriteThroughOnExit
) {
678 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
680 if (ClearWaitOnExit
) {
682 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
685 DebugTrace(-1, Dbg
, "FatFlushDirectory -> 0x%08lx\n", ReturnStatus
);
693 IN PIRP_CONTEXT IrpContext
,
701 The function carefully flushes the entire FAT for a volume. It is
702 nessecary to dance around a bit because of complicated synchronization
707 Vcb - Supplies the Vcb whose FAT is being flushed
718 IO_STATUS_BLOCK Iosb
;
719 LARGE_INTEGER Offset
;
721 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
726 // If this volume is write protected, no need to flush.
729 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
)) {
731 return STATUS_SUCCESS
;
735 // Make sure the Vcb is OK.
740 FatVerifyVcb( IrpContext
, Vcb
);
742 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
743 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
745 FatResetExceptionState( IrpContext
);
748 if (Vcb
->VcbCondition
!= VcbGood
) {
750 return STATUS_FILE_INVALID
;
754 // The only way we have to correctly synchronize things is to
755 // repin stuff, and then unpin repin it.
757 // With NT 5.0, we can use some new cache manager support to make
758 // this a lot more efficient (important for FAT32). Since we're
759 // only worried about ranges that are dirty - and since we're a
760 // modified-no-write stream - we can assume that if there is no
761 // BCB, there is no work to do in the range. I.e., the lazy writer
764 // This is much better than reading the entire FAT in and trying
765 // to punch it out (see the test in the write path to blow
766 // off writes that don't correspond to dirty ranges of the FAT).
767 // For FAT32, this would be a *lot* of reading.
770 if (Vcb
->AllocationSupport
.FatIndexBitSize
!= 12) {
773 // Walk through the Fat, one page at a time.
779 NumberOfPages
= ( FatReservedBytes(&Vcb
->Bpb
) +
780 FatBytesPerFat(&Vcb
->Bpb
) +
781 (PAGE_SIZE
- 1) ) / PAGE_SIZE
;
784 for ( Page
= 0, Offset
.QuadPart
= 0;
785 Page
< NumberOfPages
;
786 Page
++, Offset
.LowPart
+= PAGE_SIZE
) {
790 if (CcPinRead( Vcb
->VirtualVolumeFile
,
793 PIN_WAIT
| PIN_IF_BCB
,
797 CcSetDirtyPinnedData( Bcb
, NULL
);
800 CcUnpinRepinnedBcb( Bcb
, TRUE
, &Iosb
);
802 if (!NT_SUCCESS(Iosb
.Status
)) {
804 ReturnStatus
= Iosb
.Status
;
808 } _SEH2_EXCEPT(FatExceptionFilter(IrpContext
, _SEH2_GetExceptionInformation())) {
810 ReturnStatus
= IrpContext
->ExceptionStatus
;
818 // We read in the entire fat in the 12 bit case.
821 Offset
.QuadPart
= FatReservedBytes( &Vcb
->Bpb
);
825 if (CcPinRead( Vcb
->VirtualVolumeFile
,
827 FatBytesPerFat( &Vcb
->Bpb
),
828 PIN_WAIT
| PIN_IF_BCB
,
832 CcSetDirtyPinnedData( Bcb
, NULL
);
835 CcUnpinRepinnedBcb( Bcb
, TRUE
, &Iosb
);
837 if (!NT_SUCCESS(Iosb
.Status
)) {
839 ReturnStatus
= Iosb
.Status
;
843 } _SEH2_EXCEPT(FatExceptionFilter(IrpContext
, _SEH2_GetExceptionInformation())) {
845 ReturnStatus
= IrpContext
->ExceptionStatus
;
855 IN PIRP_CONTEXT IrpContext
,
857 IN FAT_FLUSH_TYPE FlushType
864 The following routine is used to flush a volume to disk, including the
865 volume file, and ea file.
869 Vcb - Supplies the volume being flushed
871 FlushType - Specifies the kind of flushing to perform
875 NTSTATUS - The Status from the flush.
881 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
886 // If this volume is write protected, no need to flush.
889 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
)) {
891 return STATUS_SUCCESS
;
895 // Flush all the files and directories.
898 Status
= FatFlushDirectory( IrpContext
, Vcb
->RootDcb
, FlushType
);
900 if (!NT_SUCCESS(Status
)) {
902 ReturnStatus
= Status
;
909 Status
= FatFlushFat( IrpContext
, Vcb
);
911 if (!NT_SUCCESS(Status
)) {
913 ReturnStatus
= Status
;
917 // Unlock the volume if it is removable.
920 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVABLE_MEDIA
) &&
921 !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
)) {
923 FatToggleMediaEjectDisable( IrpContext
, Vcb
, FALSE
);
932 IN PIRP_CONTEXT IrpContext
,
934 IN FAT_FLUSH_TYPE FlushType
941 This routine simply flushes the data section on a file.
945 Fcb - Supplies the file being flushed
947 FlushType - Specifies the kind of flushing to perform
951 NTSTATUS - The Status from the flush.
956 IO_STATUS_BLOCK Iosb
;
961 CcFlushCache( &Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &Iosb
);
963 if ( !FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
)) {
966 // Grab and release PagingIo to serialize ourselves with the lazy writer.
967 // This will work to ensure that all IO has completed on the cached
970 // If we are to invalidate the file, now is the right time to do it. Do
971 // it non-recursively so we don't thump children before their time.
974 ExAcquireResourceExclusiveLite( Fcb
->Header
.PagingIoResource
, TRUE
);
976 if (FlushType
== FlushAndInvalidate
) {
978 FatMarkFcbCondition( IrpContext
, Fcb
, FcbBad
, FALSE
);
981 ExReleaseResourceLite( Fcb
->Header
.PagingIoResource
);
989 FatHijackIrpAndFlushDevice (
990 IN PIRP_CONTEXT IrpContext
,
992 IN PDEVICE_OBJECT TargetDeviceObject
999 This routine is called when we need to send a flush to a device but
1000 we don't have a flush Irp. What this routine does is make a copy
1001 of its current Irp stack location, but changes the Irp Major code
1002 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
1003 the knees in the completion routine, fix it up and return to the
1004 user as if nothing had happened.
1008 Irp - The Irp to hijack
1010 TargetDeviceObject - The device to send the request to.
1014 NTSTATUS - The Status from the flush in case anybody cares.
1021 PIO_STACK_LOCATION NextIrpSp
;
1026 // Get the next stack location, and copy over the stack location
1029 NextIrpSp
= IoGetNextIrpStackLocation( Irp
);
1031 *NextIrpSp
= *IoGetCurrentIrpStackLocation( Irp
);
1033 NextIrpSp
->MajorFunction
= IRP_MJ_FLUSH_BUFFERS
;
1034 NextIrpSp
->MinorFunction
= 0;
1037 // Set up the completion routine
1040 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
1042 IoSetCompletionRoutine( Irp
,
1043 FatHijackCompletionRoutine
,
1050 // Send the request.
1053 Status
= IoCallDriver( TargetDeviceObject
, Irp
);
1055 if (Status
== STATUS_PENDING
) {
1057 KeWaitForSingleObject( &Event
, Executive
, KernelMode
, FALSE
, NULL
);
1059 Status
= Irp
->IoStatus
.Status
;
1063 // If the driver doesn't support flushes, return SUCCESS.
1066 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) {
1067 Status
= STATUS_SUCCESS
;
1070 Irp
->IoStatus
.Status
= 0;
1071 Irp
->IoStatus
.Information
= 0;
1078 FatFlushFatEntries (
1079 IN PIRP_CONTEXT IrpContext
,
1087 Routine Description:
1089 This macro flushes the FAT page(s) containing the passed in run.
1093 Vcb - Supplies the volume being flushed
1095 Cluster - The starting cluster
1097 Count - The number of FAT entries in the run
1107 LARGE_INTEGER FileOffset
;
1109 IO_STATUS_BLOCK Iosb
;
1113 FileOffset
.HighPart
= 0;
1114 FileOffset
.LowPart
= FatReservedBytes( &Vcb
->Bpb
);
1116 if (Vcb
->AllocationSupport
.FatIndexBitSize
== 12) {
1118 FileOffset
.LowPart
+= Cluster
* 3 / 2;
1119 ByteCount
= (Count
* 3 / 2) + 1;
1121 } else if (Vcb
->AllocationSupport
.FatIndexBitSize
== 32) {
1123 FileOffset
.LowPart
+= Cluster
* sizeof(ULONG
);
1124 ByteCount
= Count
* sizeof(ULONG
);
1128 FileOffset
.LowPart
+= Cluster
* sizeof( USHORT
);
1129 ByteCount
= Count
* sizeof( USHORT
);
1133 CcFlushCache( &Vcb
->SectionObjectPointers
,
1138 if (NT_SUCCESS(Iosb
.Status
)) {
1139 Iosb
.Status
= FatHijackIrpAndFlushDevice( IrpContext
,
1140 IrpContext
->OriginatingIrp
,
1141 Vcb
->TargetDeviceObject
);
1144 if (!NT_SUCCESS(Iosb
.Status
)) {
1145 FatNormalizeAndRaiseStatus(IrpContext
, Iosb
.Status
);
1151 FatFlushDirentForFile (
1152 IN PIRP_CONTEXT IrpContext
,
1158 Routine Description:
1160 This macro flushes the page containing a file's DIRENT in its parent.
1164 Fcb - Supplies the file whose DIRENT is being flushed
1173 LARGE_INTEGER FileOffset
;
1174 IO_STATUS_BLOCK Iosb
;
1178 FileOffset
.QuadPart
= Fcb
->DirentOffsetWithinDirectory
;
1180 CcFlushCache( &Fcb
->ParentDcb
->NonPaged
->SectionObjectPointers
,
1185 if (NT_SUCCESS(Iosb
.Status
)) {
1186 Iosb
.Status
= FatHijackIrpAndFlushDevice( IrpContext
,
1187 IrpContext
->OriginatingIrp
,
1188 Fcb
->Vcb
->TargetDeviceObject
);
1191 if (!NT_SUCCESS(Iosb
.Status
)) {
1192 FatNormalizeAndRaiseStatus(IrpContext
, Iosb
.Status
);
1198 // Local support routine
1203 FatFlushCompletionRoutine (
1204 IN PDEVICE_OBJECT DeviceObject
,
1210 NTSTATUS Status
= (NTSTATUS
) (ULONG_PTR
) Contxt
;
1213 // Add the hack-o-ramma to fix formats.
1216 if ( Irp
->PendingReturned
) {
1218 IoMarkIrpPending( Irp
);
1222 // If the Irp got STATUS_INVALID_DEVICE_REQUEST, normalize it
1223 // to STATUS_SUCCESS.
1226 if (Irp
->IoStatus
.Status
== STATUS_INVALID_DEVICE_REQUEST
) {
1228 Irp
->IoStatus
.Status
= Status
;
1231 UNREFERENCED_PARAMETER( DeviceObject
);
1232 UNREFERENCED_PARAMETER( Contxt
);
1234 return STATUS_SUCCESS
;
1238 // Local support routine
1243 FatHijackCompletionRoutine (
1244 IN PDEVICE_OBJECT DeviceObject
,
1251 // Set the event so that our call will wake up.
1254 KeSetEvent( (PKEVENT
)Contxt
, 0, FALSE
);
1256 UNREFERENCED_PARAMETER( DeviceObject
);
1257 UNREFERENCED_PARAMETER( Irp
);
1259 return STATUS_MORE_PROCESSING_REQUIRED
;