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