📄 write.c
字号:
/*
* COPYRIGHT: See COPYRIGHT.TXT
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
* FILE: write.c
* PROGRAMMER: Matt Wu <mattwu@163.com>
* HOMEPAGE: http://ext2.yeah.net
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include "ntifs.h"
#include "ext2fs.h"
/* GLOBALS ***************************************************************/
extern PEXT2_GLOBAL gExt2Global;
/* DEFINITIONS *************************************************************/
NTSTATUS
Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext);
NTSTATUS
Ext2WriteFile (IN PEXT2_IRP_CONTEXT IrpContext);
NTSTATUS
Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, Ext2ZeroHoles)
#pragma alloc_text(PAGE, Ext2Write)
#pragma alloc_text(PAGE, Ext2WriteVolume)
#pragma alloc_text(PAGE, Ext2WriteInode)
#pragma alloc_text(PAGE, Ext2WriteFile)
#pragma alloc_text(PAGE, Ext2WriteComplete)
#pragma alloc_text(PAGE, Ext2SupersedeOrOverWriteFile)
#pragma alloc_text(PAGE, Ext2IsDirectoryEmpty)
#pragma alloc_text(PAGE, Ext2DeleteFile)
#endif
/* FUNCTIONS *************************************************************/
BOOLEAN
Ext2ZeroHoles (
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
IN PFILE_OBJECT FileObject,
IN LONGLONG Offset,
IN LONGLONG Count
)
{
LARGE_INTEGER StartAddr = {0,0};
LARGE_INTEGER EndAddr = {0,0};
StartAddr.QuadPart = (Offset + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
EndAddr.QuadPart = (Offset + Count + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
if (StartAddr.QuadPart < EndAddr.QuadPart)
{
return CcZeroData( FileObject,
&StartAddr,
&EndAddr,
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
}
return TRUE;
}
NTSTATUS
Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PEXT2_VCB Vcb;
PEXT2_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;
PUCHAR Buffer;
__try
{
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
FileObject = IrpContext->FileObject;
FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
ASSERT(FcbOrVcb);
if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb))
{
Status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
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);
Ext2DbgPrint(D_WRITE, "Ext2WriteVolume: Len=%xh Off=%I64x Paging=%xh Nocache=%xh\n", Length, ByteOffset.QuadPart, PagingIo, Nocache);
if (Length == 0)
{
Irp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
__leave;
}
if (Nocache &&
(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
Length & (SECTOR_SIZE - 1)))
{
Status = STATUS_INVALID_PARAMETER;
__leave;
}
if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
{
ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
Status = STATUS_PENDING;
__leave;
}
if (ByteOffset.QuadPart >=
Vcb->PartitionInformation.PartitionLength.QuadPart )
{
Irp->IoStatus.Information = 0;
Status = STATUS_END_OF_FILE;
__leave;
}
if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL))
{
ExAcquireResourceExclusive(&Vcb->MainResource, TRUE);
MainResourceAcquired = TRUE;
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
ExReleaseResource(&Vcb->PagingIoResource);
CcFlushCache( &(Vcb->SectionObject),
&ByteOffset,
Length,
&(Irp->IoStatus));
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
Status = Irp->IoStatus.Status;
__leave;
}
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
ExReleaseResource(&Vcb->PagingIoResource);
CcPurgeCacheSection( &(Vcb->SectionObject),
(PLARGE_INTEGER)&(ByteOffset),
Length,
FALSE );
ExReleaseResource(&Vcb->MainResource);
MainResourceAcquired = FALSE;
}
if (!PagingIo)
{
if (!ExAcquireResourceSharedLite(
&Vcb->MainResource,
IrpContext->IsSynchronous ))
{
Status = STATUS_PENDING;
__leave;
}
MainResourceAcquired = TRUE;
}
else
{
if (!ExAcquireResourceSharedLite(
&Vcb->PagingIoResource,
IrpContext->IsSynchronous ))
{
Status = STATUS_PENDING;
__leave;
}
PagingIoResourceAcquired = TRUE;
}
if (!Nocache)
{
if ((ByteOffset.QuadPart + Length) >
Vcb->PartitionInformation.PartitionLength.QuadPart
)
{
Length = (ULONG) (
Vcb->PartitionInformation.PartitionLength.QuadPart -
ByteOffset.QuadPart);
Length &= ~(SECTOR_SIZE - 1);
}
if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
{
CcPrepareMdlWrite (
Vcb->StreamObj,
&ByteOffset,
Length,
&Irp->MdlAddress,
&Irp->IoStatus );
Status = Irp->IoStatus.Status;
}
else
{
PBCB Bcb;
PVOID Buf;
Buffer = Ext2GetUserBuffer(Irp);
if (Buffer == NULL)
{
Status = STATUS_INVALID_USER_BUFFER;
__leave;
}
CcPreparePinWrite(
Vcb->StreamObj,
&ByteOffset,
Length,
FALSE,
TRUE,
&Bcb,
&Buf );
RtlCopyMemory(Buf, Buffer, Length);
CcUnpinData(Bcb);
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status))
Irp->IoStatus.Information = Length;
}
else
{
PEXT2_BDL ext2_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 &= ~(SECTOR_SIZE - 1);
}
Status = Ext2LockUserBuffer(
IrpContext->Irp,
Length,
IoReadAccess );
if (!NT_SUCCESS(Status))
{
__leave;
}
ext2_bdl = ExAllocatePool(PagedPool, (Length / Vcb->ext2_block) * sizeof(EXT2_BDL));
if (!ext2_bdl)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
DirtyLba = ByteOffset.QuadPart;
RemainLength = (LONGLONG) Length;
while (RemainLength > 0)
{
DirtyStart = DirtyLba;
if (Ext2LookupMcbEntry(Vcb, DirtyStart, &DirtyLba, &DirtyLength,
(PLONGLONG)NULL, (PLONGLONG)NULL, (PULONG)NULL))
{
if (DirtyLba == -1)
{
DirtyLba = DirtyStart + DirtyLength;
RemainLength = ByteOffset.QuadPart + (LONGLONG)Length - DirtyLba;
continue;
}
ext2_bdl[Blocks].Irp = NULL;
ext2_bdl[Blocks].Lba = DirtyLba;
ext2_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length - RemainLength - (DirtyLba - DirtyStart));
if (DirtyLba + DirtyLength > DirtyStart + RemainLength)
{
ext2_bdl[Blocks].Length = (ULONG)(DirtyStart + RemainLength - DirtyLba);
RemainLength = 0;
}
else
{
ext2_bdl[Blocks].Length = (ULONG)DirtyLength;
RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength);
}
DirtyLba = DirtyStart + DirtyLength;
Blocks++;
}
else
{
if (Blocks == 0)
{
if (ext2_bdl)
ExFreePool(ext2_bdl);
// Lookup fails at the first time, ie. no dirty blocks in the run
if (RemainLength == (LONGLONG)Length)
Status = STATUS_SUCCESS;
else
Status = STATUS_UNSUCCESSFUL;
__leave;
}
else
{
break;
}
}
}
if (Blocks > 0)
{
Status = Ext2ReadWriteBlocks(IrpContext,
Vcb,
ext2_bdl,
Length,
Blocks,
FALSE );
Irp = IrpContext->Irp;
if (NT_SUCCESS(Status))
{
ULONG i;
for (i=0; i<Blocks;i++)
Ext2RemoveMcbEntry(Vcb, ext2_bdl[i].Lba, ext2_bdl[i].Length);
}
if (ext2_bdl)
ExFreePool(ext2_bdl);
if (!Irp)
__leave;
}
else
{
if (ext2_bdl)
ExFreePool(ext2_bdl);
Status = STATUS_SUCCESS;
__leave;
}
}
}
__finally
{
if (PagingIoResourceAcquired)
{
ExReleaseResourceForThreadLite(
&Vcb->PagingIoResource,
ExGetCurrentResourceThread());
}
if (MainResourceAcquired)
{
ExReleaseResourceForThreadLite(
&Vcb->MainResource,
ExGetCurrentResourceThread());
}
if (!IrpContext->ExceptionInProgress)
{
if (Irp)
{
if (Status == STATUS_PENDING)
{
Status = Ext2LockUserBuffer(
IrpContext->Irp,
Length,
IoReadAccess );
if (NT_SUCCESS(Status))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -