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