xref: /reactos/drivers/filesystems/ext2/src/write.c (revision 8f9ef68e)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             write.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 
14 /* GLOBALS ***************************************************************/
15 
16 extern PEXT2_GLOBAL Ext2Global;
17 
18 #define DL_FLP  DL_DBG
19 
20 /* DEFINITIONS *************************************************************/
21 
22 #define EXT2_FLPFLUSH_MAGIC 'FF2E'
23 
24 typedef struct _EXT2_FLPFLUSH_CONTEXT {
25 
26     PEXT2_VCB           Vcb;
27     PEXT2_FCB           Fcb;
28     PFILE_OBJECT        FileObject;
29 
30     KDPC                Dpc;
31     KTIMER              Timer;
32     WORK_QUEUE_ITEM     Item;
33 
34 } EXT2_FLPFLUSH_CONTEXT, *PEXT2_FLPFLUSH_CONTEXT;
35 
36 #ifdef __REACTOS__
37 VOID NTAPI
38 #else
39 VOID
40 #endif
41 Ext2FloppyFlush(IN PVOID Parameter);
42 
43 #ifdef __REACTOS__
44 VOID NTAPI
45 #else
46 VOID
47 #endif
48 Ext2FloppyFlushDpc (
49     IN PKDPC Dpc,
50     IN PVOID DeferredContext,
51     IN PVOID SystemArgument1,
52     IN PVOID SystemArgument2);
53 
54 
55 NTSTATUS
56 Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext);
57 
58 NTSTATUS
59 Ext2WriteFile (IN PEXT2_IRP_CONTEXT IrpContext);
60 
61 NTSTATUS
62 Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext);
63 
64 VOID
65 Ext2DeferWrite(IN PEXT2_IRP_CONTEXT, PIRP Irp);
66 
67 
68 /* FUNCTIONS *************************************************************/
69 
70 #ifdef __REACTOS__
71 VOID NTAPI
72 #else
73 VOID
74 #endif
75 Ext2FloppyFlush(IN PVOID Parameter)
76 {
77     PEXT2_FLPFLUSH_CONTEXT Context;
78     PFILE_OBJECT           FileObject;
79     PEXT2_FCB Fcb;
80     PEXT2_VCB Vcb;
81 
82     Context = (PEXT2_FLPFLUSH_CONTEXT) Parameter;
83     FileObject = Context->FileObject;
84     Fcb = Context->Fcb;
85     Vcb = Context->Vcb;
86 
87     DEBUG(DL_FLP, ("Ext2FloppyFlushing ...\n"));
88 
89     IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
90 
91     if (FileObject) {
92         ASSERT(Fcb == (PEXT2_FCB)FileObject->FsContext);
93         ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
94         ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
95         ExReleaseResourceLite(&Fcb->PagingIoResource);
96 
97         CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL);
98         ExReleaseResourceLite(&Fcb->MainResource);
99 
100         ObDereferenceObject(FileObject);
101     }
102 
103     if (Vcb) {
104         ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
105 
106         ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
107         ExReleaseResourceLite(&Vcb->PagingIoResource);
108 
109         Ext2FlushVcb(Vcb);
110         ExReleaseResourceLite(&Vcb->MainResource);
111     }
112 
113     IoSetTopLevelIrp(NULL);
114     Ext2FreePool(Parameter, EXT2_FLPFLUSH_MAGIC);
115 }
116 
117 #ifdef __REACTOS__
118 VOID NTAPI
119 #else
120 VOID
121 #endif
122 Ext2FloppyFlushDpc (
123     IN PKDPC Dpc,
124     IN PVOID DeferredContext,
125     IN PVOID SystemArgument1,
126     IN PVOID SystemArgument2
127 )
128 {
129     PEXT2_FLPFLUSH_CONTEXT Context;
130 
131     Context = (PEXT2_FLPFLUSH_CONTEXT) DeferredContext;
132 
133     DEBUG(DL_FLP, ("Ext2FloppyFlushDpc is to be started...\n"));
134 
135     ExQueueWorkItem(&Context->Item, CriticalWorkQueue);
136 }
137 
138 VOID
139 Ext2StartFloppyFlushDpc (
140     PEXT2_VCB   Vcb,
141     PEXT2_FCB   Fcb,
142     PFILE_OBJECT FileObject )
143 {
144     LARGE_INTEGER          OneSecond;
145     PEXT2_FLPFLUSH_CONTEXT Context;
146 
147     ASSERT(IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK));
148 
149     Context = Ext2AllocatePool(
150                   NonPagedPool,
151                   sizeof(EXT2_FLPFLUSH_CONTEXT),
152                   EXT2_FLPFLUSH_MAGIC
153               );
154 
155     if (!Context) {
156         DEBUG(DL_ERR, ( "Ex2StartFloppy...: failed to allocate Context\n"));
157         DbgBreak();
158         return;
159     }
160 
161     KeInitializeTimer(&Context->Timer);
162 
163     KeInitializeDpc( &Context->Dpc,
164                      Ext2FloppyFlushDpc,
165                      Context );
166 
167     ExInitializeWorkItem( &Context->Item,
168                           Ext2FloppyFlush,
169                           Context );
170 
171     Context->Vcb = Vcb;
172     Context->Fcb = Fcb;
173     Context->FileObject = FileObject;
174 
175     if (FileObject) {
176         ObReferenceObject(FileObject);
177     }
178 
179     OneSecond.QuadPart = (LONGLONG)-1*1000*1000*10;
180     KeSetTimer( &Context->Timer,
181                 OneSecond,
182                 &Context->Dpc );
183 }
184 
185 BOOLEAN
186 Ext2ZeroData (
187     IN PEXT2_IRP_CONTEXT IrpContext,
188     IN PEXT2_VCB         Vcb,
189     IN PFILE_OBJECT      FileObject,
190     IN PLARGE_INTEGER    Start,
191     IN PLARGE_INTEGER    End
192     )
193 {
194     PEXT2_FCB       Fcb;
195     PBCB            Bcb;
196     PVOID           Ptr;
197     ULONG           Size;
198     BOOLEAN         rc = TRUE;
199 
200     ASSERT (End && Start && End->QuadPart > Start->QuadPart);
201     Fcb = (PEXT2_FCB) FileObject->FsContext;
202 
203     /* skip data zero if we've already tracked unwritten part */
204     if (0 == (  End->LowPart & (BLOCK_SIZE -1)) &&
205         0 == (Start->LowPart & (BLOCK_SIZE -1))) {
206 
207         if (INODE_HAS_EXTENT(Fcb->Inode)) {
208             return TRUE;
209         } else {
210 #if !EXT2_PRE_ALLOCATION_SUPPORT
211             return TRUE;
212 #endif
213         }
214     }
215 
216     /* clear data in range [Start, End) */
217     _SEH2_TRY {
218         rc = CcZeroData(FileObject, Start, End, Ext2CanIWait());
219     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
220         DbgBreak();
221     } _SEH2_END;
222 
223     return rc;
224 }
225 
226 VOID
227 Ext2DeferWrite(IN PEXT2_IRP_CONTEXT IrpContext, PIRP Irp)
228 {
229     ASSERT(IrpContext->Irp == Irp);
230 
231     Ext2QueueRequest(IrpContext);
232 }
233 
234 
235 NTSTATUS
236 Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext)
237 {
238     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
239 
240     PEXT2_VCB           Vcb = NULL;
241     PEXT2_CCB           Ccb = NULL;
242     PEXT2_FCBVCB        FcbOrVcb = NULL;
243     PFILE_OBJECT        FileObject = NULL;
244 
245     PDEVICE_OBJECT      DeviceObject = NULL;
246 
247     PIRP                Irp = NULL;
248     PIO_STACK_LOCATION  IoStackLocation = NULL;
249 
250     ULONG               Length;
251     LARGE_INTEGER       ByteOffset;
252 
253     BOOLEAN             PagingIo = FALSE;
254     BOOLEAN             Nocache = FALSE;
255     BOOLEAN             SynchronousIo = FALSE;
256     BOOLEAN             MainResourceAcquired = FALSE;
257 
258     BOOLEAN             bDeferred = FALSE;
259 
260     PUCHAR              Buffer = NULL;
261     PEXT2_EXTENT        Chain = NULL;
262     EXT2_EXTENT         BlockArray;
263 
264     _SEH2_TRY {
265 
266         ASSERT(IrpContext);
267         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
268                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
269 
270         DeviceObject = IrpContext->DeviceObject;
271         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
272         ASSERT(Vcb != NULL);
273         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
274                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
275 
276         FileObject = IrpContext->FileObject;
277         FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
278         ASSERT(FcbOrVcb);
279 
280         if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) {
281             Status = STATUS_INVALID_DEVICE_REQUEST;
282             _SEH2_LEAVE;
283         }
284 
285         Ccb = (PEXT2_CCB) FileObject->FsContext2;
286         Irp = IrpContext->Irp;
287         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
288 
289         Length = IoStackLocation->Parameters.Write.Length;
290         ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;
291 
292         PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
293         Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE) || (Ccb != NULL);
294         SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
295 
296         if (PagingIo) {
297             ASSERT(Nocache);
298         }
299 
300         DEBUG(DL_INF, ("Ext2WriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
301                        ByteOffset.QuadPart, Length, PagingIo, Nocache));
302 
303         if (Length == 0) {
304             Irp->IoStatus.Information = 0;
305             Status = STATUS_SUCCESS;
306             _SEH2_LEAVE;
307         }
308 
309         if (Nocache &&
310                 (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
311                  Length & (SECTOR_SIZE - 1))) {
312             Status = STATUS_INVALID_PARAMETER;
313             _SEH2_LEAVE;
314         }
315 
316         if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
317             ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
318             Status = STATUS_PENDING;
319             _SEH2_LEAVE;
320         }
321 
322         if (ByteOffset.QuadPart >=
323                 Vcb->PartitionInformation.PartitionLength.QuadPart  ) {
324             Irp->IoStatus.Information = 0;
325             Status = STATUS_END_OF_FILE;
326             _SEH2_LEAVE;
327         }
328 
329         if (!Nocache) {
330 
331             BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
332             BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
333             BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
334 
335             if ( !CcCanIWrite(
336                         FileObject,
337                         Length,
338                         (bWait && bQueue),
339                         bAgain ) ) {
340 
341                 Status = Ext2LockUserBuffer(
342                              IrpContext->Irp,
343                              Length,
344                              IoReadAccess);
345                 if (NT_SUCCESS(Status)) {
346                     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
347                     CcDeferWrite( FileObject,
348                                   (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite,
349                                   IrpContext,
350                                   Irp,
351                                   Length,
352                                   bAgain );
353 
354                     bDeferred = TRUE;
355                     Status = STATUS_PENDING;
356 
357                     _SEH2_LEAVE;
358                 }
359             }
360         }
361 
362         /*
363          * User direct volume access
364          */
365 
366         if (Ccb != NULL && !PagingIo) {
367 
368             if (!FlagOn(Ccb->Flags, CCB_VOLUME_DASD_PURGE)) {
369 
370                 if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
371                     Status = Ext2PurgeVolume( Vcb, TRUE);
372                 }
373 
374                 SetFlag(Ccb->Flags, CCB_VOLUME_DASD_PURGE);
375             }
376 
377             if (!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) {
378                 if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) {
379                     Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
380                 }
381             }
382 
383         } else if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL))  {
384 
385             ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
386             MainResourceAcquired = TRUE;
387 
388             ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
389             ExReleaseResourceLite(&Vcb->PagingIoResource);
390 
391             CcFlushCache( &(Vcb->SectionObject),
392                           &ByteOffset,
393                           Length,
394                           &(Irp->IoStatus));
395 
396             if (!NT_SUCCESS(Irp->IoStatus.Status))  {
397                 Status = Irp->IoStatus.Status;
398                 _SEH2_LEAVE;
399             }
400 
401             ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
402             ExReleaseResourceLite(&Vcb->PagingIoResource);
403 
404             CcPurgeCacheSection( &(Vcb->SectionObject),
405                                  (PLARGE_INTEGER)&(ByteOffset),
406                                  Length,
407                                  FALSE );
408 
409             ExReleaseResourceLite(&Vcb->MainResource);
410             MainResourceAcquired = FALSE;
411         }
412 
413         if ( (ByteOffset.QuadPart + Length) > Vcb->Header.FileSize.QuadPart) {
414             Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
415         }
416 
417         if (!Nocache) {
418 
419             if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
420 
421                 CcPrepareMdlWrite (
422                     Vcb->Volume,
423                     &ByteOffset,
424                     Length,
425                     &Irp->MdlAddress,
426                     &Irp->IoStatus );
427 
428                 Status = Irp->IoStatus.Status;
429 
430             } else {
431 
432                 Buffer = Ext2GetUserBuffer(Irp);
433                 if (Buffer == NULL) {
434                     DbgBreak();
435 
436                     Status = STATUS_INVALID_USER_BUFFER;
437                     _SEH2_LEAVE;
438                 }
439 
440                 if (!CcCopyWrite( Vcb->Volume,
441                                   (PLARGE_INTEGER)(&ByteOffset),
442                                   Length,
443                                   TRUE,
444                                   Buffer )) {
445                     Status = STATUS_PENDING;
446                     _SEH2_LEAVE;
447                 }
448 
449                 Status = Irp->IoStatus.Status;
450                 Ext2AddVcbExtent(Vcb, ByteOffset.QuadPart, (LONGLONG)Length);
451             }
452 
453             if (NT_SUCCESS(Status)) {
454                 Irp->IoStatus.Information = Length;
455             }
456 
457         } else if (PagingIo) {
458 
459             LONGLONG            DirtyStart;
460             LONGLONG            DirtyLba;
461             LONGLONG            DirtyLength;
462             LONGLONG            RemainLength;
463 
464             PEXT2_EXTENT        Extent = NULL;
465             PEXT2_EXTENT        List = NULL;
466 
467             Length &= ~((ULONG)SECTOR_SIZE - 1);
468 
469             Status = Ext2LockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
470             if (!NT_SUCCESS(Status)) {
471                 _SEH2_LEAVE;
472             }
473 
474             DirtyLba = ByteOffset.QuadPart;
475             RemainLength = (LONGLONG) Length;
476 
477             ASSERT(Length >= SECTOR_SIZE);
478 
479             while (RemainLength > 0) {
480 
481                 DirtyStart = DirtyLba;
482                 ASSERT(DirtyStart >= ByteOffset.QuadPart);
483                 ASSERT(DirtyStart <= ByteOffset.QuadPart + Length);
484 
485                 if (Ext2LookupVcbExtent(Vcb, DirtyStart, &DirtyLba, &DirtyLength)) {
486 
487                     if (DirtyLba == -1) {
488 
489                         DirtyLba = DirtyStart + DirtyLength;
490                         if (ByteOffset.QuadPart + Length > DirtyLba) {
491                             RemainLength = ByteOffset.QuadPart + Length - DirtyLba;
492                             ASSERT(DirtyStart >= ByteOffset.QuadPart);
493                             ASSERT(DirtyStart <= ByteOffset.QuadPart + Length);
494                         } else {
495                             RemainLength = 0;
496                         }
497                         continue;
498                     }
499 
500                     ASSERT(DirtyLba <= DirtyStart);
501                     Extent = Ext2AllocateExtent();
502 
503                     if (!Extent) {
504                         DEBUG(DL_ERR, ( "Ex2WriteVolume: failed to allocate Extent\n"));
505                         Status = STATUS_INSUFFICIENT_RESOURCES;
506                         _SEH2_LEAVE;
507                     }
508 
509                     Extent->Irp = NULL;
510                     Extent->Lba = DirtyStart;
511                     Extent->Offset = (ULONG)( DirtyStart + Length -
512                                               RemainLength - DirtyLba );
513                     ASSERT(Extent->Offset <= Length);
514 
515                     if (DirtyLba + DirtyLength >= DirtyStart + RemainLength) {
516                         Extent->Length = (ULONG)( DirtyLba +
517                                                   RemainLength -
518                                                   DirtyStart );
519                         ASSERT(Extent->Length <= Length);
520                         RemainLength = 0;
521                     } else {
522                         Extent->Length = (ULONG)(DirtyLength + DirtyLba - DirtyStart);
523                         RemainLength = RemainLength - Extent->Length;
524 /*
525                         RemainLength =  (DirtyStart + RemainLength) -
526                                         (DirtyLba + DirtyLength);
527 */
528                         ASSERT(RemainLength <= (LONGLONG)Length);
529                         ASSERT(Extent->Length <= Length);
530                     }
531 
532                     ASSERT(Extent->Length >= SECTOR_SIZE);
533                     DirtyLba = DirtyStart + Extent->Length;
534 
535                     if (List) {
536                         List->Next = Extent;
537                         List = Extent;
538                     } else {
539                         Chain = List = Extent;
540                     }
541 
542                 } else {
543 
544                     if (RemainLength > SECTOR_SIZE) {
545                         DirtyLba = DirtyStart + SECTOR_SIZE;
546                         RemainLength -= SECTOR_SIZE;
547                     } else {
548                         RemainLength = 0;
549                     }
550                 }
551             }
552 
553             if (Chain) {
554                 Status = Ext2ReadWriteBlocks(IrpContext,
555                                              Vcb,
556                                              Chain,
557                                              Length );
558                 Irp = IrpContext->Irp;
559 
560                 if (NT_SUCCESS(Status)) {
561                     for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
562                         Ext2RemoveVcbExtent(Vcb, Extent->Lba, Extent->Length);
563                     }
564                 }
565 
566                 if (!Irp) {
567                     _SEH2_LEAVE;
568                 }
569 
570             } else {
571 
572                 Irp->IoStatus.Information = Length;
573                 Status = STATUS_SUCCESS;
574                 _SEH2_LEAVE;
575             }
576 
577         } else {
578 
579             Length &= ~((ULONG)SECTOR_SIZE - 1);
580 
581             Status = Ext2LockUserBuffer(
582                          IrpContext->Irp,
583                          Length,
584                          IoWriteAccess );
585 
586             if (!NT_SUCCESS(Status)) {
587                 _SEH2_LEAVE;
588             }
589 
590             BlockArray.Irp = NULL;
591             BlockArray.Lba = ByteOffset.QuadPart;
592             BlockArray.Offset = 0;
593             BlockArray.Length = Length;
594             BlockArray.Next = NULL;
595 
596             Status = Ext2ReadWriteBlocks(IrpContext,
597                                          Vcb,
598                                          &BlockArray,
599                                          Length );
600 
601             if (NT_SUCCESS(Status)) {
602                 Irp->IoStatus.Information = Length;
603             }
604 
605             Irp = IrpContext->Irp;
606             if (!Irp) {
607                 _SEH2_LEAVE;
608             }
609         }
610 
611     } _SEH2_FINALLY {
612 
613         if (MainResourceAcquired) {
614             ExReleaseResourceLite(&Vcb->MainResource);
615         }
616 
617         if (!IrpContext->ExceptionInProgress) {
618 
619             if (Irp) {
620 
621                 if (Status == STATUS_PENDING) {
622 
623                     if (!bDeferred) {
624                         Status = Ext2LockUserBuffer(
625                                      IrpContext->Irp,
626                                      Length,
627                                      IoReadAccess );
628 
629                         if (NT_SUCCESS(Status)) {
630                             Status = Ext2QueueRequest(IrpContext);
631                         } else {
632                             Ext2CompleteIrpContext(IrpContext, Status);
633                         }
634                     }
635 
636                 } else {
637 
638                     if (NT_SUCCESS(Status)) {
639 
640                         if (SynchronousIo && !PagingIo) {
641                             FileObject->CurrentByteOffset.QuadPart =
642                                 ByteOffset.QuadPart + Irp->IoStatus.Information;
643                         }
644 
645                         if (!PagingIo) {
646                             SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
647                         }
648                     }
649 
650                     Ext2CompleteIrpContext(IrpContext, Status);
651                 }
652 
653             } else {
654 
655                 Ext2FreeIrpContext(IrpContext);
656             }
657         }
658 
659         if (Chain) {
660             Ext2DestroyExtentChain(Chain);
661         }
662     } _SEH2_END;
663 
664     return Status;
665 }
666 
667 NTSTATUS
668 Ext2WriteInode (
669     IN PEXT2_IRP_CONTEXT    IrpContext,
670     IN PEXT2_VCB            Vcb,
671     IN PEXT2_MCB            Mcb,
672     IN ULONGLONG            Offset,
673     IN PVOID                Buffer,
674     IN ULONG                Size,
675     IN BOOLEAN              bDirectIo,
676     OUT PULONG              BytesWritten
677     )
678 {
679     PEXT2_EXTENT    Chain = NULL;
680     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
681 
682     _SEH2_TRY {
683 
684         if (BytesWritten) {
685             *BytesWritten = 0;
686         }
687 
688         Status = Ext2BuildExtents (
689                      IrpContext,
690                      Vcb,
691                      Mcb,
692                      Offset,
693                      Size,
694                      S_ISDIR(Mcb->Inode.i_mode) ? FALSE : TRUE,
695                      &Chain
696                  );
697 
698         if (!NT_SUCCESS(Status)) {
699             _SEH2_LEAVE;
700         }
701 
702         if (Chain == NULL) {
703             Status = STATUS_SUCCESS;
704             _SEH2_LEAVE;
705         }
706 
707         if (bDirectIo) {
708 
709             ASSERT(IrpContext != NULL);
710 
711             //
712             // We assume the offset is aligned.
713             //
714 
715             Status = Ext2ReadWriteBlocks(
716                          IrpContext,
717                          Vcb,
718                          Chain,
719                          Size
720                      );
721 
722         } else {
723 
724             PEXT2_EXTENT Extent;
725             for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
726 
727                 if ( !Ext2SaveBuffer(
728                             IrpContext,
729                             Vcb,
730                             Extent->Lba,
731                             Extent->Length,
732                             (PVOID)((PUCHAR)Buffer + Extent->Offset)
733                         )) {
734                     _SEH2_LEAVE;
735                 }
736             }
737 
738             if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
739 
740                 DEBUG(DL_FLP, ("Ext2WriteInode is starting FlushingDpc...\n"));
741                 Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
742             }
743 
744             Status = STATUS_SUCCESS;
745         }
746 
747     } _SEH2_FINALLY {
748 
749         if (Chain) {
750             Ext2DestroyExtentChain(Chain);
751         }
752 
753         if (NT_SUCCESS(Status) && BytesWritten) {
754             *BytesWritten = Size;
755         }
756     } _SEH2_END;
757 
758     return Status;
759 }
760 
761 
762 NTSTATUS
763 Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
764 {
765     PEXT2_VCB           Vcb = NULL;
766     PEXT2_FCB           Fcb = NULL;
767     PEXT2_CCB           Ccb = NULL;
768     PFILE_OBJECT        FileObject = NULL;
769 
770     PDEVICE_OBJECT      DeviceObject = NULL;
771 
772     PIRP                Irp = NULL;
773     PIO_STACK_LOCATION  IoStackLocation = NULL;
774     PUCHAR              Buffer = NULL;
775 
776     LARGE_INTEGER       ByteOffset;
777     ULONG               ReturnedLength = 0;
778     ULONG               Length;
779 
780     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
781 
782     BOOLEAN             OpPostIrp = FALSE;
783     BOOLEAN             PagingIo = FALSE;
784     BOOLEAN             Nocache = FALSE;
785     BOOLEAN             SynchronousIo = FALSE;
786 
787     BOOLEAN             RecursiveWriteThrough = FALSE;
788     BOOLEAN             MainResourceAcquired = FALSE;
789     BOOLEAN             PagingIoResourceAcquired = FALSE;
790 
791     BOOLEAN             bDeferred = FALSE;
792 #ifndef __REACTOS__
793     BOOLEAN             UpdateFileValidSize = FALSE;
794 #endif
795     BOOLEAN             FileSizesChanged = FALSE;
796     BOOLEAN             rc;
797 
798 
799     _SEH2_TRY {
800 
801         ASSERT(IrpContext);
802         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
803                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
804 
805         DeviceObject = IrpContext->DeviceObject;
806         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
807         ASSERT(Vcb != NULL);
808         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
809                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
810 
811         FileObject = IrpContext->FileObject;
812         Fcb = (PEXT2_FCB) FileObject->FsContext;
813         Ccb = (PEXT2_CCB) FileObject->FsContext2;
814         ASSERT(Fcb);
815         ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
816                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
817 
818         Irp = IrpContext->Irp;
819         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
820 
821         Length = IoStackLocation->Parameters.Write.Length;
822         ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;
823 
824         PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
825         Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE);
826         SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
827 
828         if (PagingIo) {
829             ASSERT(Nocache);
830         }
831 
832         DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
833                        &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
834 
835         if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
836             Status = STATUS_INVALID_DEVICE_REQUEST;
837             _SEH2_LEAVE;
838         }
839 
840         if (IsFileDeleted(Fcb->Mcb) ||
841             (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) {
842             Status = STATUS_FILE_DELETED;
843             _SEH2_LEAVE;
844         }
845 
846         if (Length == 0) {
847             Irp->IoStatus.Information = 0;
848             Status = STATUS_SUCCESS;
849             _SEH2_LEAVE;
850         }
851 
852         if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
853             ByteOffset.HighPart == -1) {
854             ByteOffset = FileObject->CurrentByteOffset;
855         } else if (IsWritingToEof(ByteOffset)) {
856             ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
857         }
858 
859         if (Nocache && !PagingIo &&
860             ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
861                (Length & (SECTOR_SIZE - 1))) ) {
862             Status = STATUS_INVALID_PARAMETER;
863             _SEH2_LEAVE;
864         }
865 
866         if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
867             ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
868             Status = STATUS_PENDING;
869             _SEH2_LEAVE;
870         }
871 
872         if (!Nocache) {
873 
874             BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
875             BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
876             BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
877 
878             if ( !CcCanIWrite(
879                         FileObject,
880                         Length,
881                         (bWait && bQueue),
882                         bAgain ) ) {
883 
884                 Status = Ext2LockUserBuffer(
885                              IrpContext->Irp,
886                              Length,
887                              IoReadAccess);
888 
889                 if (NT_SUCCESS(Status)) {
890                     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
891                     CcDeferWrite( FileObject,
892                                   (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite,
893                                   IrpContext,
894                                   Irp,
895                                   Length,
896                                   bAgain );
897                     bDeferred = TRUE;
898                     Status = STATUS_PENDING;
899                     _SEH2_LEAVE;
900                 }
901             }
902         }
903 
904         if (IsDirectory(Fcb) && !PagingIo) {
905             Status = STATUS_INVALID_DEVICE_REQUEST;
906             _SEH2_LEAVE;
907         }
908 
909         if (IsFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && !IrpContext->IsTopLevel) {
910 
911             PIRP TopIrp;
912 
913             TopIrp = IoGetTopLevelIrp();
914 
915             if ( (ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG &&
916                     NodeType(TopIrp) == IO_TYPE_IRP) {
917 
918                 PIO_STACK_LOCATION IrpStack;
919 
920                 IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
921 
922                 if ((IrpStack->MajorFunction == IRP_MJ_WRITE) &&
923                     (IrpStack->FileObject->FsContext == FileObject->FsContext) &&
924                     !FlagOn(TopIrp->Flags, IRP_NOCACHE) ) {
925 
926                     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
927                     RecursiveWriteThrough = TRUE;
928                 }
929             }
930         }
931 
932         if (PagingIo) {
933 
934             if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, TRUE)) {
935                 Status = STATUS_PENDING;
936                 _SEH2_LEAVE;
937             }
938             PagingIoResourceAcquired = TRUE;
939 
940             if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {
941 
942                 if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
943 
944                     Status = STATUS_SUCCESS;
945                     Irp->IoStatus.Information = 0;
946                     _SEH2_LEAVE;
947 
948                 } else {
949 
950                     ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
951                     if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart)
952                         Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
953                 }
954 
955             } else {
956 
957                 ReturnedLength = Length;
958             }
959 
960         } else {
961 
962             if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) {
963                 Status = STATUS_ACCESS_DENIED;
964                 _SEH2_LEAVE;
965             }
966 
967             if (IsDirectory(Fcb)) {
968                 _SEH2_LEAVE;
969             }
970 
971             if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) {
972                 Status = STATUS_PENDING;
973                 _SEH2_LEAVE;
974             }
975             MainResourceAcquired = TRUE;
976 
977             //
978             //  Do flushing for such cases
979             //
980             if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject != NULL)  {
981 
982                 ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE);
983                 ExReleaseResourceLite(&Fcb->PagingIoResource);
984 
985                 CcFlushCache( &(Fcb->SectionObject),
986                               &ByteOffset,
987                               CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
988                               &(Irp->IoStatus));
989                 ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
990 
991                 if (!NT_SUCCESS(Irp->IoStatus.Status)) {
992                     Status = Irp->IoStatus.Status;
993                     _SEH2_LEAVE;
994                 }
995 
996                 ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE);
997                 ExReleaseResourceLite(&Fcb->PagingIoResource);
998 
999                 CcPurgeCacheSection( &(Fcb->SectionObject),
1000                                      &(ByteOffset),
1001                                      CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
1002                                      FALSE );
1003             }
1004 
1005             if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLockAnchor, Irp)) {
1006                 Status = STATUS_FILE_LOCK_CONFLICT;
1007                 _SEH2_LEAVE;
1008             }
1009 
1010             if (Ccb != NULL) {
1011                 Status = FsRtlCheckOplock( &Fcb->Oplock,
1012                                            Irp,
1013                                            IrpContext,
1014                                            Ext2OplockComplete,
1015                                            Ext2LockIrp );
1016 
1017                 if (Status != STATUS_SUCCESS) {
1018                     OpPostIrp = TRUE;
1019                     _SEH2_LEAVE;
1020                 }
1021 
1022                 //
1023                 //  Set the flag indicating if Fast I/O is possible
1024                 //
1025 
1026                 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
1027             }
1028 
1029             //
1030             //  Extend the inode size when the i/o is beyond the file end ?
1031             //
1032 
1033             if ((ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {
1034 
1035                 LARGE_INTEGER AllocationSize, Last;
1036 
1037                 if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE)) {
1038                     Status = STATUS_PENDING;
1039                     _SEH2_LEAVE;
1040                 }
1041                 PagingIoResourceAcquired = TRUE;
1042 
1043                 /* let this irp wait, since it has to be synchronous */
1044                 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1045 
1046                 Last.QuadPart = Fcb->Header.AllocationSize.QuadPart;
1047                 AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);
1048                 AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
1049                                           (ULONGLONG)AllocationSize.QuadPart,
1050                                           (ULONGLONG)BLOCK_SIZE);
1051 
1052                 /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks
1053                    for indirect files, otherwise we might get gabage data in holes */
1054                 IrpContext->MajorFunction += IRP_MJ_MAXIMUM_FUNCTION;
1055                 Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize);
1056                 IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION;
1057                 if (AllocationSize.QuadPart > Last.QuadPart) {
1058                     Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart;
1059                     SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE);
1060                 }
1061                 ExReleaseResourceLite(&Fcb->PagingIoResource);
1062                 PagingIoResourceAcquired = FALSE;
1063 
1064                 if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
1065                     if (NT_SUCCESS(Status)) {
1066                         DbgBreak();
1067                         Status = STATUS_UNSUCCESSFUL;
1068                     }
1069                     _SEH2_LEAVE;
1070                 }
1071 
1072                 if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) {
1073                     Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
1074                 }
1075 
1076                 Fcb->Header.FileSize.QuadPart = Fcb->Inode->i_size = ByteOffset.QuadPart + Length;
1077                 Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
1078 
1079                 if (CcIsFileCached(FileObject)) {
1080                     CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
1081                 }
1082 
1083                 FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED;
1084                 FileSizesChanged = TRUE;
1085 
1086                 if (Fcb->Header.FileSize.QuadPart >= 0x80000000 &&
1087                         !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
1088                     SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
1089                     Ext2SaveSuper(IrpContext, Vcb);
1090                 }
1091 
1092                 DEBUG(DL_IO, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n",
1093                               &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
1094                               Fcb->Header.AllocationSize.QuadPart));
1095             }
1096 
1097             ReturnedLength = Length;
1098         }
1099 
1100         if (!Nocache) {
1101 
1102             if (FileObject->PrivateCacheMap == NULL) {
1103                 CcInitializeCacheMap(
1104                     FileObject,
1105                     (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
1106                     FALSE,
1107                     &Ext2Global->CacheManagerCallbacks,
1108                     Fcb );
1109 
1110                 CcSetReadAheadGranularity(
1111                     FileObject,
1112                     READ_AHEAD_GRANULARITY );
1113             }
1114 
1115             if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
1116 
1117                 CcPrepareMdlWrite(
1118                     FileObject,
1119                     &ByteOffset,
1120                     Length,
1121                     &Irp->MdlAddress,
1122                     &Irp->IoStatus );
1123 
1124                 Status = Irp->IoStatus.Status;
1125 
1126             } else {
1127 
1128                 Buffer = Ext2GetUserBuffer(Irp);
1129                 if (Buffer == NULL) {
1130                     DbgBreak();
1131                     Status = STATUS_INVALID_USER_BUFFER;
1132                     _SEH2_LEAVE;
1133                 }
1134 
1135                 if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
1136 
1137                     /* let this irp wait, since it has to be synchronous */
1138                     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1139 
1140                     rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
1141                                       &Fcb->Header.ValidDataLength, &ByteOffset);
1142                     if (!rc) {
1143                         Status = STATUS_PENDING;
1144                         DbgBreak();
1145                         _SEH2_LEAVE;
1146                     }
1147                 }
1148 
1149                 if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) {
1150                     if (Ext2CanIWait() ||
1151                         !CcCopyWrite(FileObject,  &ByteOffset, Length, TRUE, Buffer)) {
1152                         Status = STATUS_PENDING;
1153                         DbgBreak();
1154                         _SEH2_LEAVE;
1155                     }
1156                 }
1157 
1158                 if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
1159 
1160                     if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
1161                         Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1162                     } else {
1163                         if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
1164                             Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
1165                     }
1166 
1167                     CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
1168                     FileSizesChanged = TRUE;
1169                 }
1170 
1171                 Status = STATUS_SUCCESS;
1172             }
1173 
1174             if (NT_SUCCESS(Status)) {
1175                 Irp->IoStatus.Information = Length;
1176                 if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
1177                     DEBUG(DL_FLP, ("Ext2WriteFile is starting FlushingDpc...\n"));
1178                     Ext2StartFloppyFlushDpc(Vcb, Fcb, FileObject);
1179                 }
1180             }
1181 
1182         } else {
1183 
1184             if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
1185                 if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
1186 
1187                     /* let this irp wait, since it has to be synchronous */
1188                     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1189                     rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
1190                                       &Fcb->Header.ValidDataLength,
1191                                       &ByteOffset);
1192                     if (!rc) {
1193                         Status = STATUS_PENDING;
1194                         DbgBreak();
1195                         _SEH2_LEAVE;
1196                     }
1197                 }
1198             }
1199 
1200             Status = Ext2LockUserBuffer(
1201                          IrpContext->Irp,
1202                          Length,
1203                          IoReadAccess );
1204 
1205             if (!NT_SUCCESS(Status)) {
1206                 _SEH2_LEAVE;
1207             }
1208 
1209             Irp->IoStatus.Status = STATUS_SUCCESS;
1210             Irp->IoStatus.Information = ReturnedLength;
1211 
1212             Status = Ext2WriteInode(
1213                          IrpContext,
1214                          Vcb,
1215                          Fcb->Mcb,
1216                          (ULONGLONG)(ByteOffset.QuadPart),
1217                          NULL,
1218                          ReturnedLength,
1219                          TRUE,
1220                          &Length
1221                      );
1222 
1223             Irp = IrpContext->Irp;
1224 
1225             if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
1226 
1227                 if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
1228 
1229                     FileSizesChanged = TRUE;
1230 
1231                     if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
1232                         if (!PagingIo)
1233                             Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length;
1234                         Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1235                     } else {
1236                         if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
1237                             Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
1238                     }
1239 
1240                     if (!PagingIo && CcIsFileCached(FileObject)) {
1241                         CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
1242                     }
1243 
1244                     DEBUG(DL_IO, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n",
1245                                   &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
1246                                    Fcb->Header.AllocationSize.QuadPart, ByteOffset.QuadPart, Length));
1247                 }
1248             }
1249         }
1250 
1251         if (FileSizesChanged) {
1252             FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED;
1253             Ext2NotifyReportChange( IrpContext,  Vcb, Fcb->Mcb,
1254                                     FILE_NOTIFY_CHANGE_SIZE,
1255                                     FILE_ACTION_MODIFIED );
1256         }
1257 
1258     } _SEH2_FINALLY {
1259 
1260         /*
1261          *  in case we got excpetions, we need revert MajorFunction
1262          *  back to IRP_MJ_WRITE. The reason we do this, is to tell
1263          *  Ext2ExpandFile to allocate unwritten extent or don't add
1264          *  new blocks for indirect files.
1265          */
1266         if (IrpContext->MajorFunction > IRP_MJ_MAXIMUM_FUNCTION)
1267             IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION;
1268 
1269         if (Irp) {
1270             if (PagingIoResourceAcquired) {
1271                 ExReleaseResourceLite(&Fcb->PagingIoResource);
1272             }
1273 
1274             if (MainResourceAcquired) {
1275                 ExReleaseResourceLite(&Fcb->MainResource);
1276             }
1277         }
1278 
1279         if (!OpPostIrp && !IrpContext->ExceptionInProgress) {
1280 
1281             if (Irp) {
1282 
1283                 if (Status == STATUS_PENDING ||
1284                         Status == STATUS_CANT_WAIT ) {
1285 
1286                     if (!bDeferred) {
1287                         Status = Ext2QueueRequest(IrpContext);
1288                     }
1289 
1290                 } else {
1291 
1292                     if (NT_SUCCESS(Status) && !PagingIo) {
1293 
1294                         if (SynchronousIo) {
1295                             FileObject->CurrentByteOffset.QuadPart =
1296                                 ByteOffset.QuadPart + Irp->IoStatus.Information;
1297                         }
1298 
1299                         SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
1300                         SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
1301                     }
1302 
1303                     Ext2CompleteIrpContext(IrpContext, Status);
1304                 }
1305             } else {
1306                 Ext2FreeIrpContext(IrpContext);
1307             }
1308         }
1309     } _SEH2_END;
1310 
1311     DEBUG(DL_IO, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d "
1312                   "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n",
1313                   &Fcb->Mcb->ShortName, ByteOffset, Length, PagingIo, Nocache, ReturnedLength,
1314                   Fcb->Header.ValidDataLength.QuadPart,Fcb->Header.FileSize.QuadPart,
1315                   Fcb->Inode->i_size, Status));
1316 
1317     return Status;
1318 }
1319 
1320 NTSTATUS
1321 Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext)
1322 {
1323     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
1324     PFILE_OBJECT    FileObject;
1325     PIRP            Irp;
1326     PIO_STACK_LOCATION IrpSp;
1327 
1328     _SEH2_TRY {
1329 
1330         ASSERT(IrpContext);
1331         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1332                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1333 
1334         FileObject = IrpContext->FileObject;
1335 
1336         Irp = IrpContext->Irp;
1337         IrpSp = IoGetCurrentIrpStackLocation(Irp);
1338 
1339         CcMdlWriteComplete(FileObject, &(IrpSp->Parameters.Write.ByteOffset), Irp->MdlAddress);
1340         Irp->MdlAddress = NULL;
1341         Status = STATUS_SUCCESS;
1342 
1343     } _SEH2_FINALLY {
1344 
1345         if (!IrpContext->ExceptionInProgress) {
1346             Ext2CompleteIrpContext(IrpContext, Status);
1347         }
1348     } _SEH2_END;
1349 
1350     return Status;
1351 }
1352 
1353 
1354 NTSTATUS
1355 Ext2Write (IN PEXT2_IRP_CONTEXT IrpContext)
1356 {
1357     NTSTATUS            Status;
1358     PEXT2_FCBVCB        FcbOrVcb;
1359     PDEVICE_OBJECT      DeviceObject;
1360     PFILE_OBJECT        FileObject;
1361     PEXT2_VCB           Vcb;
1362     BOOLEAN             bCompleteRequest = TRUE;
1363 
1364     ASSERT(IrpContext);
1365 
1366     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1367            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1368 
1369     _SEH2_TRY {
1370 
1371         if (IsFlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE)) {
1372 
1373             Status =  Ext2WriteComplete(IrpContext);
1374             bCompleteRequest = FALSE;
1375 
1376         } else {
1377 
1378             DeviceObject = IrpContext->DeviceObject;
1379             if (IsExt2FsDevice(DeviceObject)) {
1380                 Status = STATUS_INVALID_DEVICE_REQUEST;
1381                 _SEH2_LEAVE;
1382             }
1383             FileObject = IrpContext->FileObject;
1384 
1385             Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1386 
1387             if (Vcb->Identifier.Type != EXT2VCB ||
1388                     Vcb->Identifier.Size != sizeof(EXT2_VCB) ) {
1389                 Status = STATUS_INVALID_PARAMETER;
1390                 _SEH2_LEAVE;
1391             }
1392 
1393             if (IsVcbReadOnly(Vcb)) {
1394                 Status = STATUS_MEDIA_WRITE_PROTECTED;
1395                 _SEH2_LEAVE;
1396             }
1397 
1398             if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
1399                 Vcb->LockFile != FileObject ) {
1400                 Status = STATUS_ACCESS_DENIED;
1401                 _SEH2_LEAVE;
1402             }
1403 
1404             FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
1405 
1406             if (FcbOrVcb->Identifier.Type == EXT2VCB) {
1407 
1408                 Status = Ext2WriteVolume(IrpContext);
1409                 if (!NT_SUCCESS(Status)) {
1410                     DbgBreak();
1411                 }
1412                 bCompleteRequest = FALSE;
1413 
1414             } else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
1415 
1416                 if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
1417                     Status = STATUS_TOO_LATE;
1418                     _SEH2_LEAVE;
1419                 }
1420 
1421                 Status = Ext2WriteFile(IrpContext);
1422                 if (!NT_SUCCESS(Status)) {
1423                     DbgBreak();
1424                 }
1425 
1426                 bCompleteRequest = FALSE;
1427             } else {
1428                 Status = STATUS_INVALID_PARAMETER;
1429             }
1430         }
1431 
1432     } _SEH2_FINALLY {
1433 
1434         if (bCompleteRequest) {
1435             Ext2CompleteIrpContext(IrpContext, Status);
1436         }
1437     } _SEH2_END;
1438 
1439     return Status;
1440 }
1441