📄 write.c
字号:
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
Write.c
Abstract:
This module implements the File Write routine for Write called by the
dispatch driver.
--*/
#include "FatProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (FAT_BUG_CHECK_WRITE)
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_WRITE)
//
// Macros to increment the appropriate performance counters.
//
#define CollectWriteStats(VCB,OPEN_TYPE,BYTE_COUNT) { \
PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()].Common; \
if (((OPEN_TYPE) == UserFileOpen)) { \
Stats->UserFileWrites += 1; \
Stats->UserFileWriteBytes += (ULONG)(BYTE_COUNT); \
} else if (((OPEN_TYPE) == VirtualVolumeFile || ((OPEN_TYPE) == DirectoryFile))) { \
Stats->MetaDataWrites += 1; \
Stats->MetaDataWriteBytes += (ULONG)(BYTE_COUNT); \
} \
}
BOOLEAN FatNoAsync = FALSE;
//
// Local support routines
//
VOID
FatDeferredFlushDpc (
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
VOID
FatDeferredFlush (
PVOID Parameter
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatDeferredFlush)
#pragma alloc_text(PAGE, FatCommonWrite)
#endif
NTSTATUS
FatFsdWrite (
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine implements the FSD part of the NtWriteFile API call
Arguments:
VolumeDeviceObject - Supplies the volume device object where the
file being Write exists
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The FSD status for the IRP
--*/
{
PFCB Fcb;
NTSTATUS Status;
PIRP_CONTEXT IrpContext = NULL;
BOOLEAN ModWriter = FALSE;
BOOLEAN TopLevel;
DebugTrace(+1, Dbg, "FatFsdWrite\n", 0);
//
// Call the common Write routine, with blocking allowed if synchronous
//
FsRtlEnterFileSystem();
//
// We are first going to do a quick check for paging file IO. Since this
// is a fast path, we must replicate the check for the fsdo.
//
if (!FatDeviceIsFatFsdo( IoGetCurrentIrpStackLocation(Irp)->DeviceObject)) {
Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext);
if ((NodeType(Fcb) == FAT_NTC_FCB) &&
FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
//
// Do the usual STATUS_PENDING things.
//
IoMarkIrpPending( Irp );
//
// Perform the actual IO, it will be completed when the io finishes.
//
FatPagingFileIo( Irp, Fcb );
FsRtlExitFileSystem();
return STATUS_PENDING;
}
}
try {
TopLevel = FatIsIrpTopLevel( Irp );
IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
//
// This is a kludge for the mod writer case. The correct state
// of recursion is set in IrpContext, however, we much with the
// actual top level Irp field to get the correct WriteThrough
// behaviour.
//
if (IoGetTopLevelIrp() == (PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP) {
ModWriter = TRUE;
IoSetTopLevelIrp( Irp );
}
//
// If this is an Mdl complete request, don't go through
// common write.
//
if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {
DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 );
Status = FatCompleteMdl( IrpContext, Irp );
} else {
Status = FatCommonWrite( IrpContext, Irp );
}
} except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
//
// We had some trouble trying to perform the requested
// operation, so we'll abort the I/O request with
// the error status that we get back from the
// execption code
//
Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
}
// ASSERT( !(ModWriter && (Status == STATUS_CANT_WAIT)) );
ASSERT( !(ModWriter && TopLevel) );
if (ModWriter) { IoSetTopLevelIrp((PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP); }
if (TopLevel) { IoSetTopLevelIrp( NULL ); }
FsRtlExitFileSystem();
//
// And return to our caller
//
DebugTrace(-1, Dbg, "FatFsdWrite -> %08lx\n", Status);
UNREFERENCED_PARAMETER( VolumeDeviceObject );
return Status;
}
NTSTATUS
FatCommonWrite (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp
)
/*++
Routine Description:
This is the common write routine for NtWriteFile, called from both
the Fsd, or from the Fsp if a request could not be completed without
blocking in the Fsd. This routine's actions are
conditionalized by the Wait input parameter, which determines whether
it is allowed to block or not. If a blocking condition is encountered
with Wait == FALSE, however, the request is posted to the Fsp, who
always calls with WAIT == TRUE.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
--*/
{
PVCB Vcb;
PFCB FcbOrDcb;
PCCB Ccb;
VBO StartingVbo;
ULONG ByteCount;
ULONG FileSize;
ULONG InitialFileSize;
ULONG InitialValidDataLength;
PIO_STACK_LOCATION IrpSp;
PFILE_OBJECT FileObject;
TYPE_OF_OPEN TypeOfOpen;
BOOLEAN PostIrp = FALSE;
BOOLEAN OplockPostIrp = FALSE;
BOOLEAN ExtendingFile = FALSE;
BOOLEAN FcbOrDcbAcquired = FALSE;
BOOLEAN SwitchBackToAsync = FALSE;
BOOLEAN CalledByLazyWriter = FALSE;
BOOLEAN ExtendingValidData = FALSE;
BOOLEAN FcbAcquiredExclusive = FALSE;
BOOLEAN FcbCanDemoteToShared = FALSE;
BOOLEAN WriteFileSizeToDirent = FALSE;
BOOLEAN RecursiveWriteThrough = FALSE;
BOOLEAN UnwindOutstandingAsync = FALSE;
BOOLEAN PagingIoResourceAcquired = FALSE;
BOOLEAN SynchronousIo;
BOOLEAN WriteToEof;
BOOLEAN PagingIo;
BOOLEAN NonCachedIo;
BOOLEAN Wait;
NTSTATUS Status;
FAT_IO_CONTEXT StackFatIoContext;
//
// A system buffer is only used if we have to access the buffer directly
// from the Fsp to clear a portion or to do a synchronous I/O, or a
// cached transfer. It is possible that our caller may have already
// mapped a system buffer, in which case we must remember this so
// we do not unmap it on the way out.
//
PVOID SystemBuffer = (PVOID) NULL;
LARGE_INTEGER StartingByte;
//
// Get current Irp stack location and file object
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
FileObject = IrpSp->FileObject;
DebugTrace(+1, Dbg, "FatCommonWrite\n", 0);
DebugTrace( 0, Dbg, "Irp = %8lx\n", Irp);
DebugTrace( 0, Dbg, "ByteCount = %8lx\n", IrpSp->Parameters.Write.Length);
DebugTrace( 0, Dbg, "ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.LowPart);
DebugTrace( 0, Dbg, "ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.HighPart);
//
// Initialize the appropriate local variables.
//
Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
//ASSERT( PagingIo || FileObject->WriteAccess );
//
// Extract the bytecount and do our noop/throttle checking.
//
ByteCount = IrpSp->Parameters.Write.Length;
//
// If there is nothing to write, return immediately.
//
if (ByteCount == 0) {
Irp->IoStatus.Information = 0;
FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
return STATUS_SUCCESS;
}
//
// See if we have to defer the write.
//
if (!NonCachedIo &&
!CcCanIWrite(FileObject,
ByteCount,
(BOOLEAN)(Wait && !BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_IN_FSP)),
BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) {
BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE);
FatPrePostIrp( IrpContext, Irp );
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE );
CcDeferWrite( FileObject,
(PCC_POST_DEFERRED_WRITE)FatAddToWorkque,
IrpContext,
Irp,
ByteCount,
Retrying );
return STATUS_PENDING;
}
//
// Determine our starting position and type. If we are writing
// at EOF, then we will need additional synchronization before
// the IO is issued to determine where the data will go.
//
StartingByte = IrpSp->Parameters.Write.ByteOffset;
StartingVbo = StartingByte.LowPart;
WriteToEof = ( (StartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE) &&
(StartingByte.HighPart == -1) );
//
// Extract the nature of the write from the file object, and case on it
//
TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -