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