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