2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
10 /* INCLUDES *****************************************************************/
14 /* GLOBALS ***************************************************************/
16 extern PEXT2_GLOBAL Ext2Global
;
20 /* DEFINITIONS *************************************************************/
22 #define EXT2_FLPFLUSH_MAGIC 'FF2E'
24 typedef struct _EXT2_FLPFLUSH_CONTEXT
{
28 PFILE_OBJECT FileObject
;
34 } EXT2_FLPFLUSH_CONTEXT
, *PEXT2_FLPFLUSH_CONTEXT
;
37 Ext2FloppyFlush(IN PVOID Parameter
);
42 IN PVOID DeferredContext
,
43 IN PVOID SystemArgument1
,
44 IN PVOID SystemArgument2
);
48 Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext
);
51 Ext2WriteFile (IN PEXT2_IRP_CONTEXT IrpContext
);
54 Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext
);
57 Ext2DeferWrite(IN PEXT2_IRP_CONTEXT
, PIRP Irp
);
60 /* FUNCTIONS *************************************************************/
63 Ext2FloppyFlush(IN PVOID Parameter
)
65 PEXT2_FLPFLUSH_CONTEXT Context
;
66 PFILE_OBJECT FileObject
;
70 Context
= (PEXT2_FLPFLUSH_CONTEXT
) Parameter
;
71 FileObject
= Context
->FileObject
;
75 DEBUG(DL_FLP
, ("Ext2FloppyFlushing ...\n"));
77 IoSetTopLevelIrp((PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
);
80 ASSERT(Fcb
== (PEXT2_FCB
)FileObject
->FsContext
);
82 ExAcquireSharedStarveExclusive(&Fcb
->PagingIoResource
, TRUE
);
83 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
85 CcFlushCache(&(Fcb
->SectionObject
), NULL
, 0, NULL
);
87 ObDereferenceObject(FileObject
);
91 ExAcquireSharedStarveExclusive(&Vcb
->PagingIoResource
, TRUE
);
92 ExReleaseResourceLite(&Vcb
->PagingIoResource
);
94 CcFlushCache(&(Vcb
->SectionObject
), NULL
, 0, NULL
);
97 IoSetTopLevelIrp(NULL
);
98 Ext2FreePool(Parameter
, EXT2_FLPFLUSH_MAGIC
);
104 IN PVOID DeferredContext
,
105 IN PVOID SystemArgument1
,
106 IN PVOID SystemArgument2
109 PEXT2_FLPFLUSH_CONTEXT Context
;
111 Context
= (PEXT2_FLPFLUSH_CONTEXT
) DeferredContext
;
113 DEBUG(DL_FLP
, ("Ext2FloppyFlushDpc is to be started...\n"));
115 ExQueueWorkItem(&Context
->Item
, CriticalWorkQueue
);
119 Ext2StartFloppyFlushDpc (
122 PFILE_OBJECT FileObject
)
124 LARGE_INTEGER OneSecond
;
125 PEXT2_FLPFLUSH_CONTEXT Context
;
127 ASSERT(IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
));
129 Context
= Ext2AllocatePool(
131 sizeof(EXT2_FLPFLUSH_CONTEXT
),
136 DEBUG(DL_ERR
, ( "Ex2StartFloppy...: failed to allocate Context\n"));
141 KeInitializeTimer(&Context
->Timer
);
143 KeInitializeDpc( &Context
->Dpc
,
147 ExInitializeWorkItem( &Context
->Item
,
153 Context
->FileObject
= FileObject
;
156 ObReferenceObject(FileObject
);
159 OneSecond
.QuadPart
= (LONGLONG
)-1*1000*1000*10;
160 KeSetTimer( &Context
->Timer
,
167 IN PEXT2_IRP_CONTEXT IrpContext
,
169 IN PFILE_OBJECT FileObject
,
170 IN PLARGE_INTEGER Start
,
171 IN PLARGE_INTEGER End
181 ASSERT (End
&& Start
&& End
->QuadPart
> Start
->QuadPart
);
182 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
184 /* skip data zero if we've already tracked unwritten part */
185 if (0 == ( End
->LowPart
& (BLOCK_SIZE
-1)) &&
186 0 == (Start
->LowPart
& (BLOCK_SIZE
-1))) {
188 if (INODE_HAS_EXTENT(Fcb
->Inode
)) {
191 #if !EXT2_PRE_ALLOCATION_SUPPORT
197 /* clear data in range [Start, End) */
198 return CcZeroData(FileObject
, Start
, End
, Ext2CanIWait());
202 Ext2DeferWrite(IN PEXT2_IRP_CONTEXT IrpContext
, PIRP Irp
)
204 ASSERT(IrpContext
->Irp
== Irp
);
206 Ext2QueueRequest(IrpContext
);
211 Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext
)
213 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
217 PEXT2_FCBVCB FcbOrVcb
;
218 PFILE_OBJECT FileObject
;
220 PDEVICE_OBJECT DeviceObject
;
223 PIO_STACK_LOCATION IoStackLocation
;
226 LARGE_INTEGER ByteOffset
;
228 BOOLEAN PagingIo
= FALSE
;
229 BOOLEAN Nocache
= FALSE
;
230 BOOLEAN SynchronousIo
= FALSE
;
231 BOOLEAN MainResourceAcquired
= FALSE
;
233 BOOLEAN bDeferred
= FALSE
;
235 PUCHAR Buffer
= NULL
;
236 PEXT2_EXTENT Chain
= NULL
;
237 EXT2_EXTENT BlockArray
;
242 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
243 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
245 DeviceObject
= IrpContext
->DeviceObject
;
246 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
248 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
249 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
251 FileObject
= IrpContext
->FileObject
;
252 FcbOrVcb
= (PEXT2_FCBVCB
) FileObject
->FsContext
;
255 if (!(FcbOrVcb
->Identifier
.Type
== EXT2VCB
&& (PVOID
)FcbOrVcb
== (PVOID
)Vcb
)) {
256 Status
= STATUS_INVALID_DEVICE_REQUEST
;
260 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
261 Irp
= IrpContext
->Irp
;
262 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
264 Length
= IoStackLocation
->Parameters
.Write
.Length
;
265 ByteOffset
= IoStackLocation
->Parameters
.Write
.ByteOffset
;
267 PagingIo
= IsFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
268 Nocache
= IsFlagOn(Irp
->Flags
, IRP_NOCACHE
) || (Ccb
!= NULL
);
269 SynchronousIo
= IsFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
275 DEBUG(DL_INF
, ("Ext2WriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
276 ByteOffset
.QuadPart
, Length
, PagingIo
, Nocache
));
279 Irp
->IoStatus
.Information
= 0;
280 Status
= STATUS_SUCCESS
;
285 (ByteOffset
.LowPart
& (SECTOR_SIZE
- 1) ||
286 Length
& (SECTOR_SIZE
- 1))) {
287 Status
= STATUS_INVALID_PARAMETER
;
291 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_DPC
)) {
292 ClearFlag(IrpContext
->MinorFunction
, IRP_MN_DPC
);
293 Status
= STATUS_PENDING
;
297 if (ByteOffset
.QuadPart
>=
298 Vcb
->PartitionInformation
.PartitionLength
.QuadPart
) {
299 Irp
->IoStatus
.Information
= 0;
300 Status
= STATUS_END_OF_FILE
;
306 BOOLEAN bAgain
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
307 BOOLEAN bWait
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
308 BOOLEAN bQueue
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_REQUEUED
);
316 Status
= Ext2LockUserBuffer(
320 if (NT_SUCCESS(Status
)) {
321 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
322 CcDeferWrite( FileObject
,
323 (PCC_POST_DEFERRED_WRITE
)Ext2DeferWrite
,
330 Status
= STATUS_PENDING
;
338 * User direct volume access
341 if (Ccb
!= NULL
&& !PagingIo
) {
343 if (!FlagOn(Ccb
->Flags
, CCB_VOLUME_DASD_PURGE
)) {
345 if (!FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
346 Status
= Ext2PurgeVolume( Vcb
, TRUE
);
349 SetFlag(Ccb
->Flags
, CCB_VOLUME_DASD_PURGE
);
352 if (!IsFlagOn(Ccb
->Flags
, CCB_ALLOW_EXTENDED_DASD_IO
)) {
353 if (ByteOffset
.QuadPart
+ Length
> Vcb
->Header
.FileSize
.QuadPart
) {
354 Length
= (ULONG
)(Vcb
->Header
.FileSize
.QuadPart
- ByteOffset
.QuadPart
);
358 } else if (Nocache
&& !PagingIo
&& (Vcb
->SectionObject
.DataSectionObject
!= NULL
)) {
360 ExAcquireResourceExclusiveLite(&Vcb
->MainResource
, TRUE
);
361 MainResourceAcquired
= TRUE
;
363 ExAcquireSharedStarveExclusive(&Vcb
->PagingIoResource
, TRUE
);
364 ExReleaseResourceLite(&Vcb
->PagingIoResource
);
366 CcFlushCache( &(Vcb
->SectionObject
),
371 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
372 Status
= Irp
->IoStatus
.Status
;
376 ExAcquireSharedStarveExclusive(&Vcb
->PagingIoResource
, TRUE
);
377 ExReleaseResourceLite(&Vcb
->PagingIoResource
);
379 CcPurgeCacheSection( &(Vcb
->SectionObject
),
380 (PLARGE_INTEGER
)&(ByteOffset
),
384 ExReleaseResourceLite(&Vcb
->MainResource
);
385 MainResourceAcquired
= FALSE
;
388 if ( (ByteOffset
.QuadPart
+ Length
) > Vcb
->Header
.FileSize
.QuadPart
) {
389 Length
= (ULONG
)(Vcb
->Header
.FileSize
.QuadPart
- ByteOffset
.QuadPart
);
394 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
403 Status
= Irp
->IoStatus
.Status
;
407 Buffer
= Ext2GetUserBuffer(Irp
);
408 if (Buffer
== NULL
) {
411 Status
= STATUS_INVALID_USER_BUFFER
;
415 if (!CcCopyWrite( Vcb
->Volume
,
416 (PLARGE_INTEGER
)(&ByteOffset
),
420 Status
= STATUS_PENDING
;
424 Status
= Irp
->IoStatus
.Status
;
425 Ext2AddVcbExtent(Vcb
, ByteOffset
.QuadPart
, (LONGLONG
)Length
);
428 if (NT_SUCCESS(Status
)) {
429 Irp
->IoStatus
.Information
= Length
;
432 } else if (PagingIo
) {
436 LONGLONG DirtyLength
;
437 LONGLONG RemainLength
;
439 PEXT2_EXTENT Extent
= NULL
;
440 PEXT2_EXTENT List
= NULL
;
442 Length
&= ~((ULONG
)SECTOR_SIZE
- 1);
444 Status
= Ext2LockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
445 if (!NT_SUCCESS(Status
)) {
449 DirtyLba
= ByteOffset
.QuadPart
;
450 RemainLength
= (LONGLONG
) Length
;
452 ASSERT(Length
>= SECTOR_SIZE
);
454 while (RemainLength
> 0) {
456 DirtyStart
= DirtyLba
;
457 ASSERT(DirtyStart
>= ByteOffset
.QuadPart
);
458 ASSERT(DirtyStart
<= ByteOffset
.QuadPart
+ Length
);
460 if (Ext2LookupVcbExtent(Vcb
, DirtyStart
, &DirtyLba
, &DirtyLength
)) {
462 if (DirtyLba
== -1) {
464 DirtyLba
= DirtyStart
+ DirtyLength
;
465 if (ByteOffset
.QuadPart
+ Length
> DirtyLba
) {
466 RemainLength
= ByteOffset
.QuadPart
+ Length
- DirtyLba
;
467 ASSERT(DirtyStart
>= ByteOffset
.QuadPart
);
468 ASSERT(DirtyStart
<= ByteOffset
.QuadPart
+ Length
);
475 ASSERT(DirtyLba
<= DirtyStart
);
476 Extent
= Ext2AllocateExtent();
479 DEBUG(DL_ERR
, ( "Ex2WriteVolume: failed to allocate Extent\n"));
480 Status
= STATUS_INSUFFICIENT_RESOURCES
;
485 Extent
->Lba
= DirtyLba
;
486 Extent
->Offset
= (ULONG
)( DirtyStart
+ Length
-
487 RemainLength
- DirtyLba
);
488 ASSERT(Extent
->Offset
<= Length
);
490 if (DirtyLba
+ DirtyLength
>= DirtyStart
+ RemainLength
) {
491 Extent
->Length
= (ULONG
)( DirtyLba
+
494 ASSERT(Extent
->Length
<= Length
);
497 Extent
->Length
= (ULONG
)(DirtyLength
+ DirtyLba
- DirtyStart
);
498 RemainLength
= (DirtyStart
+ RemainLength
) -
499 (DirtyLba
+ DirtyLength
);
500 ASSERT(RemainLength
<= (LONGLONG
)Length
);
501 ASSERT(Extent
->Length
<= Length
);
504 ASSERT(Extent
->Length
>= SECTOR_SIZE
);
505 DirtyLba
= DirtyStart
+ DirtyLength
;
511 Chain
= List
= Extent
;
516 if (RemainLength
> SECTOR_SIZE
) {
517 DirtyLba
= DirtyStart
+ SECTOR_SIZE
;
518 RemainLength
-= SECTOR_SIZE
;
526 Status
= Ext2ReadWriteBlocks(IrpContext
,
530 Irp
= IrpContext
->Irp
;
532 if (NT_SUCCESS(Status
)) {
533 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
534 Ext2RemoveVcbExtent(Vcb
, Extent
->Lba
, Extent
->Length
);
544 Irp
->IoStatus
.Information
= Length
;
545 Status
= STATUS_SUCCESS
;
551 Length
&= ~((ULONG
)SECTOR_SIZE
- 1);
553 Status
= Ext2LockUserBuffer(
558 if (!NT_SUCCESS(Status
)) {
562 BlockArray
.Irp
= NULL
;
563 BlockArray
.Lba
= ByteOffset
.QuadPart
;
564 BlockArray
.Offset
= 0;
565 BlockArray
.Length
= Length
;
566 BlockArray
.Next
= NULL
;
568 Status
= Ext2ReadWriteBlocks(IrpContext
,
573 if (NT_SUCCESS(Status
)) {
574 Irp
->IoStatus
.Information
= Length
;
577 Irp
= IrpContext
->Irp
;
585 if (MainResourceAcquired
) {
586 ExReleaseResourceLite(&Vcb
->MainResource
);
589 if (!IrpContext
->ExceptionInProgress
) {
593 if (Status
== STATUS_PENDING
) {
596 Status
= Ext2LockUserBuffer(
601 if (NT_SUCCESS(Status
)) {
602 Status
= Ext2QueueRequest(IrpContext
);
604 Ext2CompleteIrpContext(IrpContext
, Status
);
610 if (NT_SUCCESS(Status
)) {
612 if (SynchronousIo
&& !PagingIo
) {
613 FileObject
->CurrentByteOffset
.QuadPart
=
614 ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
618 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
622 Ext2CompleteIrpContext(IrpContext
, Status
);
627 Ext2FreeIrpContext(IrpContext
);
632 Ext2DestroyExtentChain(Chain
);
641 IN PEXT2_IRP_CONTEXT IrpContext
,
647 IN BOOLEAN bDirectIo
,
648 OUT PULONG BytesWritten
651 PEXT2_EXTENT Chain
= NULL
;
652 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
660 Status
= Ext2BuildExtents (
666 IsMcbDirectory(Mcb
) ? FALSE
: TRUE
,
670 if (!NT_SUCCESS(Status
)) {
675 Status
= STATUS_SUCCESS
;
681 ASSERT(IrpContext
!= NULL
);
684 // We assume the offset is aligned.
687 Status
= Ext2ReadWriteBlocks(
697 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
699 if ( !Ext2SaveBuffer(
704 (PVOID
)((PUCHAR
)Buffer
+ Extent
->Offset
)
710 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
712 DEBUG(DL_FLP
, ("Ext2WriteInode is starting FlushingDpc...\n"));
713 Ext2StartFloppyFlushDpc(Vcb
, NULL
, NULL
);
716 Status
= STATUS_SUCCESS
;
722 Ext2DestroyExtentChain(Chain
);
725 if (NT_SUCCESS(Status
) && BytesWritten
) {
726 *BytesWritten
= Size
;
734 Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext
)
739 PFILE_OBJECT FileObject
;
741 PDEVICE_OBJECT DeviceObject
;
744 PIO_STACK_LOCATION IoStackLocation
;
747 LARGE_INTEGER ByteOffset
;
748 ULONG ReturnedLength
= 0;
751 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
753 BOOLEAN OpPostIrp
= FALSE
;
754 BOOLEAN PagingIo
= FALSE
;
755 BOOLEAN Nocache
= FALSE
;
756 BOOLEAN SynchronousIo
= FALSE
;
758 BOOLEAN RecursiveWriteThrough
= FALSE
;
759 BOOLEAN MainResourceAcquired
= FALSE
;
760 BOOLEAN PagingIoResourceAcquired
= FALSE
;
762 BOOLEAN bDeferred
= FALSE
;
764 BOOLEAN UpdateFileValidSize
= FALSE
;
766 BOOLEAN FileSizesChanged
= FALSE
;
773 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
774 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
776 DeviceObject
= IrpContext
->DeviceObject
;
777 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
779 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
780 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
782 FileObject
= IrpContext
->FileObject
;
783 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
784 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
786 ASSERT((Fcb
->Identifier
.Type
== EXT2FCB
) &&
787 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)));
789 Irp
= IrpContext
->Irp
;
790 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
792 Length
= IoStackLocation
->Parameters
.Write
.Length
;
793 ByteOffset
= IoStackLocation
->Parameters
.Write
.ByteOffset
;
795 PagingIo
= IsFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
796 Nocache
= IsFlagOn(Irp
->Flags
, IRP_NOCACHE
);
797 SynchronousIo
= IsFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
803 DEBUG(DL_INF
, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
804 &Fcb
->Mcb
->ShortName
, ByteOffset
.QuadPart
, Length
, PagingIo
, Nocache
));
806 if (IsSpecialFile(Fcb
)) {
807 Status
= STATUS_INVALID_DEVICE_REQUEST
;
811 if (IsFileDeleted(Fcb
->Mcb
) ||
812 (IsSymLink(Fcb
) && IsFileDeleted(Fcb
->Mcb
->Target
)) ) {
813 Status
= STATUS_FILE_DELETED
;
818 Irp
->IoStatus
.Information
= 0;
819 Status
= STATUS_SUCCESS
;
823 if (Nocache
&& ( (ByteOffset
.LowPart
& (SECTOR_SIZE
- 1)) ||
824 (Length
& (SECTOR_SIZE
- 1))) ) {
825 Status
= STATUS_INVALID_PARAMETER
;
829 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_DPC
)) {
830 ClearFlag(IrpContext
->MinorFunction
, IRP_MN_DPC
);
831 Status
= STATUS_PENDING
;
837 BOOLEAN bAgain
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
838 BOOLEAN bWait
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
839 BOOLEAN bQueue
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_REQUEUED
);
847 Status
= Ext2LockUserBuffer(
852 if (NT_SUCCESS(Status
)) {
853 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
854 CcDeferWrite( FileObject
,
855 (PCC_POST_DEFERRED_WRITE
)Ext2DeferWrite
,
861 Status
= STATUS_PENDING
;
867 if (IsWritingToEof(ByteOffset
)) {
868 ByteOffset
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
871 if (IsDirectory(Fcb
) && !PagingIo
) {
872 Status
= STATUS_INVALID_DEVICE_REQUEST
;
876 if (IsFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) && !IrpContext
->IsTopLevel
) {
880 TopIrp
= IoGetTopLevelIrp();
882 if ( (ULONG_PTR
)TopIrp
> FSRTL_MAX_TOP_LEVEL_IRP_FLAG
&&
883 NodeType(TopIrp
) == IO_TYPE_IRP
) {
885 PIO_STACK_LOCATION IrpStack
;
887 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
889 if ((IrpStack
->MajorFunction
== IRP_MJ_WRITE
) &&
890 (IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
) &&
891 !FlagOn(TopIrp
->Flags
, IRP_NOCACHE
) ) {
893 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
894 RecursiveWriteThrough
= TRUE
;
901 if (!ExAcquireResourceSharedLite(&Fcb
->PagingIoResource
, TRUE
)) {
902 Status
= STATUS_PENDING
;
905 PagingIoResourceAcquired
= TRUE
;
907 if ( (ByteOffset
.QuadPart
+ Length
) > Fcb
->Header
.AllocationSize
.QuadPart
) {
909 if ( ByteOffset
.QuadPart
>= Fcb
->Header
.AllocationSize
.QuadPart
) {
911 Status
= STATUS_END_OF_FILE
;
912 Irp
->IoStatus
.Information
= 0;
917 Length
= (ULONG
)(Fcb
->Header
.AllocationSize
.QuadPart
- ByteOffset
.QuadPart
);
923 if (IsDirectory(Fcb
)) {
927 if (!ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
)) {
928 Status
= STATUS_PENDING
;
931 MainResourceAcquired
= TRUE
;
934 // Do flushing for such cases
936 if (Nocache
&& Ccb
!= NULL
&& Fcb
->SectionObject
.DataSectionObject
!= NULL
) {
938 ExAcquireSharedStarveExclusive( &Fcb
->PagingIoResource
, TRUE
);
939 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
941 CcFlushCache( &(Fcb
->SectionObject
),
943 CEILING_ALIGNED(ULONG
, Length
, BLOCK_SIZE
),
945 ClearLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
947 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
948 Status
= Irp
->IoStatus
.Status
;
952 ExAcquireSharedStarveExclusive( &Fcb
->PagingIoResource
, TRUE
);
953 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
955 CcPurgeCacheSection( &(Fcb
->SectionObject
),
957 CEILING_ALIGNED(ULONG
, Length
, BLOCK_SIZE
),
961 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLockAnchor
, Irp
)) {
962 Status
= STATUS_FILE_LOCK_CONFLICT
;
967 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
973 if (Status
!= STATUS_SUCCESS
) {
979 // Set the flag indicating if Fast I/O is possible
982 Fcb
->Header
.IsFastIoPossible
= Ext2IsFastIoPossible(Fcb
);
986 // Extend the inode size when the i/o is beyond the file end ?
989 if ((ByteOffset
.QuadPart
+ Length
) > Fcb
->Header
.FileSize
.QuadPart
) {
991 LARGE_INTEGER AllocationSize
, Last
;
993 if (!ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, TRUE
)) {
994 Status
= STATUS_PENDING
;
997 PagingIoResourceAcquired
= TRUE
;
999 /* let this irp wait, since it has to be synchronous */
1000 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1002 Last
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
1003 AllocationSize
.QuadPart
= (LONGLONG
)(ByteOffset
.QuadPart
+ Length
);
1004 AllocationSize
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
1005 (ULONGLONG
)AllocationSize
.QuadPart
,
1006 (ULONGLONG
)BLOCK_SIZE
);
1008 /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks
1009 for indirect files, otherwise we might get gabage data in holes */
1010 IrpContext
->MajorFunction
+= IRP_MJ_MAXIMUM_FUNCTION
;
1011 Status
= Ext2ExpandFile(IrpContext
, Vcb
, Fcb
->Mcb
, &AllocationSize
);
1012 IrpContext
->MajorFunction
-= IRP_MJ_MAXIMUM_FUNCTION
;
1013 if (AllocationSize
.QuadPart
> Last
.QuadPart
) {
1014 Fcb
->Header
.AllocationSize
.QuadPart
= AllocationSize
.QuadPart
;
1015 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_WRITE
);
1017 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1018 PagingIoResourceAcquired
= FALSE
;
1020 if (ByteOffset
.QuadPart
>= Fcb
->Header
.AllocationSize
.QuadPart
) {
1021 if (NT_SUCCESS(Status
)) {
1023 Status
= STATUS_UNSUCCESSFUL
;
1028 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.AllocationSize
.QuadPart
) {
1029 Length
= (ULONG
)(Fcb
->Header
.AllocationSize
.QuadPart
- ByteOffset
.QuadPart
);
1032 Fcb
->Header
.FileSize
.QuadPart
= Fcb
->Inode
->i_size
= ByteOffset
.QuadPart
+ Length
;
1033 Ext2SaveInode(IrpContext
, Vcb
, Fcb
->Inode
);
1035 if (CcIsFileCached(FileObject
)) {
1036 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
1039 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
| FO_FILE_MODIFIED
;
1040 FileSizesChanged
= TRUE
;
1042 if (Fcb
->Header
.FileSize
.QuadPart
>= 0x80000000 &&
1043 !IsFlagOn(SUPER_BLOCK
->s_feature_ro_compat
, EXT2_FEATURE_RO_COMPAT_LARGE_FILE
)) {
1044 SetFlag(SUPER_BLOCK
->s_feature_ro_compat
, EXT2_FEATURE_RO_COMPAT_LARGE_FILE
);
1045 Ext2SaveSuper(IrpContext
, Vcb
);
1048 DEBUG(DL_IO
, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n",
1049 &Fcb
->Mcb
->ShortName
, Fcb
->Header
.FileSize
.QuadPart
,
1050 Fcb
->Header
.AllocationSize
.QuadPart
));
1054 ReturnedLength
= Length
;
1058 if (FileObject
->PrivateCacheMap
== NULL
) {
1059 CcInitializeCacheMap(
1061 (PCC_FILE_SIZES
)(&Fcb
->Header
.AllocationSize
),
1063 &Ext2Global
->CacheManagerCallbacks
,
1066 CcSetReadAheadGranularity(
1068 READ_AHEAD_GRANULARITY
);
1071 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
1080 Status
= Irp
->IoStatus
.Status
;
1084 Buffer
= Ext2GetUserBuffer(Irp
);
1085 if (Buffer
== NULL
) {
1087 Status
= STATUS_INVALID_USER_BUFFER
;
1091 if (ByteOffset
.QuadPart
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1093 /* let this irp wait, since it has to be synchronous */
1094 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1096 rc
= Ext2ZeroData(IrpContext
, Vcb
, FileObject
,
1097 &Fcb
->Header
.ValidDataLength
, &ByteOffset
);
1099 Status
= STATUS_PENDING
;
1105 if (!CcCopyWrite(FileObject
, &ByteOffset
, Length
, Ext2CanIWait(), Buffer
)) {
1106 if (Ext2CanIWait() ||
1107 !CcCopyWrite(FileObject
, &ByteOffset
, Length
, TRUE
, Buffer
)) {
1108 Status
= STATUS_PENDING
;
1114 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1116 if (Fcb
->Header
.FileSize
.QuadPart
< ByteOffset
.QuadPart
+ Length
) {
1117 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1119 if (Fcb
->Header
.ValidDataLength
.QuadPart
< ByteOffset
.QuadPart
+ Length
)
1120 Fcb
->Header
.ValidDataLength
.QuadPart
= ByteOffset
.QuadPart
+ Length
;
1123 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
1124 FileSizesChanged
= TRUE
;
1127 Status
= STATUS_SUCCESS
;
1130 if (NT_SUCCESS(Status
)) {
1131 Irp
->IoStatus
.Information
= Length
;
1132 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
1133 DEBUG(DL_FLP
, ("Ext2WriteFile is starting FlushingDpc...\n"));
1134 Ext2StartFloppyFlushDpc(Vcb
, Fcb
, FileObject
);
1140 if (!PagingIo
&& !RecursiveWriteThrough
&& !IsLazyWriter(Fcb
)) {
1141 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1142 if (ByteOffset
.QuadPart
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1144 /* let this irp wait, since it has to be synchronous */
1145 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1146 rc
= Ext2ZeroData(IrpContext
, Vcb
, FileObject
,
1147 &Fcb
->Header
.ValidDataLength
,
1150 Status
= STATUS_PENDING
;
1158 Status
= Ext2LockUserBuffer(
1163 if (!NT_SUCCESS(Status
)) {
1167 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1168 Irp
->IoStatus
.Information
= ReturnedLength
;
1170 Status
= Ext2WriteInode(
1174 (ULONGLONG
)(ByteOffset
.QuadPart
),
1181 Irp
= IrpContext
->Irp
;
1183 if (NT_SUCCESS(Status
) && !PagingIo
&& !RecursiveWriteThrough
&& !IsLazyWriter(Fcb
)) {
1185 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1187 FileSizesChanged
= TRUE
;
1189 if (Fcb
->Header
.FileSize
.QuadPart
< ByteOffset
.QuadPart
+ Length
) {
1190 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1192 if (Fcb
->Header
.ValidDataLength
.QuadPart
< ByteOffset
.QuadPart
+ Length
)
1193 Fcb
->Header
.ValidDataLength
.QuadPart
= ByteOffset
.QuadPart
+ Length
;
1196 if (CcIsFileCached(FileObject
)) {
1197 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
1200 DEBUG(DL_IO
, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n",
1201 &Fcb
->Mcb
->ShortName
, Fcb
->Header
.FileSize
.QuadPart
,
1202 Fcb
->Header
.AllocationSize
.QuadPart
, ByteOffset
.QuadPart
, Length
));
1207 if (FileSizesChanged
) {
1208 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
| FO_FILE_MODIFIED
;
1209 Ext2NotifyReportChange( IrpContext
, Vcb
, Fcb
->Mcb
,
1210 FILE_NOTIFY_CHANGE_SIZE
,
1211 FILE_ACTION_MODIFIED
);
1217 * in case we got excpetions, we need revert MajorFunction
1218 * back to IRP_MJ_WRITE. The reason we do this, if to tell
1219 * Ext2ExpandFile to allocate unwritten extent or don't add
1220 * new blocks for indirect files.
1222 if (IrpContext
->MajorFunction
> IRP_MJ_MAXIMUM_FUNCTION
)
1223 IrpContext
->MajorFunction
-= IRP_MJ_MAXIMUM_FUNCTION
;
1226 if (PagingIoResourceAcquired
) {
1227 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1230 if (MainResourceAcquired
) {
1231 ExReleaseResourceLite(&Fcb
->MainResource
);
1235 if (!OpPostIrp
&& !IrpContext
->ExceptionInProgress
) {
1239 if (Status
== STATUS_PENDING
||
1240 Status
== STATUS_CANT_WAIT
) {
1243 Status
= Ext2QueueRequest(IrpContext
);
1248 if (NT_SUCCESS(Status
) && !PagingIo
) {
1250 if (SynchronousIo
) {
1251 FileObject
->CurrentByteOffset
.QuadPart
=
1252 ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
1255 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
1256 SetLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
1259 Ext2CompleteIrpContext(IrpContext
, Status
);
1262 Ext2FreeIrpContext(IrpContext
);
1267 DEBUG(DL_IO
, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d "
1268 "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n",
1269 &Fcb
->Mcb
->ShortName
, ByteOffset
, Length
, PagingIo
, Nocache
, ReturnedLength
,
1270 Fcb
->Header
.ValidDataLength
.QuadPart
,Fcb
->Header
.FileSize
.QuadPart
,
1271 Fcb
->Inode
->i_size
, Status
));
1277 Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext
)
1279 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1280 PFILE_OBJECT FileObject
;
1282 PIO_STACK_LOCATION IrpSp
;
1287 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
1288 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
1290 FileObject
= IrpContext
->FileObject
;
1292 Irp
= IrpContext
->Irp
;
1293 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1295 CcMdlWriteComplete(FileObject
, &(IrpSp
->Parameters
.Write
.ByteOffset
), Irp
->MdlAddress
);
1296 Irp
->MdlAddress
= NULL
;
1297 Status
= STATUS_SUCCESS
;
1301 if (!IrpContext
->ExceptionInProgress
) {
1302 Ext2CompleteIrpContext(IrpContext
, Status
);
1311 Ext2Write (IN PEXT2_IRP_CONTEXT IrpContext
)
1314 PEXT2_FCBVCB FcbOrVcb
;
1315 PDEVICE_OBJECT DeviceObject
;
1316 PFILE_OBJECT FileObject
;
1318 BOOLEAN bCompleteRequest
= TRUE
;
1322 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
1323 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
1327 if (IsFlagOn(IrpContext
->MinorFunction
, IRP_MN_COMPLETE
)) {
1329 Status
= Ext2WriteComplete(IrpContext
);
1330 bCompleteRequest
= FALSE
;
1334 DeviceObject
= IrpContext
->DeviceObject
;
1335 if (IsExt2FsDevice(DeviceObject
)) {
1336 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1339 FileObject
= IrpContext
->FileObject
;
1341 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
1343 if (Vcb
->Identifier
.Type
!= EXT2VCB
||
1344 Vcb
->Identifier
.Size
!= sizeof(EXT2_VCB
) ) {
1345 Status
= STATUS_INVALID_PARAMETER
;
1349 if (IsVcbReadOnly(Vcb
)) {
1350 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1354 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
) &&
1355 Vcb
->LockFile
!= FileObject
) {
1356 Status
= STATUS_ACCESS_DENIED
;
1360 FcbOrVcb
= (PEXT2_FCBVCB
) FileObject
->FsContext
;
1362 if (FcbOrVcb
->Identifier
.Type
== EXT2VCB
) {
1364 Status
= Ext2WriteVolume(IrpContext
);
1365 if (!NT_SUCCESS(Status
)) {
1368 bCompleteRequest
= FALSE
;
1370 } else if (FcbOrVcb
->Identifier
.Type
== EXT2FCB
) {
1372 if (IsFlagOn(Vcb
->Flags
, VCB_DISMOUNT_PENDING
)) {
1373 Status
= STATUS_TOO_LATE
;
1377 Status
= Ext2WriteFile(IrpContext
);
1378 if (!NT_SUCCESS(Status
)) {
1382 bCompleteRequest
= FALSE
;
1384 Status
= STATUS_INVALID_PARAMETER
;
1390 if (bCompleteRequest
) {
1391 Ext2CompleteIrpContext(IrpContext
, Status
);