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
);
81 ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
);
82 ExAcquireSharedStarveExclusive(&Fcb
->PagingIoResource
, TRUE
);
83 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
85 CcFlushCache(&(Fcb
->SectionObject
), NULL
, 0, NULL
);
86 ExReleaseResourceLite(&Fcb
->MainResource
);
88 ObDereferenceObject(FileObject
);
92 ExAcquireResourceExclusiveLite(&Vcb
->MainResource
, TRUE
);
94 ExAcquireSharedStarveExclusive(&Vcb
->PagingIoResource
, TRUE
);
95 ExReleaseResourceLite(&Vcb
->PagingIoResource
);
98 ExReleaseResourceLite(&Vcb
->MainResource
);
101 IoSetTopLevelIrp(NULL
);
102 Ext2FreePool(Parameter
, EXT2_FLPFLUSH_MAGIC
);
108 IN PVOID DeferredContext
,
109 IN PVOID SystemArgument1
,
110 IN PVOID SystemArgument2
113 PEXT2_FLPFLUSH_CONTEXT Context
;
115 Context
= (PEXT2_FLPFLUSH_CONTEXT
) DeferredContext
;
117 DEBUG(DL_FLP
, ("Ext2FloppyFlushDpc is to be started...\n"));
119 ExQueueWorkItem(&Context
->Item
, CriticalWorkQueue
);
123 Ext2StartFloppyFlushDpc (
126 PFILE_OBJECT FileObject
)
128 LARGE_INTEGER OneSecond
;
129 PEXT2_FLPFLUSH_CONTEXT Context
;
131 ASSERT(IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
));
133 Context
= Ext2AllocatePool(
135 sizeof(EXT2_FLPFLUSH_CONTEXT
),
140 DEBUG(DL_ERR
, ( "Ex2StartFloppy...: failed to allocate Context\n"));
145 KeInitializeTimer(&Context
->Timer
);
147 KeInitializeDpc( &Context
->Dpc
,
151 ExInitializeWorkItem( &Context
->Item
,
157 Context
->FileObject
= FileObject
;
160 ObReferenceObject(FileObject
);
163 OneSecond
.QuadPart
= (LONGLONG
)-1*1000*1000*10;
164 KeSetTimer( &Context
->Timer
,
171 IN PEXT2_IRP_CONTEXT IrpContext
,
173 IN PFILE_OBJECT FileObject
,
174 IN PLARGE_INTEGER Start
,
175 IN PLARGE_INTEGER End
184 ASSERT (End
&& Start
&& End
->QuadPart
> Start
->QuadPart
);
185 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
187 /* skip data zero if we've already tracked unwritten part */
188 if (0 == ( End
->LowPart
& (BLOCK_SIZE
-1)) &&
189 0 == (Start
->LowPart
& (BLOCK_SIZE
-1))) {
191 if (INODE_HAS_EXTENT(Fcb
->Inode
)) {
194 #if !EXT2_PRE_ALLOCATION_SUPPORT
200 /* clear data in range [Start, End) */
202 rc
= CcZeroData(FileObject
, Start
, End
, Ext2CanIWait());
203 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
211 Ext2DeferWrite(IN PEXT2_IRP_CONTEXT IrpContext
, PIRP Irp
)
213 ASSERT(IrpContext
->Irp
== Irp
);
215 Ext2QueueRequest(IrpContext
);
220 Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext
)
222 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
224 PEXT2_VCB Vcb
= NULL
;
225 PEXT2_CCB Ccb
= NULL
;
226 PEXT2_FCBVCB FcbOrVcb
= NULL
;
227 PFILE_OBJECT FileObject
= NULL
;
229 PDEVICE_OBJECT DeviceObject
= NULL
;
232 PIO_STACK_LOCATION IoStackLocation
= NULL
;
235 LARGE_INTEGER ByteOffset
;
237 BOOLEAN PagingIo
= FALSE
;
238 BOOLEAN Nocache
= FALSE
;
239 BOOLEAN SynchronousIo
= FALSE
;
240 BOOLEAN MainResourceAcquired
= FALSE
;
242 BOOLEAN bDeferred
= FALSE
;
244 PUCHAR Buffer
= NULL
;
245 PEXT2_EXTENT Chain
= NULL
;
246 EXT2_EXTENT BlockArray
;
251 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
252 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
254 DeviceObject
= IrpContext
->DeviceObject
;
255 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
257 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
258 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
260 FileObject
= IrpContext
->FileObject
;
261 FcbOrVcb
= (PEXT2_FCBVCB
) FileObject
->FsContext
;
264 if (!(FcbOrVcb
->Identifier
.Type
== EXT2VCB
&& (PVOID
)FcbOrVcb
== (PVOID
)Vcb
)) {
265 Status
= STATUS_INVALID_DEVICE_REQUEST
;
269 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
270 Irp
= IrpContext
->Irp
;
271 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
273 Length
= IoStackLocation
->Parameters
.Write
.Length
;
274 ByteOffset
= IoStackLocation
->Parameters
.Write
.ByteOffset
;
276 PagingIo
= IsFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
277 Nocache
= IsFlagOn(Irp
->Flags
, IRP_NOCACHE
) || (Ccb
!= NULL
);
278 SynchronousIo
= IsFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
284 DEBUG(DL_INF
, ("Ext2WriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
285 ByteOffset
.QuadPart
, Length
, PagingIo
, Nocache
));
288 Irp
->IoStatus
.Information
= 0;
289 Status
= STATUS_SUCCESS
;
294 (ByteOffset
.LowPart
& (SECTOR_SIZE
- 1) ||
295 Length
& (SECTOR_SIZE
- 1))) {
296 Status
= STATUS_INVALID_PARAMETER
;
300 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_DPC
)) {
301 ClearFlag(IrpContext
->MinorFunction
, IRP_MN_DPC
);
302 Status
= STATUS_PENDING
;
306 if (ByteOffset
.QuadPart
>=
307 Vcb
->PartitionInformation
.PartitionLength
.QuadPart
) {
308 Irp
->IoStatus
.Information
= 0;
309 Status
= STATUS_END_OF_FILE
;
315 BOOLEAN bAgain
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
316 BOOLEAN bWait
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
317 BOOLEAN bQueue
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_REQUEUED
);
325 Status
= Ext2LockUserBuffer(
329 if (NT_SUCCESS(Status
)) {
330 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
331 CcDeferWrite( FileObject
,
332 (PCC_POST_DEFERRED_WRITE
)Ext2DeferWrite
,
339 Status
= STATUS_PENDING
;
347 * User direct volume access
350 if (Ccb
!= NULL
&& !PagingIo
) {
352 if (!FlagOn(Ccb
->Flags
, CCB_VOLUME_DASD_PURGE
)) {
354 if (!FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
355 Status
= Ext2PurgeVolume( Vcb
, TRUE
);
358 SetFlag(Ccb
->Flags
, CCB_VOLUME_DASD_PURGE
);
361 if (!IsFlagOn(Ccb
->Flags
, CCB_ALLOW_EXTENDED_DASD_IO
)) {
362 if (ByteOffset
.QuadPart
+ Length
> Vcb
->Header
.FileSize
.QuadPart
) {
363 Length
= (ULONG
)(Vcb
->Header
.FileSize
.QuadPart
- ByteOffset
.QuadPart
);
367 } else if (Nocache
&& !PagingIo
&& (Vcb
->SectionObject
.DataSectionObject
!= NULL
)) {
369 ExAcquireResourceExclusiveLite(&Vcb
->MainResource
, TRUE
);
370 MainResourceAcquired
= TRUE
;
372 ExAcquireSharedStarveExclusive(&Vcb
->PagingIoResource
, TRUE
);
373 ExReleaseResourceLite(&Vcb
->PagingIoResource
);
375 CcFlushCache( &(Vcb
->SectionObject
),
380 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
381 Status
= Irp
->IoStatus
.Status
;
385 ExAcquireSharedStarveExclusive(&Vcb
->PagingIoResource
, TRUE
);
386 ExReleaseResourceLite(&Vcb
->PagingIoResource
);
388 CcPurgeCacheSection( &(Vcb
->SectionObject
),
389 (PLARGE_INTEGER
)&(ByteOffset
),
393 ExReleaseResourceLite(&Vcb
->MainResource
);
394 MainResourceAcquired
= FALSE
;
397 if ( (ByteOffset
.QuadPart
+ Length
) > Vcb
->Header
.FileSize
.QuadPart
) {
398 Length
= (ULONG
)(Vcb
->Header
.FileSize
.QuadPart
- ByteOffset
.QuadPart
);
403 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
412 Status
= Irp
->IoStatus
.Status
;
416 Buffer
= Ext2GetUserBuffer(Irp
);
417 if (Buffer
== NULL
) {
420 Status
= STATUS_INVALID_USER_BUFFER
;
424 if (!CcCopyWrite( Vcb
->Volume
,
425 (PLARGE_INTEGER
)(&ByteOffset
),
429 Status
= STATUS_PENDING
;
433 Status
= Irp
->IoStatus
.Status
;
434 Ext2AddVcbExtent(Vcb
, ByteOffset
.QuadPart
, (LONGLONG
)Length
);
437 if (NT_SUCCESS(Status
)) {
438 Irp
->IoStatus
.Information
= Length
;
441 } else if (PagingIo
) {
445 LONGLONG DirtyLength
;
446 LONGLONG RemainLength
;
448 PEXT2_EXTENT Extent
= NULL
;
449 PEXT2_EXTENT List
= NULL
;
451 Length
&= ~((ULONG
)SECTOR_SIZE
- 1);
453 Status
= Ext2LockUserBuffer(IrpContext
->Irp
, Length
, IoReadAccess
);
454 if (!NT_SUCCESS(Status
)) {
458 DirtyLba
= ByteOffset
.QuadPart
;
459 RemainLength
= (LONGLONG
) Length
;
461 ASSERT(Length
>= SECTOR_SIZE
);
463 while (RemainLength
> 0) {
465 DirtyStart
= DirtyLba
;
466 ASSERT(DirtyStart
>= ByteOffset
.QuadPart
);
467 ASSERT(DirtyStart
<= ByteOffset
.QuadPart
+ Length
);
469 if (Ext2LookupVcbExtent(Vcb
, DirtyStart
, &DirtyLba
, &DirtyLength
)) {
471 if (DirtyLba
== -1) {
473 DirtyLba
= DirtyStart
+ DirtyLength
;
474 if (ByteOffset
.QuadPart
+ Length
> DirtyLba
) {
475 RemainLength
= ByteOffset
.QuadPart
+ Length
- DirtyLba
;
476 ASSERT(DirtyStart
>= ByteOffset
.QuadPart
);
477 ASSERT(DirtyStart
<= ByteOffset
.QuadPart
+ Length
);
484 ASSERT(DirtyLba
<= DirtyStart
);
485 Extent
= Ext2AllocateExtent();
488 DEBUG(DL_ERR
, ( "Ex2WriteVolume: failed to allocate Extent\n"));
489 Status
= STATUS_INSUFFICIENT_RESOURCES
;
494 Extent
->Lba
= DirtyStart
;
495 Extent
->Offset
= (ULONG
)( DirtyStart
+ Length
-
496 RemainLength
- DirtyLba
);
497 ASSERT(Extent
->Offset
<= Length
);
499 if (DirtyLba
+ DirtyLength
>= DirtyStart
+ RemainLength
) {
500 Extent
->Length
= (ULONG
)( DirtyLba
+
503 ASSERT(Extent
->Length
<= Length
);
506 Extent
->Length
= (ULONG
)(DirtyLength
+ DirtyLba
- DirtyStart
);
507 RemainLength
= RemainLength
- Extent
->Length
;
509 RemainLength = (DirtyStart + RemainLength) -
510 (DirtyLba + DirtyLength);
512 ASSERT(RemainLength
<= (LONGLONG
)Length
);
513 ASSERT(Extent
->Length
<= Length
);
516 ASSERT(Extent
->Length
>= SECTOR_SIZE
);
517 DirtyLba
= DirtyStart
+ Extent
->Length
;
523 Chain
= List
= Extent
;
528 if (RemainLength
> SECTOR_SIZE
) {
529 DirtyLba
= DirtyStart
+ SECTOR_SIZE
;
530 RemainLength
-= SECTOR_SIZE
;
538 Status
= Ext2ReadWriteBlocks(IrpContext
,
542 Irp
= IrpContext
->Irp
;
544 if (NT_SUCCESS(Status
)) {
545 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
546 Ext2RemoveVcbExtent(Vcb
, Extent
->Lba
, Extent
->Length
);
556 Irp
->IoStatus
.Information
= Length
;
557 Status
= STATUS_SUCCESS
;
563 Length
&= ~((ULONG
)SECTOR_SIZE
- 1);
565 Status
= Ext2LockUserBuffer(
570 if (!NT_SUCCESS(Status
)) {
574 BlockArray
.Irp
= NULL
;
575 BlockArray
.Lba
= ByteOffset
.QuadPart
;
576 BlockArray
.Offset
= 0;
577 BlockArray
.Length
= Length
;
578 BlockArray
.Next
= NULL
;
580 Status
= Ext2ReadWriteBlocks(IrpContext
,
585 if (NT_SUCCESS(Status
)) {
586 Irp
->IoStatus
.Information
= Length
;
589 Irp
= IrpContext
->Irp
;
597 if (MainResourceAcquired
) {
598 ExReleaseResourceLite(&Vcb
->MainResource
);
601 if (!IrpContext
->ExceptionInProgress
) {
605 if (Status
== STATUS_PENDING
) {
608 Status
= Ext2LockUserBuffer(
613 if (NT_SUCCESS(Status
)) {
614 Status
= Ext2QueueRequest(IrpContext
);
616 Ext2CompleteIrpContext(IrpContext
, Status
);
622 if (NT_SUCCESS(Status
)) {
624 if (SynchronousIo
&& !PagingIo
) {
625 FileObject
->CurrentByteOffset
.QuadPart
=
626 ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
630 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
634 Ext2CompleteIrpContext(IrpContext
, Status
);
639 Ext2FreeIrpContext(IrpContext
);
644 Ext2DestroyExtentChain(Chain
);
653 IN PEXT2_IRP_CONTEXT IrpContext
,
659 IN BOOLEAN bDirectIo
,
660 OUT PULONG BytesWritten
663 PEXT2_EXTENT Chain
= NULL
;
664 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
672 Status
= Ext2BuildExtents (
678 S_ISDIR(Mcb
->Inode
.i_mode
) ? FALSE
: TRUE
,
682 if (!NT_SUCCESS(Status
)) {
687 Status
= STATUS_SUCCESS
;
693 ASSERT(IrpContext
!= NULL
);
696 // We assume the offset is aligned.
699 Status
= Ext2ReadWriteBlocks(
709 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
711 if ( !Ext2SaveBuffer(
716 (PVOID
)((PUCHAR
)Buffer
+ Extent
->Offset
)
722 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
724 DEBUG(DL_FLP
, ("Ext2WriteInode is starting FlushingDpc...\n"));
725 Ext2StartFloppyFlushDpc(Vcb
, NULL
, NULL
);
728 Status
= STATUS_SUCCESS
;
734 Ext2DestroyExtentChain(Chain
);
737 if (NT_SUCCESS(Status
) && BytesWritten
) {
738 *BytesWritten
= Size
;
747 Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext
)
749 PEXT2_VCB Vcb
= NULL
;
750 PEXT2_FCB Fcb
= NULL
;
751 PEXT2_CCB Ccb
= NULL
;
752 PFILE_OBJECT FileObject
= NULL
;
754 PDEVICE_OBJECT DeviceObject
= NULL
;
757 PIO_STACK_LOCATION IoStackLocation
= NULL
;
758 PUCHAR Buffer
= NULL
;
760 LARGE_INTEGER ByteOffset
;
761 ULONG ReturnedLength
= 0;
764 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
766 BOOLEAN OpPostIrp
= FALSE
;
767 BOOLEAN PagingIo
= FALSE
;
768 BOOLEAN Nocache
= FALSE
;
769 BOOLEAN SynchronousIo
= FALSE
;
771 BOOLEAN RecursiveWriteThrough
= FALSE
;
772 BOOLEAN MainResourceAcquired
= FALSE
;
773 BOOLEAN PagingIoResourceAcquired
= FALSE
;
775 BOOLEAN bDeferred
= FALSE
;
777 BOOLEAN UpdateFileValidSize
= FALSE
;
779 BOOLEAN FileSizesChanged
= FALSE
;
786 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
787 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
789 DeviceObject
= IrpContext
->DeviceObject
;
790 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
792 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
793 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
795 FileObject
= IrpContext
->FileObject
;
796 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
797 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
799 ASSERT((Fcb
->Identifier
.Type
== EXT2FCB
) &&
800 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)));
802 Irp
= IrpContext
->Irp
;
803 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
805 Length
= IoStackLocation
->Parameters
.Write
.Length
;
806 ByteOffset
= IoStackLocation
->Parameters
.Write
.ByteOffset
;
808 PagingIo
= IsFlagOn(Irp
->Flags
, IRP_PAGING_IO
);
809 Nocache
= IsFlagOn(Irp
->Flags
, IRP_NOCACHE
);
810 SynchronousIo
= IsFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
816 DEBUG(DL_INF
, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
817 &Fcb
->Mcb
->ShortName
, ByteOffset
.QuadPart
, Length
, PagingIo
, Nocache
));
819 if (IsSpecialFile(Fcb
) || IsInodeSymLink(Fcb
->Inode
) ) {
820 Status
= STATUS_INVALID_DEVICE_REQUEST
;
824 if (IsFileDeleted(Fcb
->Mcb
) ||
825 (IsSymLink(Fcb
) && IsFileDeleted(Fcb
->Mcb
->Target
)) ) {
826 Status
= STATUS_FILE_DELETED
;
831 Irp
->IoStatus
.Information
= 0;
832 Status
= STATUS_SUCCESS
;
836 if (ByteOffset
.LowPart
== FILE_USE_FILE_POINTER_POSITION
&&
837 ByteOffset
.HighPart
== -1) {
838 ByteOffset
= FileObject
->CurrentByteOffset
;
839 } else if (IsWritingToEof(ByteOffset
)) {
840 ByteOffset
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
843 if (Nocache
&& !PagingIo
&&
844 ( (ByteOffset
.LowPart
& (SECTOR_SIZE
- 1)) ||
845 (Length
& (SECTOR_SIZE
- 1))) ) {
846 Status
= STATUS_INVALID_PARAMETER
;
850 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_DPC
)) {
851 ClearFlag(IrpContext
->MinorFunction
, IRP_MN_DPC
);
852 Status
= STATUS_PENDING
;
858 BOOLEAN bAgain
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
859 BOOLEAN bWait
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
860 BOOLEAN bQueue
= IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_REQUEUED
);
868 Status
= Ext2LockUserBuffer(
873 if (NT_SUCCESS(Status
)) {
874 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DEFERRED
);
875 CcDeferWrite( FileObject
,
876 (PCC_POST_DEFERRED_WRITE
)Ext2DeferWrite
,
882 Status
= STATUS_PENDING
;
888 if (IsDirectory(Fcb
) && !PagingIo
) {
889 Status
= STATUS_INVALID_DEVICE_REQUEST
;
893 if (IsFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
) && !IrpContext
->IsTopLevel
) {
897 TopIrp
= IoGetTopLevelIrp();
899 if ( (ULONG_PTR
)TopIrp
> FSRTL_MAX_TOP_LEVEL_IRP_FLAG
&&
900 NodeType(TopIrp
) == IO_TYPE_IRP
) {
902 PIO_STACK_LOCATION IrpStack
;
904 IrpStack
= IoGetCurrentIrpStackLocation(TopIrp
);
906 if ((IrpStack
->MajorFunction
== IRP_MJ_WRITE
) &&
907 (IrpStack
->FileObject
->FsContext
== FileObject
->FsContext
) &&
908 !FlagOn(TopIrp
->Flags
, IRP_NOCACHE
) ) {
910 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
911 RecursiveWriteThrough
= TRUE
;
918 if (!ExAcquireResourceSharedLite(&Fcb
->PagingIoResource
, TRUE
)) {
919 Status
= STATUS_PENDING
;
922 PagingIoResourceAcquired
= TRUE
;
924 if ( (ByteOffset
.QuadPart
+ Length
) > Fcb
->Header
.FileSize
.QuadPart
) {
926 if (ByteOffset
.QuadPart
>= Fcb
->Header
.AllocationSize
.QuadPart
) {
928 Status
= STATUS_SUCCESS
;
929 Irp
->IoStatus
.Information
= 0;
934 ReturnedLength
= (ULONG
)(Fcb
->Header
.FileSize
.QuadPart
- ByteOffset
.QuadPart
);
935 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.AllocationSize
.QuadPart
)
936 Length
= (ULONG
)(Fcb
->Header
.AllocationSize
.QuadPart
- ByteOffset
.QuadPart
);
941 ReturnedLength
= Length
;
946 if (!Ext2CheckFileAccess(Vcb
, Fcb
->Mcb
, Ext2FileCanWrite
)) {
947 Status
= STATUS_ACCESS_DENIED
;
951 if (IsDirectory(Fcb
)) {
955 if (!ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
)) {
956 Status
= STATUS_PENDING
;
959 MainResourceAcquired
= TRUE
;
962 // Do flushing for such cases
964 if (Nocache
&& Ccb
!= NULL
&& Fcb
->SectionObject
.DataSectionObject
!= NULL
) {
966 ExAcquireSharedStarveExclusive( &Fcb
->PagingIoResource
, TRUE
);
967 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
969 CcFlushCache( &(Fcb
->SectionObject
),
971 CEILING_ALIGNED(ULONG
, Length
, BLOCK_SIZE
),
973 ClearLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
975 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
976 Status
= Irp
->IoStatus
.Status
;
980 ExAcquireSharedStarveExclusive( &Fcb
->PagingIoResource
, TRUE
);
981 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
983 CcPurgeCacheSection( &(Fcb
->SectionObject
),
985 CEILING_ALIGNED(ULONG
, Length
, BLOCK_SIZE
),
989 if (!FsRtlCheckLockForWriteAccess(&Fcb
->FileLockAnchor
, Irp
)) {
990 Status
= STATUS_FILE_LOCK_CONFLICT
;
995 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1001 if (Status
!= STATUS_SUCCESS
) {
1007 // Set the flag indicating if Fast I/O is possible
1010 Fcb
->Header
.IsFastIoPossible
= Ext2IsFastIoPossible(Fcb
);
1014 // Extend the inode size when the i/o is beyond the file end ?
1017 if ((ByteOffset
.QuadPart
+ Length
) > Fcb
->Header
.FileSize
.QuadPart
) {
1019 LARGE_INTEGER AllocationSize
, Last
;
1021 if (!ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, TRUE
)) {
1022 Status
= STATUS_PENDING
;
1025 PagingIoResourceAcquired
= TRUE
;
1027 /* let this irp wait, since it has to be synchronous */
1028 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1030 Last
.QuadPart
= Fcb
->Header
.AllocationSize
.QuadPart
;
1031 AllocationSize
.QuadPart
= (LONGLONG
)(ByteOffset
.QuadPart
+ Length
);
1032 AllocationSize
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
1033 (ULONGLONG
)AllocationSize
.QuadPart
,
1034 (ULONGLONG
)BLOCK_SIZE
);
1036 /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks
1037 for indirect files, otherwise we might get gabage data in holes */
1038 IrpContext
->MajorFunction
+= IRP_MJ_MAXIMUM_FUNCTION
;
1039 Status
= Ext2ExpandFile(IrpContext
, Vcb
, Fcb
->Mcb
, &AllocationSize
);
1040 IrpContext
->MajorFunction
-= IRP_MJ_MAXIMUM_FUNCTION
;
1041 if (AllocationSize
.QuadPart
> Last
.QuadPart
) {
1042 Fcb
->Header
.AllocationSize
.QuadPart
= AllocationSize
.QuadPart
;
1043 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_WRITE
);
1045 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1046 PagingIoResourceAcquired
= FALSE
;
1048 if (ByteOffset
.QuadPart
>= Fcb
->Header
.AllocationSize
.QuadPart
) {
1049 if (NT_SUCCESS(Status
)) {
1051 Status
= STATUS_UNSUCCESSFUL
;
1056 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.AllocationSize
.QuadPart
) {
1057 Length
= (ULONG
)(Fcb
->Header
.AllocationSize
.QuadPart
- ByteOffset
.QuadPart
);
1060 Fcb
->Header
.FileSize
.QuadPart
= Fcb
->Inode
->i_size
= ByteOffset
.QuadPart
+ Length
;
1061 Ext2SaveInode(IrpContext
, Vcb
, Fcb
->Inode
);
1063 if (CcIsFileCached(FileObject
)) {
1064 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
1067 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
| FO_FILE_MODIFIED
;
1068 FileSizesChanged
= TRUE
;
1070 if (Fcb
->Header
.FileSize
.QuadPart
>= 0x80000000 &&
1071 !IsFlagOn(SUPER_BLOCK
->s_feature_ro_compat
, EXT2_FEATURE_RO_COMPAT_LARGE_FILE
)) {
1072 SetFlag(SUPER_BLOCK
->s_feature_ro_compat
, EXT2_FEATURE_RO_COMPAT_LARGE_FILE
);
1073 Ext2SaveSuper(IrpContext
, Vcb
);
1076 DEBUG(DL_IO
, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n",
1077 &Fcb
->Mcb
->ShortName
, Fcb
->Header
.FileSize
.QuadPart
,
1078 Fcb
->Header
.AllocationSize
.QuadPart
));
1081 ReturnedLength
= Length
;
1086 if (FileObject
->PrivateCacheMap
== NULL
) {
1087 CcInitializeCacheMap(
1089 (PCC_FILE_SIZES
)(&Fcb
->Header
.AllocationSize
),
1091 &Ext2Global
->CacheManagerCallbacks
,
1094 CcSetReadAheadGranularity(
1096 READ_AHEAD_GRANULARITY
);
1099 if (FlagOn(IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
1108 Status
= Irp
->IoStatus
.Status
;
1112 Buffer
= Ext2GetUserBuffer(Irp
);
1113 if (Buffer
== NULL
) {
1115 Status
= STATUS_INVALID_USER_BUFFER
;
1119 if (ByteOffset
.QuadPart
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1121 /* let this irp wait, since it has to be synchronous */
1122 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1124 rc
= Ext2ZeroData(IrpContext
, Vcb
, FileObject
,
1125 &Fcb
->Header
.ValidDataLength
, &ByteOffset
);
1127 Status
= STATUS_PENDING
;
1133 if (!CcCopyWrite(FileObject
, &ByteOffset
, Length
, Ext2CanIWait(), Buffer
)) {
1134 if (Ext2CanIWait() ||
1135 !CcCopyWrite(FileObject
, &ByteOffset
, Length
, TRUE
, Buffer
)) {
1136 Status
= STATUS_PENDING
;
1142 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1144 if (Fcb
->Header
.FileSize
.QuadPart
< ByteOffset
.QuadPart
+ Length
) {
1145 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1147 if (Fcb
->Header
.ValidDataLength
.QuadPart
< ByteOffset
.QuadPart
+ Length
)
1148 Fcb
->Header
.ValidDataLength
.QuadPart
= ByteOffset
.QuadPart
+ Length
;
1151 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
1152 FileSizesChanged
= TRUE
;
1155 Status
= STATUS_SUCCESS
;
1158 if (NT_SUCCESS(Status
)) {
1159 Irp
->IoStatus
.Information
= Length
;
1160 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
1161 DEBUG(DL_FLP
, ("Ext2WriteFile is starting FlushingDpc...\n"));
1162 Ext2StartFloppyFlushDpc(Vcb
, Fcb
, FileObject
);
1168 if (!PagingIo
&& !RecursiveWriteThrough
&& !IsLazyWriter(Fcb
)) {
1169 if (ByteOffset
.QuadPart
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1171 /* let this irp wait, since it has to be synchronous */
1172 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1173 rc
= Ext2ZeroData(IrpContext
, Vcb
, FileObject
,
1174 &Fcb
->Header
.ValidDataLength
,
1177 Status
= STATUS_PENDING
;
1184 Status
= Ext2LockUserBuffer(
1189 if (!NT_SUCCESS(Status
)) {
1193 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1194 Irp
->IoStatus
.Information
= ReturnedLength
;
1196 Status
= Ext2WriteInode(
1200 (ULONGLONG
)(ByteOffset
.QuadPart
),
1207 Irp
= IrpContext
->Irp
;
1209 if (NT_SUCCESS(Status
) && !RecursiveWriteThrough
&& !IsLazyWriter(Fcb
)) {
1211 if (ByteOffset
.QuadPart
+ Length
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
1213 FileSizesChanged
= TRUE
;
1215 if (Fcb
->Header
.FileSize
.QuadPart
< ByteOffset
.QuadPart
+ Length
) {
1217 Fcb
->Header
.FileSize
.QuadPart
= ByteOffset
.QuadPart
+ Length
;
1218 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1220 if (Fcb
->Header
.ValidDataLength
.QuadPart
< ByteOffset
.QuadPart
+ Length
)
1221 Fcb
->Header
.ValidDataLength
.QuadPart
= ByteOffset
.QuadPart
+ Length
;
1224 if (!PagingIo
&& CcIsFileCached(FileObject
)) {
1225 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
1228 DEBUG(DL_IO
, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n",
1229 &Fcb
->Mcb
->ShortName
, Fcb
->Header
.FileSize
.QuadPart
,
1230 Fcb
->Header
.AllocationSize
.QuadPart
, ByteOffset
.QuadPart
, Length
));
1235 if (FileSizesChanged
) {
1236 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
| FO_FILE_MODIFIED
;
1237 Ext2NotifyReportChange( IrpContext
, Vcb
, Fcb
->Mcb
,
1238 FILE_NOTIFY_CHANGE_SIZE
,
1239 FILE_ACTION_MODIFIED
);
1245 * in case we got excpetions, we need revert MajorFunction
1246 * back to IRP_MJ_WRITE. The reason we do this, is to tell
1247 * Ext2ExpandFile to allocate unwritten extent or don't add
1248 * new blocks for indirect files.
1250 if (IrpContext
->MajorFunction
> IRP_MJ_MAXIMUM_FUNCTION
)
1251 IrpContext
->MajorFunction
-= IRP_MJ_MAXIMUM_FUNCTION
;
1254 if (PagingIoResourceAcquired
) {
1255 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1258 if (MainResourceAcquired
) {
1259 ExReleaseResourceLite(&Fcb
->MainResource
);
1263 if (!OpPostIrp
&& !IrpContext
->ExceptionInProgress
) {
1267 if (Status
== STATUS_PENDING
||
1268 Status
== STATUS_CANT_WAIT
) {
1271 Status
= Ext2QueueRequest(IrpContext
);
1276 if (NT_SUCCESS(Status
) && !PagingIo
) {
1278 if (SynchronousIo
) {
1279 FileObject
->CurrentByteOffset
.QuadPart
=
1280 ByteOffset
.QuadPart
+ Irp
->IoStatus
.Information
;
1283 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
1284 SetLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
1287 Ext2CompleteIrpContext(IrpContext
, Status
);
1290 Ext2FreeIrpContext(IrpContext
);
1295 DEBUG(DL_IO
, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d "
1296 "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n",
1297 &Fcb
->Mcb
->ShortName
, ByteOffset
, Length
, PagingIo
, Nocache
, ReturnedLength
,
1298 Fcb
->Header
.ValidDataLength
.QuadPart
,Fcb
->Header
.FileSize
.QuadPart
,
1299 Fcb
->Inode
->i_size
, Status
));
1305 Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext
)
1307 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1308 PFILE_OBJECT FileObject
;
1310 PIO_STACK_LOCATION IrpSp
;
1315 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
1316 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
1318 FileObject
= IrpContext
->FileObject
;
1320 Irp
= IrpContext
->Irp
;
1321 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1323 CcMdlWriteComplete(FileObject
, &(IrpSp
->Parameters
.Write
.ByteOffset
), Irp
->MdlAddress
);
1324 Irp
->MdlAddress
= NULL
;
1325 Status
= STATUS_SUCCESS
;
1329 if (!IrpContext
->ExceptionInProgress
) {
1330 Ext2CompleteIrpContext(IrpContext
, Status
);
1339 Ext2Write (IN PEXT2_IRP_CONTEXT IrpContext
)
1342 PEXT2_FCBVCB FcbOrVcb
;
1343 PDEVICE_OBJECT DeviceObject
;
1344 PFILE_OBJECT FileObject
;
1346 BOOLEAN bCompleteRequest
= TRUE
;
1350 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
1351 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
1355 if (IsFlagOn(IrpContext
->MinorFunction
, IRP_MN_COMPLETE
)) {
1357 Status
= Ext2WriteComplete(IrpContext
);
1358 bCompleteRequest
= FALSE
;
1362 DeviceObject
= IrpContext
->DeviceObject
;
1363 if (IsExt2FsDevice(DeviceObject
)) {
1364 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1367 FileObject
= IrpContext
->FileObject
;
1369 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
1371 if (Vcb
->Identifier
.Type
!= EXT2VCB
||
1372 Vcb
->Identifier
.Size
!= sizeof(EXT2_VCB
) ) {
1373 Status
= STATUS_INVALID_PARAMETER
;
1377 if (IsVcbReadOnly(Vcb
)) {
1378 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1382 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
) &&
1383 Vcb
->LockFile
!= FileObject
) {
1384 Status
= STATUS_ACCESS_DENIED
;
1388 FcbOrVcb
= (PEXT2_FCBVCB
) FileObject
->FsContext
;
1390 if (FcbOrVcb
->Identifier
.Type
== EXT2VCB
) {
1392 Status
= Ext2WriteVolume(IrpContext
);
1393 if (!NT_SUCCESS(Status
)) {
1396 bCompleteRequest
= FALSE
;
1398 } else if (FcbOrVcb
->Identifier
.Type
== EXT2FCB
) {
1400 if (IsFlagOn(Vcb
->Flags
, VCB_DISMOUNT_PENDING
)) {
1401 Status
= STATUS_TOO_LATE
;
1405 Status
= Ext2WriteFile(IrpContext
);
1406 if (!NT_SUCCESS(Status
)) {
1410 bCompleteRequest
= FALSE
;
1412 Status
= STATUS_INVALID_PARAMETER
;
1418 if (bCompleteRequest
) {
1419 Ext2CompleteIrpContext(IrpContext
, Status
);