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