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