📄 swapbuffers.c
字号:
workingName = &volProp->FileSystemDeviceName;
} else {
//
// No name, don't save the context
//
status = STATUS_FLT_DO_NOT_ATTACH;
leave;
}
//
// Get size of buffer to allocate. This is the length of the
// string plus room for a trailing colon.
//
size = workingName->Length + sizeof(WCHAR);
//
// Now allocate a buffer to hold this name
//
ctx->Name.Buffer = ExAllocatePoolWithTag( NonPagedPool,
size,
NAME_TAG );
if (ctx->Name.Buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
//
// Init the rest of the fields
//
ctx->Name.Length = 0;
ctx->Name.MaximumLength = size;
//
// Copy the name in
//
RtlCopyUnicodeString( &ctx->Name,
workingName );
//
// Put a trailing colon to make the display look good
//
RtlAppendUnicodeToString( &ctx->Name,
L":" );
}
//
// Set the context
//
status = FltSetVolumeContext( FltObjects->Volume,
FLT_SET_CONTEXT_KEEP_IF_EXISTS,
ctx,
NULL );
//
// Log debug info
//
LOG_PRINT( LOGFL_VOLCTX,
("SwapBuffers!InstanceSetup: Real SectSize=0x%04x, Used SectSize=0x%04x, Name=\"%wZ\"\n",
volProp->SectorSize,
ctx->SectorSize,
&ctx->Name) );
//
// It is OK for the context to already be defined.
//
if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) {
status = STATUS_SUCCESS;
}
} finally {
//
// Always release the context. If the set failed, it will free the
// context. If not, it will remove the reference added by the set.
// Note that the name buffer in the ctx will get freed by the context
// cleanup routine.
//
if (ctx) {
FltReleaseContext( ctx );
}
//
// Remove the reference added to the device object by
// FltGetDiskDeviceObject.
//
if (devObj) {
ObDereferenceObject( devObj );
}
}
return status;
}
VOID
CleanupVolumeContext(
IN PFLT_CONTEXT Context,
IN FLT_CONTEXT_TYPE ContextType
)
/*++
Routine Description:
The given context is being freed.
Free the allocated name buffer if there one.
Arguments:
Context - The context being freed
ContextType - The type of context this is
Return Value:
None
--*/
{
PVOLUME_CONTEXT ctx = Context;
UNREFERENCED_PARAMETER( ContextType );
ASSERT(ContextType == FLT_VOLUME_CONTEXT);
if (ctx->Name.Buffer != NULL) {
ExFreePool(ctx->Name.Buffer);
ctx->Name.Buffer = NULL;
}
}
NTSTATUS
InstanceQueryTeardown (
IN PCFLT_RELATED_OBJECTS FltObjects,
IN FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
)
/*++
Routine Description:
This is called when an instance is being manually deleted by a
call to FltDetachVolume or FilterDetach. We always return it is OK to
detach.
Arguments:
FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
opaque handles to this filter, instance and its associated volume.
Flags - Indicating where this detach request came from.
Return Value:
Always succeed.
--*/
{
UNREFERENCED_PARAMETER( FltObjects );
UNREFERENCED_PARAMETER( Flags );
return STATUS_SUCCESS;
}
/*************************************************************************
Initialization and unload routines.
*************************************************************************/
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the initialization routine. This registers with FltMgr and
initializes all global data structures.
Arguments:
DriverObject - Pointer to driver object created by the system to
represent this driver.
RegistryPath - Unicode string identifying where the parameters for this
driver are located in the registry.
Return Value:
Status of the operation
--*/
{
NTSTATUS status;
//
// Get debug trace flags
//
ReadDriverParameters( RegistryPath );
//
// Init lookaside list used to allocate our context structure used to
// pass information from out preOperation callback to our postOperation
// callback.
//
ExInitializeNPagedLookasideList( &Pre2PostContextList,
NULL,
NULL,
0,
sizeof(PRE_2_POST_CONTEXT),
PRE_2_POST_TAG,
0 );
//
// Register with FltMgr
//
status = FltRegisterFilter( DriverObject,
&FilterRegistration,
&gFilterHandle );
if (NT_SUCCESS( status )) {
//
// Start filtering i/o
//
status = FltStartFiltering( gFilterHandle );
if (!NT_SUCCESS( status )) {
FltUnregisterFilter( gFilterHandle );
}
}
return status;
}
NTSTATUS
FilterUnload (
FLT_FILTER_UNLOAD_FLAGS Flags
)
/*++
Routine Description:
Called when this mini-filter is about to be unloaded. We unregister
from the FltMgr and then return it is OK to unload
Arguments:
Flags - Indicating if this is a mandatory unload.
Return Value:
Returns the final status of this operation.
--*/
{
UNREFERENCED_PARAMETER( Flags );
//
// Unregister from FLT mgr
//
FltUnregisterFilter( gFilterHandle );
//
// Delete lookaside list
//
ExDeleteNPagedLookasideList( &Pre2PostContextList );
return STATUS_SUCCESS;
}
/*************************************************************************
MiniFilter callback routines.
*************************************************************************/
FLT_PREOP_CALLBACK_STATUS
SwapPreReadBuffers(
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
)
/*++
Routine Description:
This routine demonstrates how to swap buffers for the READ operation.
Note that it handles all errors by simply not doing the buffer swap.
Arguments:
Data - Pointer to the filter callbackData that is passed to us.
FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
opaque handles to this filter, instance, its associated volume and
file object.
CompletionContext - Receives the context that will be passed to the
post-operation callback.
Return Value:
FLT_PREOP_SUCCESS_WITH_CALLBACK - we want a postOpeation callback
FLT_PREOP_SUCCESS_NO_CALLBACK - we don't want a postOperation callback
--*/
{
PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb;
FLT_PREOP_CALLBACK_STATUS retValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
PVOID newBuf = NULL;
PMDL newMdl = NULL;
PVOLUME_CONTEXT volCtx = NULL;
PPRE_2_POST_CONTEXT p2pCtx;
NTSTATUS status;
ULONG readLen = iopb->Parameters.Read.Length;
try {
//
// If they are trying to read ZERO bytes, then don't do anything and
// we don't need a post-operation callback.
//
if (readLen == 0) {
leave;
}
//
// Get our volume context so we can display our volume name in the
// debug output.
//
status = FltGetVolumeContext( FltObjects->Filter,
FltObjects->Volume,
&volCtx );
if (!NT_SUCCESS(status)) {
LOG_PRINT( LOGFL_ERRORS,
("SwapBuffers!SwapPreReadBuffers: Error getting volume context, status=%x\n",
status) );
leave;
}
//
// If this is a non-cached I/O we need to round the length up to the
// sector size for this device. We must do this because the file
// systems do this and we need to make sure our buffer is as big
// as they are expecting.
//
if (FlagOn(IRP_NOCACHE,iopb->IrpFlags)) {
readLen = (ULONG)ROUND_TO_SIZE(readLen,volCtx->SectorSize);
}
//
// Allocate nonPaged memory for the buffer we are swapping to.
// If we fail to get the memory, just don't swap buffers on this
// operation.
//
newBuf = ExAllocatePoolWithTag( NonPagedPool,
readLen,
BUFFER_SWAP_TAG );
if (newBuf == NULL) {
LOG_PRINT( LOGFL_ERRORS,
("SwapBuffers!SwapPreReadBuffers: %wZ Failed to allocate %d bytes of memory\n",
&volCtx->Name,
readLen) );
leave;
}
//
// We only need to build a MDL for IRP operations. We don't need to
// do this for a FASTIO operation since the FASTIO interface has no
// parameter for passing the MDL to the file system.
//
if (FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_IRP_OPERATION)) {
//
// Allocate a MDL for the new allocated memory. If we fail
// the MDL allocation then we won't swap buffer for this operation
//
newMdl = IoAllocateMdl( newBuf,
readLen,
FALSE,
FALSE,
NULL );
if (newMdl == NULL) {
LOG_PRINT( LOGFL_ERRORS,
("SwapBuffers!SwapPreReadBuffers: %wZ Failed to allocate MDL\n",
&volCtx->Name) );
leave;
}
//
// setup the MDL for the non-paged pool we just allocated
//
MmBuildMdlForNonPagedPool( newMdl );
}
//
// We are ready to swap buffers, get a pre2Post context structure.
// We need it to pass the volume context and the allocate memory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -