Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / ffs / src / write.c
diff --git a/drivers/filesystems/ffs/src/write.c b/drivers/filesystems/ffs/src/write.c
new file mode 100644 (file)
index 0000000..24e04b7
--- /dev/null
@@ -0,0 +1,1588 @@
+/* 
+ * FFS File System Driver for Windows
+ *
+ * write.c
+ *
+ * 2004.5.6 ~
+ *
+ * Lee Jae-Hong, http://www.pyrasis.com
+ *
+ * See License.txt
+ *
+ */
+
+#include "ntifs.h"
+#include "ffsdrv.h"
+
+#if !FFS_READ_ONLY
+
+/* Globals */
+
+extern PFFS_GLOBAL FFSGlobal;
+
+
+/* Definitions */
+
+typedef struct _FFS_FLPFLUSH_CONTEXT {
+
+       PFFS_VCB     Vcb;
+       PFFS_FCB     Fcb;
+       PFILE_OBJECT FileObject;
+
+       KDPC         Dpc;
+       KTIMER       Timer;
+       WORK_QUEUE_ITEM Item;
+
+} FFS_FLPFLUSH_CONTEXT, *PFFS_FLPFLUSH_CONTEXT;
+
+#ifdef _PREFAST_
+WORKER_THREAD_ROUTINE __drv_mustHoldCriticalRegion FFSFloppyFlush;
+#endif // _PREFAST_
+
+__drv_mustHoldCriticalRegion
+VOID
+FFSFloppyFlush(
+       IN PVOID Parameter);
+
+#ifdef _PREFAST_
+KDEFERRED_ROUTINE FFSFloppyFlushDpc;
+#endif // _PREFAST_
+
+VOID
+FFSFloppyFlushDpc(
+       IN PKDPC Dpc,
+       IN PVOID DeferredContext,
+       IN PVOID SystemArgument1,
+       IN PVOID SystemArgument2);
+
+
+
+NTSTATUS
+FFSWriteComplete(
+       IN PFFS_IRP_CONTEXT IrpContext);
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSWriteFile(
+       IN PFFS_IRP_CONTEXT IrpContext);
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSWriteVolume(
+       IN PFFS_IRP_CONTEXT IrpContext);
+
+VOID
+FFSDeferWrite(
+       IN   PFFS_IRP_CONTEXT,
+       PIRP Irp);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, FFSFloppyFlush)
+#pragma alloc_text(PAGE, FFSStartFloppyFlushDpc)
+#pragma alloc_text(PAGE, FFSZeroHoles)
+#pragma alloc_text(PAGE, FFSWrite)
+#pragma alloc_text(PAGE, FFSWriteVolume)
+#pragma alloc_text(PAGE, FFSv1WriteInode)
+#pragma alloc_text(PAGE, FFSWriteFile)
+#pragma alloc_text(PAGE, FFSWriteComplete)
+#endif
+
+
+__drv_mustHoldCriticalRegion
+VOID
+FFSFloppyFlush(
+       IN PVOID Parameter)
+{
+       PFFS_FLPFLUSH_CONTEXT Context;
+       PFILE_OBJECT          FileObject;
+       PFFS_FCB              Fcb;
+       PFFS_VCB              Vcb;
+
+    PAGED_CODE();
+
+       Context = (PFFS_FLPFLUSH_CONTEXT) Parameter;
+       FileObject = Context->FileObject;
+       Fcb = Context->Fcb;
+       Vcb = Context->Vcb;
+
+       FFSPrint((DBG_USER, "FFSFloppyFlushing ...\n"));
+
+       IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
+
+       if (Vcb)
+       {
+               ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
+               ExReleaseResourceLite(&Vcb->PagingIoResource);
+
+               CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL);
+       }
+
+       if (FileObject)
+       {
+               ASSERT(Fcb == (PFFS_FCB)FileObject->FsContext);
+
+               ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
+               ExReleaseResourceLite(&Fcb->PagingIoResource);
+
+               CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL);
+
+               ObDereferenceObject(FileObject);
+       }
+
+       IoSetTopLevelIrp(NULL);
+
+       ExFreePool(Parameter);
+}
+
+
+VOID
+FFSFloppyFlushDpc(
+       IN PKDPC Dpc,
+       IN PVOID DeferredContext,
+       IN PVOID SystemArgument1,
+       IN PVOID SystemArgument2)
+{
+       PFFS_FLPFLUSH_CONTEXT Context;
+
+       Context = (PFFS_FLPFLUSH_CONTEXT)DeferredContext;
+
+       FFSPrint((DBG_USER, "FFSFloppyFlushDpc is to be started...\n"));
+
+       ExInitializeWorkItem(&Context->Item,
+                       FFSFloppyFlush,
+                       Context);
+
+       ExQueueWorkItem(&Context->Item, CriticalWorkQueue);
+}
+
+
+VOID
+FFSStartFloppyFlushDpc(
+       PFFS_VCB     Vcb,
+       PFFS_FCB     Fcb,
+       PFILE_OBJECT FileObject)
+{
+       LARGE_INTEGER          OneSecond;
+       PFFS_FLPFLUSH_CONTEXT Context;
+
+    PAGED_CODE();
+
+       ASSERT(IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK));
+
+       Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(PFFS_FLPFLUSH_CONTEXT), FFS_POOL_TAG);
+
+       if (!Context)
+       {
+               FFSBreakPoint();
+               return;
+       }
+
+       KeInitializeTimer(&Context->Timer);
+
+       KeInitializeDpc(&Context->Dpc,
+                       FFSFloppyFlushDpc,
+                       Context);
+
+       Context->Vcb = Vcb;
+       Context->Fcb = Fcb;
+       Context->FileObject = FileObject;
+
+       if (FileObject)
+       {
+               ObReferenceObject(FileObject);
+       }
+
+       OneSecond.QuadPart = (LONGLONG) - 1 * 1000 * 1000 * 10;
+       KeSetTimer(&Context->Timer,
+                       OneSecond,
+                       &Context->Dpc);
+}
+
+
+BOOLEAN
+FFSZeroHoles(
+       IN PFFS_IRP_CONTEXT IrpContext,
+       IN PFFS_VCB         Vcb,
+       IN PFILE_OBJECT     FileObject,
+       IN LONGLONG         Offset,
+       IN LONGLONG         Count)
+{
+       LARGE_INTEGER StartAddr = {0, 0};
+       LARGE_INTEGER EndAddr = {0, 0};
+
+    PAGED_CODE();
+
+       StartAddr.QuadPart = (Offset + (SECTOR_SIZE - 1)) &
+               ~((LONGLONG)SECTOR_SIZE - 1);
+
+       EndAddr.QuadPart = (Offset + Count + (SECTOR_SIZE - 1)) &
+               ~((LONGLONG)SECTOR_SIZE - 1);
+
+       if (StartAddr.QuadPart < EndAddr.QuadPart)
+       {
+               return CcZeroData(FileObject,
+                               &StartAddr,
+                               &EndAddr,
+                               IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
+       }
+
+       return TRUE;
+}
+
+
+VOID
+FFSDeferWrite(
+       IN PFFS_IRP_CONTEXT IrpContext,
+       PIRP Irp)
+{
+       ASSERT(IrpContext->Irp == Irp);
+
+       FFSQueueRequest(IrpContext);
+}
+
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSWriteVolume(
+       IN PFFS_IRP_CONTEXT IrpContext)
+{
+       NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+
+       PFFS_VCB            Vcb;
+       PFFS_CCB            Ccb;
+       PFFS_FCBVCB         FcbOrVcb;
+       PFILE_OBJECT        FileObject;
+
+       PDEVICE_OBJECT      DeviceObject;
+
+       PIRP                Irp;
+       PIO_STACK_LOCATION  IoStackLocation;
+
+       ULONG               Length;
+       LARGE_INTEGER       ByteOffset;
+
+       BOOLEAN             PagingIo;
+       BOOLEAN             Nocache;
+       BOOLEAN             SynchronousIo;
+       BOOLEAN             MainResourceAcquired = FALSE;
+       BOOLEAN             PagingIoResourceAcquired = FALSE;
+
+       BOOLEAN             bDeferred = FALSE;
+
+       PUCHAR              Buffer;
+
+    PAGED_CODE();
+
+       _SEH2_TRY
+       {
+               ASSERT(IrpContext);
+
+               ASSERT((IrpContext->Identifier.Type == FFSICX) &&
+                               (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
+
+               DeviceObject = IrpContext->DeviceObject;
+
+               Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;
+
+               ASSERT(Vcb != NULL);
+
+               ASSERT((Vcb->Identifier.Type == FFSVCB) &&
+                               (Vcb->Identifier.Size == sizeof(FFS_VCB)));
+
+               FileObject = IrpContext->FileObject;
+
+               FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext;
+
+               ASSERT(FcbOrVcb);
+
+               if (!(FcbOrVcb->Identifier.Type == FFSVCB && (PVOID)FcbOrVcb == (PVOID)Vcb))
+               {
+                       Status = STATUS_INVALID_DEVICE_REQUEST;
+                       _SEH2_LEAVE;
+               }
+
+               Ccb = (PFFS_CCB)FileObject->FsContext2;
+
+               Irp = IrpContext->Irp;
+
+               IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+               Length = IoStackLocation->Parameters.Write.Length;
+               ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;
+
+               PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
+               Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
+               SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);
+
+               FFSPrint((DBG_INFO, "FFSWriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
+                                       ByteOffset.QuadPart, Length, PagingIo, Nocache));
+
+               if (Length == 0)
+               {
+                       Irp->IoStatus.Information = 0;
+                       Status = STATUS_SUCCESS;
+                       _SEH2_LEAVE;
+               }
+
+               // For the case of "Direct Access Storage Device", we
+               // need flush/purge the cache
+
+               if (Ccb != NULL)
+               {
+                       ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+                       MainResourceAcquired = TRUE;
+
+                       Status = FFSPurgeVolume(Vcb, TRUE);
+
+                       ExReleaseResourceLite(&Vcb->MainResource);
+                       MainResourceAcquired = FALSE;
+
+                       if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO))
+                       {
+                               if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart)
+                               {
+                                       Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
+                               }
+                       }
+
+                       {
+                               FFS_BDL BlockArray;
+
+                               if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
+                                               (Length & (SECTOR_SIZE - 1)))
+                               {
+                                       Status = STATUS_INVALID_PARAMETER;
+                                       _SEH2_LEAVE;
+                               }
+
+                               Status = FFSLockUserBuffer(
+                                                       IrpContext->Irp,
+                                                       Length,
+                                                       IoReadAccess);
+
+                               if (!NT_SUCCESS(Status))
+                               {
+                                       _SEH2_LEAVE;
+                               }
+
+                               BlockArray.Irp = NULL;
+                               BlockArray.Lba = ByteOffset.QuadPart;;
+                               BlockArray.Offset = 0;
+                               BlockArray.Length = Length;
+
+                               Status = FFSReadWriteBlocks(IrpContext,
+                                                       Vcb,
+                                                       &BlockArray,
+                                                       Length,
+                                                       1,
+                                                       FALSE);
+                               Irp = IrpContext->Irp;
+
+                               _SEH2_LEAVE;
+                       }
+               }                    
+
+               if (Nocache &&
+                               (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
+                                Length & (SECTOR_SIZE - 1)))
+               {
+                       Status = STATUS_INVALID_PARAMETER;
+                       _SEH2_LEAVE;
+               }
+
+               if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
+               {
+                       ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
+                       Status = STATUS_PENDING;
+                       _SEH2_LEAVE;
+               }
+
+               if (ByteOffset.QuadPart >=
+                               Vcb->PartitionInformation.PartitionLength.QuadPart)
+               {
+                       Irp->IoStatus.Information = 0;
+                       Status = STATUS_END_OF_FILE;
+                       _SEH2_LEAVE;
+               }
+
+#if FALSE
+
+               if (!Nocache)
+               {
+                       BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
+                       BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+                       BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
+
+                       if (!CcCanIWrite(
+                                               FileObject,
+                                               Length,
+                                               (bWait && bQueue),
+                                               bAgain))
+                       {
+                               SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
+
+                               CcDeferWrite(FileObject,
+                                               (PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
+                                               IrpContext,
+                                               Irp,
+                                               Length,
+                                               bAgain);
+
+                               bDeferred = TRUE;
+
+                               FFSBreakPoint();
+
+                               Status = STATUS_PENDING;
+
+                               _SEH2_LEAVE;
+                       }
+               }
+
+#endif
+
+               if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) 
+               {
+                       ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+                       MainResourceAcquired = TRUE;
+
+                       ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
+                       ExReleaseResourceLite(&Vcb->PagingIoResource);
+
+                       CcFlushCache(&(Vcb->SectionObject),
+                                       &ByteOffset,
+                                       Length,
+                                       &(Irp->IoStatus));
+
+                       if (!NT_SUCCESS(Irp->IoStatus.Status)) 
+                       {
+                               Status = Irp->IoStatus.Status;
+                               _SEH2_LEAVE;
+                       }
+
+                       ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
+                       ExReleaseResourceLite(&Vcb->PagingIoResource);
+
+                       CcPurgeCacheSection(&(Vcb->SectionObject),
+                                       (PLARGE_INTEGER)&(ByteOffset),
+                                       Length,
+                                       FALSE);
+
+                       ExReleaseResourceLite(&Vcb->MainResource);
+                       MainResourceAcquired = FALSE;
+               }
+
+               if (!PagingIo)
+               {
+#pragma prefast( suppress: 28137, "by design" )
+                       if (!ExAcquireResourceExclusiveLite(
+                                               &Vcb->MainResource,
+                                               IrpContext->IsSynchronous))
+                       {
+                               Status = STATUS_PENDING;
+                               _SEH2_LEAVE;
+                       }
+
+                       MainResourceAcquired = TRUE;
+               }
+               else
+               {
+                       /*
+                       ULONG ResShCnt, ResExCnt; 
+                       ResShCnt = ExIsResourceAcquiredSharedLite(&Vcb->PagingIoResource);
+                       ResExCnt = ExIsResourceAcquiredExclusiveLite(&Vcb->PagingIoResource);
+
+                       FFSPrint((DBG_USER, "PagingIoRes: %xh:%xh Synchronous=%xh\n", ResShCnt, ResExCnt, IrpContext->IsSynchronous));
+                       */
+
+                       if (Ccb)
+                       {
+                               if (!ExAcquireResourceSharedLite(
+                                                       &Vcb->PagingIoResource,
+                                                       IrpContext->IsSynchronous))
+                               {
+                                       Status = STATUS_PENDING;
+                                       _SEH2_LEAVE;
+                               }
+
+                               PagingIoResourceAcquired = TRUE;
+                       }
+               }
+
+               if (!Nocache)
+               {
+                       if ((ByteOffset.QuadPart + Length) >
+                                       Vcb->PartitionInformation.PartitionLength.QuadPart
+                       )
+                       {
+                               Length = (ULONG) (
+                                               Vcb->PartitionInformation.PartitionLength.QuadPart -
+                                               ByteOffset.QuadPart);
+
+                               Length &= ~((ULONG)SECTOR_SIZE - 1);
+                       }
+
+                       if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
+                       {
+
+                               CcPrepareMdlWrite(
+                                               Vcb->StreamObj,
+                                               &ByteOffset,
+                                               Length,
+                                               &Irp->MdlAddress,
+                                               &Irp->IoStatus);
+
+                               Status = Irp->IoStatus.Status;
+                       }
+                       else
+                       {
+                               Buffer = FFSGetUserBuffer(Irp);
+
+                               if (Buffer == NULL)
+                               {
+                                       FFSBreakPoint();
+
+                                       Status = STATUS_INVALID_USER_BUFFER;
+                                       _SEH2_LEAVE;
+                               }
+
+                               if (!CcCopyWrite(Vcb->StreamObj,
+                                                       (PLARGE_INTEGER)(&ByteOffset),
+                                                       Length,
+                                                       TRUE,
+                                                       Buffer))
+                               {
+                                       Status = STATUS_PENDING;
+                                       _SEH2_LEAVE;
+                               }
+
+                               Status = Irp->IoStatus.Status;
+                               FFSAddMcbEntry(Vcb, ByteOffset.QuadPart, (LONGLONG)Length);
+                       }
+
+                       if (NT_SUCCESS(Status))
+                       {
+                               Irp->IoStatus.Information = Length;
+                       }
+               }
+               else
+               {
+                       PFFS_BDL            ffs_bdl = NULL;
+                       ULONG               Blocks = 0;
+
+                       LONGLONG            DirtyStart;
+                       LONGLONG            DirtyLba;
+                       LONGLONG            DirtyLength;
+                       LONGLONG            RemainLength;
+
+                       if ((ByteOffset.QuadPart + Length) >
+                                       Vcb->PartitionInformation.PartitionLength.QuadPart)
+                       {
+                               Length = (ULONG)(
+                                               Vcb->PartitionInformation.PartitionLength.QuadPart -
+                                               ByteOffset.QuadPart);
+
+                               Length &= ~((ULONG)SECTOR_SIZE - 1);
+                       }
+
+                       Status = FFSLockUserBuffer(
+                                       IrpContext->Irp,
+                                       Length,
+                                       IoReadAccess);
+
+                       if (!NT_SUCCESS(Status))
+                       {
+                               _SEH2_LEAVE;
+                       }
+
+                       ffs_bdl = ExAllocatePoolWithTag(PagedPool, 
+                                       (Length / Vcb->BlockSize) *
+                                       sizeof(FFS_BDL), FFS_POOL_TAG);
+
+                       if (!ffs_bdl)
+                       {
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               _SEH2_LEAVE;
+                       }
+
+                       DirtyLba = ByteOffset.QuadPart;
+                       RemainLength = (LONGLONG)Length;
+
+                       while (RemainLength > 0)
+                       {
+                               DirtyStart = DirtyLba;
+
+                               if (FFSLookupMcbEntry(Vcb, 
+                                                       DirtyStart,
+                                                       &DirtyLba,
+                                                       &DirtyLength,
+                                                       (PLONGLONG)NULL,
+                                                       (PLONGLONG)NULL,
+                                                       (PULONG)NULL))
+                               {
+
+                                       if (DirtyLba == -1)
+                                       {
+                                               DirtyLba = DirtyStart + DirtyLength;
+
+                                               RemainLength = ByteOffset.QuadPart + 
+                                                       (LONGLONG)Length -
+                                                       DirtyLba;
+                                               continue;
+                                       }
+
+                                       ffs_bdl[Blocks].Irp = NULL;
+                                       ffs_bdl[Blocks].Lba = DirtyLba;
+                                       ffs_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length +
+                                                       DirtyStart -
+                                                       RemainLength - 
+                                                       DirtyLba);
+
+                                       if (DirtyLba + DirtyLength > DirtyStart + RemainLength)
+                                       {
+                                               ffs_bdl[Blocks].Length = (ULONG)(DirtyStart +
+                                                               RemainLength -
+                                                               DirtyLba);
+                                               RemainLength = 0;
+                                       }
+                                       else
+                                       {
+                                               ffs_bdl[Blocks].Length = (ULONG)DirtyLength;
+                                               RemainLength =  (DirtyStart + RemainLength) -
+                                                       (DirtyLba + DirtyLength);
+                                       }
+
+                                       DirtyLba = DirtyStart + DirtyLength;
+                                       Blocks++;
+                               }
+                               else
+                               {
+                                       if (Blocks == 0)
+                                       {
+                                               if (ffs_bdl)
+                                                       ExFreePool(ffs_bdl);
+
+                                               //
+                                               // Lookup fails at the first time, ie. 
+                                               // no dirty blocks in the run
+                                               //
+
+                                               FFSBreakPoint();
+
+                                               if (RemainLength == (LONGLONG)Length)
+                                                       Status = STATUS_SUCCESS;
+                                               else
+                                                       Status = STATUS_UNSUCCESSFUL;
+
+                                               _SEH2_LEAVE;
+                                       }
+                                       else
+                                       {
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (Blocks > 0)
+                       {
+                               Status = FFSReadWriteBlocks(IrpContext,
+                                                       Vcb,
+                                                       ffs_bdl,
+                                                       Length,
+                                                       Blocks,
+                                                       FALSE);
+                               Irp = IrpContext->Irp;
+
+                               if (NT_SUCCESS(Status))
+                               {
+                                       ULONG   i;
+
+                                       for (i = 0; i < Blocks; i++)
+                                       {
+                                               FFSRemoveMcbEntry(Vcb,
+                                                               ffs_bdl[i].Lba,
+                                                               ffs_bdl[i].Length);
+                                       }
+                               }
+
+                               if (ffs_bdl)
+                                       ExFreePool(ffs_bdl);
+
+                               if (!Irp)
+                                       _SEH2_LEAVE;
+
+                       }
+                       else
+                       {
+                               if (ffs_bdl)
+                                       ExFreePool(ffs_bdl);
+
+                               Irp->IoStatus.Information = Length;
+
+                               Status = STATUS_SUCCESS;
+                               _SEH2_LEAVE;
+                       }
+               }
+       }
+
+       _SEH2_FINALLY
+       {
+               if (PagingIoResourceAcquired)
+               {
+                       ExReleaseResourceForThreadLite(
+                                       &Vcb->PagingIoResource,
+                                       ExGetCurrentResourceThread());
+               }
+
+               if (MainResourceAcquired)
+               {
+                       ExReleaseResourceForThreadLite(
+                                       &Vcb->MainResource,
+                                       ExGetCurrentResourceThread());
+               }
+
+               if (!IrpContext->ExceptionInProgress)
+               {
+                       if (Irp)
+                       {
+                               if (Status == STATUS_PENDING)
+                               {
+                                       if(!bDeferred)
+                                       {
+                                               Status = FFSLockUserBuffer(
+                                                               IrpContext->Irp,
+                                                               Length,
+                                                               IoReadAccess);
+
+                                               if (NT_SUCCESS(Status))
+                                               {
+                                                       Status = FFSQueueRequest(IrpContext);
+                                               }
+                                               else
+                                               {
+                                                       FFSCompleteIrpContext(IrpContext, Status);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       if (NT_SUCCESS(Status))
+                                       {
+                                               if (SynchronousIo && !PagingIo)
+                                               {
+                                                       FileObject->CurrentByteOffset.QuadPart =
+                                                               ByteOffset.QuadPart + Irp->IoStatus.Information;
+                                               }
+
+                                               if (!PagingIo)
+                                               {
+                                                       SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+                                               }
+                                       }
+
+                                       FFSCompleteIrpContext(IrpContext, Status);
+                               }
+                       }
+                       else
+                       {
+                               FFSFreeIrpContext(IrpContext);
+                       }
+               }
+       } _SEH2_END;
+
+       return Status;
+}
+
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSv1WriteInode(
+       IN PFFS_IRP_CONTEXT     IrpContext,
+       IN PFFS_VCB             Vcb,
+       IN PFFSv1_INODE         dinode1,
+       IN ULONGLONG            offset,
+       IN PVOID                Buffer,
+       IN ULONG                size,
+       IN BOOLEAN              bWriteToDisk,
+       OUT PULONG              dwRet)
+{
+       PFFS_BDL    ffs_bdl = NULL;
+       ULONG       blocks, i;
+       NTSTATUS    Status = STATUS_UNSUCCESSFUL;
+       ULONG       Totalblocks;
+       LONGLONG    AllocSize;
+
+    PAGED_CODE();
+
+       if (dwRet)
+       {
+               *dwRet = 0;
+       }
+
+       Totalblocks = (dinode1->di_blocks);
+       AllocSize = ((LONGLONG)(FFSDataBlocks(Vcb, Totalblocks)) << BLOCK_BITS);
+
+       if ((LONGLONG)offset >= AllocSize)
+       {
+               FFSPrint((DBG_ERROR, "FFSv1WriteInode: beyond the file range.\n"));
+               return STATUS_SUCCESS;
+       }
+
+       if ((LONGLONG)offset + size > AllocSize)
+       {
+               size = (ULONG)(AllocSize - offset);
+       }
+
+       blocks = FFSv1BuildBDL(IrpContext, Vcb, dinode1, offset, size, &ffs_bdl);
+
+       if (blocks <= 0)
+       {
+               return STATUS_SUCCESS;
+       }
+
+#if DBG
+       {
+               ULONG   dwTotal = 0;
+               FFSPrint((DBG_INFO, "FFSv1WriteInode: BDLCount = %xh Size=%xh Off=%xh\n",
+                                       blocks, size, offset));
+               for(i = 0; i < blocks; i++)
+               {
+                       FFSPrint((DBG_INFO, "FFSv1WriteInode: Lba=%I64xh Len=%xh Off=%xh\n",
+                                               ffs_bdl[i].Lba, ffs_bdl[i].Length, ffs_bdl[i].Offset));
+                       dwTotal += ffs_bdl[i].Length;
+               }
+
+               if (dwTotal != size)
+               {
+                       FFSBreakPoint();
+               }
+
+               FFSPrint((DBG_INFO, "FFSv1WriteInode: Total = %xh (WriteToDisk=%x)\n",
+                                       dwTotal, bWriteToDisk));
+       }
+#endif
+
+       if (bWriteToDisk)
+       {
+
+#if 0
+               for(i = 0; i < blocks; i++)
+               {
+                       {
+                               CcFlushCache(&(Vcb->SectionObject),
+                                               (PLARGE_INTEGER)&(ffs_bdl[i].Lba),
+                                               ffs_bdl[i].Length,
+                                               NULL);
+
+                               if (Vcb->SectionObject.DataSectionObject != NULL)
+                               {
+                                       ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
+                                       ExReleaseResourceLite(&Vcb->PagingIoResource);
+
+                                       CcPurgeCacheSection(&(Vcb->SectionObject),
+                                                       (PLARGE_INTEGER)&(ffs_bdl[i].Lba),
+                                                       ffs_bdl[i].Length,
+                                                       FALSE);
+                               }
+                       }
+               }
+#endif
+
+               // assume offset is aligned.
+               Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, size, blocks, FALSE);
+       }
+       else
+       {
+               for(i = 0; i < blocks; i++)
+               {
+                       if(!FFSSaveBuffer(IrpContext, Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length, (PVOID)((PUCHAR)Buffer + ffs_bdl[i].Offset)))
+                               goto errorout;
+               }
+
+               if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
+               {
+                       FFSPrint((DBG_USER, "FFSv1WriteInode is starting FlushingDpc...\n"));
+                       FFSStartFloppyFlushDpc(Vcb, NULL, NULL);
+               }
+
+               Status = STATUS_SUCCESS;
+       }
+
+errorout:
+
+       if (ffs_bdl)
+               ExFreePool(ffs_bdl);
+
+       if (NT_SUCCESS(Status))
+       {
+               if (dwRet) *dwRet = size;
+       }
+
+       return Status;
+}
+
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSv2WriteInode(
+       IN PFFS_IRP_CONTEXT     IrpContext,
+       IN PFFS_VCB             Vcb,
+       IN PFFSv2_INODE         dinode2,
+       IN ULONGLONG            offset,
+       IN PVOID                Buffer,
+       IN ULONG                size,
+       IN BOOLEAN              bWriteToDisk,
+       OUT PULONG              dwRet)
+{
+       return STATUS_UNSUCCESSFUL;
+}
+
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSWriteFile(
+       IN PFFS_IRP_CONTEXT IrpContext)
+{
+       NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+
+       PFFS_VCB            Vcb;
+       PFFS_FCB            Fcb;
+       PFFS_CCB            Ccb;
+       PFILE_OBJECT        FileObject;
+       PFILE_OBJECT        CacheObject;
+
+       PDEVICE_OBJECT      DeviceObject;
+
+       PIRP                Irp;
+       PIO_STACK_LOCATION  IoStackLocation;
+
+       ULONG               Length;
+       ULONG               ReturnedLength;
+       LARGE_INTEGER       ByteOffset;
+
+       BOOLEAN             PagingIo;
+       BOOLEAN             Nocache;
+       BOOLEAN             SynchronousIo;
+       BOOLEAN             MainResourceAcquired = FALSE;
+       BOOLEAN             PagingIoResourceAcquired = FALSE;
+
+       BOOLEAN             bNeedExtending = FALSE;
+       BOOLEAN             bAppendFile = FALSE;
+
+       BOOLEAN             bDeferred = FALSE;
+
+       PUCHAR              Buffer;
+
+    PAGED_CODE();
+
+       _SEH2_TRY
+       {
+               ASSERT(IrpContext);
+
+               ASSERT((IrpContext->Identifier.Type == FFSICX) &&
+                               (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
+
+               DeviceObject = IrpContext->DeviceObject;
+
+               Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;
+
+               ASSERT(Vcb != NULL);
+
+               ASSERT((Vcb->Identifier.Type == FFSVCB) &&
+                               (Vcb->Identifier.Size == sizeof(FFS_VCB)));
+
+               FileObject = IrpContext->FileObject;
+
+               Fcb = (PFFS_FCB)FileObject->FsContext;
+
+               ASSERT(Fcb);
+
+               ASSERT((Fcb->Identifier.Type == FFSFCB) &&
+                               (Fcb->Identifier.Size == sizeof(FFS_FCB)));
+
+               Ccb = (PFFS_CCB)FileObject->FsContext2;
+
+               Irp = IrpContext->Irp;
+
+               IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+               Length = IoStackLocation->Parameters.Write.Length;
+               ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;
+
+               PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
+               Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
+               SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);
+
+               FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
+                                       ByteOffset.QuadPart, Length, PagingIo, Nocache));
+
+               /*
+               if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED))
+               {
+                       Status = STATUS_FILE_DELETED;
+                       _SEH2_LEAVE;
+               }
+
+               if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING))
+               {
+                       Status = STATUS_DELETE_PENDING;
+                       _SEH2_LEAVE;
+               }
+               */
+
+               if (Length == 0)
+               {
+                       Irp->IoStatus.Information = 0;
+                       Status = STATUS_SUCCESS;
+                       _SEH2_LEAVE;
+               }
+
+               if (Nocache &&
+                               (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
+                                Length & (SECTOR_SIZE - 1)))
+               {
+                       Status = STATUS_INVALID_PARAMETER;
+                       _SEH2_LEAVE;
+               }
+
+               if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
+               {
+                       ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
+                       Status = STATUS_PENDING;
+                       _SEH2_LEAVE;
+               }
+
+#if FALSE
+               if (!Nocache)
+               {
+                       BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
+                       BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+                       BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
+
+                       if (!CcCanIWrite(
+                                               FileObject,
+                                               Length,
+                                               (bWait && bQueue),
+                                               bAgain))
+                       {
+                               SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
+
+                               CcDeferWrite(FileObject,
+                                               (PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
+                                               IrpContext,
+                                               Irp,
+                                               Length,
+                                               bAgain);
+
+                               bDeferred = TRUE;
+
+                               FFSBreakPoint();
+
+                               Status = STATUS_PENDING;
+                               _SEH2_LEAVE;
+                       }
+               }
+
+#endif
+
+               if (IsEndOfFile(ByteOffset))
+               {
+                       bAppendFile = TRUE;
+                       ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
+               }
+
+               if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo)
+               {
+                       Status = STATUS_INVALID_DEVICE_REQUEST;
+                       _SEH2_LEAVE;
+               }
+
+               //
+               //  Do flushing for such cases
+               //
+               if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) 
+               {
+#pragma prefast( suppress: 28137, "by design" )
+                       ExAcquireResourceExclusiveLite(&Fcb->MainResource, 
+                                       IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
+
+                       MainResourceAcquired = TRUE;
+
+                       ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
+                       ExReleaseResourceLite(&Fcb->PagingIoResource);
+
+                       CcFlushCache(&(Fcb->SectionObject),
+                                       &ByteOffset,
+                                       Length,
+                                       &(Irp->IoStatus));
+                       ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+
+                       if (!NT_SUCCESS(Irp->IoStatus.Status)) 
+                       {
+                               Status = Irp->IoStatus.Status;
+                               _SEH2_LEAVE;
+                       }
+
+                       ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
+                       ExReleaseResourceLite(&Fcb->PagingIoResource);
+
+                       CcPurgeCacheSection(&(Fcb->SectionObject),
+                                       (PLARGE_INTEGER)&(ByteOffset),
+                                       Length,
+                                       FALSE);
+
+                       ExReleaseResourceLite(&Fcb->MainResource);
+                       MainResourceAcquired = FALSE;
+               }
+
+               if (!PagingIo)
+               {
+#pragma prefast( suppress: 28137, "by design" )
+                       if (!ExAcquireResourceExclusiveLite(
+                                               &Fcb->MainResource,
+                                               IrpContext->IsSynchronous))
+                       {
+                               Status = STATUS_PENDING;
+                               _SEH2_LEAVE;
+                       }
+
+                       MainResourceAcquired = TRUE;
+               }
+               else
+               {
+                       /*
+                       ULONG ResShCnt, ResExCnt; 
+                       ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource);
+                       ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource);
+
+                       FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n",
+                       Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous));
+                       */
+                       if (!ExAcquireResourceSharedLite(
+                                               &Fcb->PagingIoResource,
+                                               IrpContext->IsSynchronous))
+                       {
+                               Status = STATUS_PENDING;
+                               _SEH2_LEAVE;
+                       }
+
+                       PagingIoResourceAcquired = TRUE;
+               }
+
+               if (!PagingIo)
+               {
+                       if (!FsRtlCheckLockForWriteAccess(
+                                               &Fcb->FileLockAnchor,
+                                               Irp))
+                       {
+                               Status = STATUS_FILE_LOCK_CONFLICT;
+                               _SEH2_LEAVE;
+                       }
+               }
+
+               if (Nocache)
+               {
+                       if ((ByteOffset.QuadPart + Length) >
+                                       Fcb->Header.AllocationSize.QuadPart)
+                       {
+                               if (ByteOffset.QuadPart >= 
+                                               Fcb->Header.AllocationSize.QuadPart)
+                               {
+                                       Status = STATUS_SUCCESS;
+                                       Irp->IoStatus.Information = 0;
+                                       _SEH2_LEAVE;
+                               }
+                               else
+                               {
+                                       if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart
+                                                               - ByteOffset.QuadPart))
+                                       {
+                                               Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart
+                                                               - ByteOffset.QuadPart);
+                                       }
+                               }
+                       }
+               }
+
+               if (!Nocache)
+               {
+                       if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
+                       {
+                               _SEH2_LEAVE;
+                       }
+
+                       if (FileObject->PrivateCacheMap == NULL)
+                       {
+                               CcInitializeCacheMap(
+                                               FileObject,
+                                               (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
+                                               FALSE,
+                                               &FFSGlobal->CacheManagerCallbacks,
+                                               Fcb);
+
+                               CcSetReadAheadGranularity(
+                                               FileObject,
+                                               READ_AHEAD_GRANULARITY);
+
+                               CcSetFileSizes(
+                                               FileObject, 
+                                               (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
+                       }
+
+                       CacheObject = FileObject;
+
+                       //
+                       //  Need extending the size of inode ?
+                       //
+                       if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) >
+                                               (ULONG)(Fcb->Header.FileSize.QuadPart)))
+                       {
+
+                               LARGE_INTEGER   ExtendSize;
+                               LARGE_INTEGER   FileSize;
+
+                               bNeedExtending = TRUE;
+                               FileSize = Fcb->Header.FileSize;
+                               ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);
+
+                               if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart)
+                               {
+                                       if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize))
+                                       {
+                                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                                               _SEH2_LEAVE;
+                                       }
+                               }
+
+                               {
+                                       Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart;
+                                       Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart;
+                               }
+
+                               if (FileObject->PrivateCacheMap)
+                               {
+                                       CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
+
+                                       if (ByteOffset.QuadPart > FileSize.QuadPart)
+                                       {
+                                               FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, 
+                                                               ByteOffset.QuadPart - FileSize.QuadPart);
+                                       }
+
+                                       if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart)
+                                       {
+                                               FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, 
+                                                               Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart);
+                                       }
+                               }
+
+                               if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1))
+                               {
+                                       Status = STATUS_SUCCESS;
+                               }
+
+                               FFSNotifyReportChange(
+                                               IrpContext,
+                                               Vcb,
+                                               Fcb,
+                                               FILE_NOTIFY_CHANGE_SIZE,
+                                               FILE_ACTION_MODIFIED);
+                       }
+
+                       if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
+                       {
+                               CcPrepareMdlWrite(
+                                               CacheObject,
+                                               (&ByteOffset),
+                                               Length,
+                                               &Irp->MdlAddress,
+                                               &Irp->IoStatus);
+
+                               Status = Irp->IoStatus.Status;
+                       }
+                       else
+                       {
+                               Buffer = FFSGetUserBuffer(Irp);
+
+                               if (Buffer == NULL)
+                               {
+                                       FFSBreakPoint();
+                                       Status = STATUS_INVALID_USER_BUFFER;
+                                       _SEH2_LEAVE;
+                               }
+
+                               if (!CcCopyWrite(
+                                                       CacheObject,
+                                                       (PLARGE_INTEGER)&ByteOffset,
+                                                       Length,
+                                                       IrpContext->IsSynchronous,
+                                                       Buffer))
+                               {
+                                       Status = STATUS_PENDING;
+                                       _SEH2_LEAVE;
+                               }
+
+                               Status = Irp->IoStatus.Status;
+                       }
+
+                       if (NT_SUCCESS(Status))
+                       {
+                               Irp->IoStatus.Information = Length;
+
+                               if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
+                               {
+                                       FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n"));
+                                       FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject);
+                               }
+                       }
+               }
+               else
+               {
+                       ReturnedLength = Length;
+
+                       Status = FFSLockUserBuffer(
+                                       IrpContext->Irp,
+                                       Length,
+                                       IoReadAccess);
+
+                       if (!NT_SUCCESS(Status))
+                       {
+                               _SEH2_LEAVE;
+                       }
+
+                       Irp->IoStatus.Status = STATUS_SUCCESS;
+                       Irp->IoStatus.Information = Length;
+
+                       Status = 
+                               FFSv1WriteInode(
+                                               IrpContext,
+                                               Vcb,
+                                               Fcb->dinode1,
+                                               (ULONGLONG)(ByteOffset.QuadPart),
+                                               NULL,
+                                               Length,
+                                               TRUE,
+                                               &ReturnedLength);
+
+                       Irp = IrpContext->Irp;
+
+               }
+       }
+
+       _SEH2_FINALLY
+       {
+               if (PagingIoResourceAcquired)
+               {
+                       ExReleaseResourceForThreadLite(
+                                       &Fcb->PagingIoResource,
+                                       ExGetCurrentResourceThread());
+               }
+
+               if (MainResourceAcquired)
+               {
+                       ExReleaseResourceForThreadLite(
+                                       &Fcb->MainResource,
+                                       ExGetCurrentResourceThread());
+               }
+
+               if (!IrpContext->ExceptionInProgress)
+               {
+                       if (Irp)
+                       {
+                               if (Status == STATUS_PENDING)
+                               {
+                                       if (!bDeferred)
+                                       {
+                                               Status = FFSLockUserBuffer(
+                                                                       IrpContext->Irp,
+                                                                       Length,
+                                                                       IoReadAccess);
+
+                                               if (NT_SUCCESS(Status))
+                                               {
+                                                       Status = FFSQueueRequest(IrpContext);
+                                               }
+                                               else
+                                               {
+                                                       FFSCompleteIrpContext(IrpContext, Status);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       if (NT_SUCCESS(Status))
+                                       {
+                                               if (SynchronousIo && !PagingIo)
+                                               {
+                                                       FileObject->CurrentByteOffset.QuadPart =
+                                                               ByteOffset.QuadPart + Irp->IoStatus.Information;
+                                               }
+
+                                               if (!PagingIo)
+                                               {
+                                                       SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+                                                       SetFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+                                               }
+                                       }
+
+                                       FFSCompleteIrpContext(IrpContext, Status);
+                               }
+                       }
+                       else
+                       {
+                               FFSFreeIrpContext(IrpContext);
+                       }
+               }
+       } _SEH2_END;
+
+       return Status;
+
+}
+
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSWriteComplete(
+       IN PFFS_IRP_CONTEXT IrpContext)
+{
+       NTSTATUS        Status = STATUS_UNSUCCESSFUL;
+       PFILE_OBJECT    FileObject;
+       PIRP            Irp;
+       PIO_STACK_LOCATION IrpSp;
+
+    PAGED_CODE();
+
+       _SEH2_TRY
+       {
+               ASSERT(IrpContext);
+
+               ASSERT((IrpContext->Identifier.Type == FFSICX) &&
+                               (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
+
+               FileObject = IrpContext->FileObject;
+
+               Irp = IrpContext->Irp;
+               IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+               CcMdlWriteComplete(FileObject, &(IrpSp->Parameters.Write.ByteOffset), Irp->MdlAddress);
+
+               Irp->MdlAddress = NULL;
+
+               Status = STATUS_SUCCESS;
+       }
+
+       _SEH2_FINALLY
+       {
+               if (!IrpContext->ExceptionInProgress)
+               {
+                       FFSCompleteIrpContext(IrpContext, Status);
+               }
+       } _SEH2_END;
+
+       return Status;
+}
+
+
+__drv_mustHoldCriticalRegion
+NTSTATUS
+FFSWrite(
+       IN PFFS_IRP_CONTEXT IrpContext)
+{
+       NTSTATUS            Status;
+       PFFS_FCBVCB         FcbOrVcb;
+       PDEVICE_OBJECT      DeviceObject;
+       PFILE_OBJECT        FileObject;
+       PFFS_VCB            Vcb;
+       BOOLEAN             bCompleteRequest = TRUE;
+
+    PAGED_CODE();
+
+       ASSERT(IrpContext);
+
+       ASSERT((IrpContext->Identifier.Type == FFSICX) &&
+                       (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
+
+       _SEH2_TRY
+       {
+               if (FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE))
+               {
+                       Status = FFSWriteComplete(IrpContext);
+                       bCompleteRequest = FALSE;
+               }
+               else
+               {
+                       DeviceObject = IrpContext->DeviceObject;
+
+                       if (DeviceObject == FFSGlobal->DeviceObject)
+                       {
+                               Status = STATUS_INVALID_DEVICE_REQUEST;
+                               _SEH2_LEAVE;
+                       }
+
+                       Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;
+
+                       if (Vcb->Identifier.Type != FFSVCB ||
+                                       Vcb->Identifier.Size != sizeof(FFS_VCB))
+                       {
+                               Status = STATUS_INVALID_PARAMETER;
+                               _SEH2_LEAVE;
+                       }
+
+                       ASSERT(IsMounted(Vcb));
+
+                       if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))
+                       {
+                               Status = STATUS_TOO_LATE;
+                               _SEH2_LEAVE;
+                       }
+
+                       if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
+                       {
+                               Status = STATUS_MEDIA_WRITE_PROTECTED;
+                               _SEH2_LEAVE;
+                       }
+
+                       FileObject = IrpContext->FileObject;
+
+                       FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext;
+
+                       if (FcbOrVcb->Identifier.Type == FFSVCB)
+                       {
+                               Status = FFSWriteVolume(IrpContext);
+
+                               if (!NT_SUCCESS(Status))
+                               {
+                                       FFSBreakPoint();
+                               }
+
+                               bCompleteRequest = FALSE;
+                       }
+                       else if (FcbOrVcb->Identifier.Type == FFSFCB)
+                       {
+                               Status = FFSWriteFile(IrpContext);
+
+                               if (!NT_SUCCESS(Status))
+                               {
+                                       FFSBreakPoint();
+                               }
+
+                               bCompleteRequest = FALSE;
+                       }
+                       else
+                       {
+                               Status = STATUS_INVALID_PARAMETER;
+                       }
+               }
+       }
+
+       _SEH2_FINALLY
+       {
+               if (bCompleteRequest)
+               {
+                       FFSCompleteIrpContext(IrpContext, Status);
+               }
+       } _SEH2_END;
+
+       return Status;
+}
+
+#endif // !FFS_READ_ONLY