📄 swapbuffers.c
字号:
/*++
Copyright (c) 1999 - 2002 Microsoft Corporation
Module Name:
SwapBuffers.c
Abstract:
This is a sample filter which demonstrates proper access of data buffer
and a general guideline of how to swap buffers.
For now it only swaps buffers for:
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_DIRECTORY_CONTROL
By default this filter attaches to all volumes it is notified about. It
does support having multiple instances on a given volume.
Environment:
Kernel mode
--*/
#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>
#pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")
PFLT_FILTER gFilterHandle;
/*************************************************************************
Pool Tags
*************************************************************************/
#define BUFFER_SWAP_TAG 'bdBS'
#define CONTEXT_TAG 'xcBS'
#define NAME_TAG 'mnBS'
#define PRE_2_POST_TAG 'ppBS'
/*************************************************************************
Local structures
*************************************************************************/
//
// This is a volume context, one of these are attached to each volume
// we monitor. This is used to get a "DOS" name for debug display.
//
typedef struct _VOLUME_CONTEXT {
//
// Holds the name to display
//
UNICODE_STRING Name;
//
// Holds the sector size for this volume.
//
ULONG SectorSize;
} VOLUME_CONTEXT, *PVOLUME_CONTEXT;
#define MIN_SECTOR_SIZE 0x200
//
// This is a context structure that is used to pass state from our
// pre-operation callback to our post-operation callback.
//
typedef struct _PRE_2_POST_CONTEXT {
//
// Pointer to our volume context structure. We always get the context
// in the preOperation path because you can not safely get it at DPC
// level. We then release it in the postOperation path. It is safe
// to release contexts at DPC level.
//
PVOLUME_CONTEXT VolCtx;
//
// Since the post-operation parameters always receive the "original"
// parameters passed to the operation, we need to pass our new destination
// buffer to our post operation routine so we can free it.
//
PVOID SwappedBuffer;
} PRE_2_POST_CONTEXT, *PPRE_2_POST_CONTEXT;
//
// This is a lookAside list used to allocate our pre-2-post structure.
//
NPAGED_LOOKASIDE_LIST Pre2PostContextList;
/*************************************************************************
Prototypes
*************************************************************************/
NTSTATUS
InstanceSetup (
__in PCFLT_RELATED_OBJECTS FltObjects,
__in FLT_INSTANCE_SETUP_FLAGS Flags,
__in DEVICE_TYPE VolumeDeviceType,
__in FLT_FILESYSTEM_TYPE VolumeFilesystemType
);
VOID
CleanupVolumeContext(
__in PFLT_CONTEXT Context,
__in FLT_CONTEXT_TYPE ContextType
);
NTSTATUS
InstanceQueryTeardown (
__in PCFLT_RELATED_OBJECTS FltObjects,
__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
);
NTSTATUS
DriverEntry (
__in PDRIVER_OBJECT DriverObject,
__in PUNICODE_STRING RegistryPath
);
NTSTATUS
FilterUnload (
__in FLT_FILTER_UNLOAD_FLAGS Flags
);
FLT_PREOP_CALLBACK_STATUS
SwapPreReadBuffers(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
);
FLT_POSTOP_CALLBACK_STATUS
SwapPostReadBuffers(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
);
FLT_POSTOP_CALLBACK_STATUS
SwapPostReadBuffersWhenSafe (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
);
FLT_PREOP_CALLBACK_STATUS
SwapPreDirCtrlBuffers(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
);
FLT_POSTOP_CALLBACK_STATUS
SwapPostDirCtrlBuffers(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
);
FLT_POSTOP_CALLBACK_STATUS
SwapPostDirCtrlBuffersWhenSafe (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
);
FLT_PREOP_CALLBACK_STATUS
SwapPreWriteBuffers(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
);
FLT_POSTOP_CALLBACK_STATUS
SwapPostWriteBuffers(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
);
VOID
ReadDriverParameters (
__in PUNICODE_STRING RegistryPath
);
//
// Assign text sections for each routine.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, InstanceSetup)
#pragma alloc_text(PAGE, CleanupVolumeContext)
#pragma alloc_text(PAGE, InstanceQueryTeardown)
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(INIT, ReadDriverParameters)
#pragma alloc_text(PAGE, FilterUnload)
#endif
//
// Operation we currently care about.
//
CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_READ,
0,
SwapPreReadBuffers,
SwapPostReadBuffers },
{ IRP_MJ_WRITE,
0,
SwapPreWriteBuffers,
SwapPostWriteBuffers },
{ IRP_MJ_DIRECTORY_CONTROL,
0,
SwapPreDirCtrlBuffers,
SwapPostDirCtrlBuffers },
{ IRP_MJ_OPERATION_END }
};
//
// Context definitions we currently care about. Note that the system will
// create a lookAside list for the volume context because an explicit size
// of the context is specified.
//
CONST FLT_CONTEXT_REGISTRATION ContextNotifications[] = {
{ FLT_VOLUME_CONTEXT,
0,
CleanupVolumeContext,
sizeof(VOLUME_CONTEXT),
CONTEXT_TAG },
{ FLT_CONTEXT_END }
};
//
// This defines what we want to filter with FltMgr
//
CONST FLT_REGISTRATION FilterRegistration = {
sizeof( FLT_REGISTRATION ), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
ContextNotifications, // Context
Callbacks, // Operation callbacks
FilterUnload, // MiniFilterUnload
InstanceSetup, // InstanceSetup
InstanceQueryTeardown, // InstanceQueryTeardown
NULL, // InstanceTeardownStart
NULL, // InstanceTeardownComplete
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
/*************************************************************************
Debug tracing information
*************************************************************************/
//
// Definitions to display log messages. The registry DWORD entry:
// "hklm\system\CurrentControlSet\Services\Swapbuffers\DebugFlags" defines
// the default state of these logging flags
//
#define LOGFL_ERRORS 0x00000001 // if set, display error messages
#define LOGFL_READ 0x00000002 // if set, display READ operation info
#define LOGFL_WRITE 0x00000004 // if set, display WRITE operation info
#define LOGFL_DIRCTRL 0x00000008 // if set, display DIRCTRL operation info
#define LOGFL_VOLCTX 0x00000010 // if set, display VOLCTX operation info
ULONG LoggingFlags = 0; // all disabled by default
#define LOG_PRINT( _logFlag, _string ) \
(FlagOn(LoggingFlags,(_logFlag)) ? \
DbgPrint _string : \
((void)0))
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// Routines
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
NTSTATUS
InstanceSetup (
__in PCFLT_RELATED_OBJECTS FltObjects,
__in FLT_INSTANCE_SETUP_FLAGS Flags,
__in DEVICE_TYPE VolumeDeviceType,
__in FLT_FILESYSTEM_TYPE VolumeFilesystemType
)
/*++
Routine Description:
This routine is called whenever a new instance is created on a volume.
By default we want to attach to all volumes. This routine will try and
get a "DOS" name for the given volume. If it can't, it will try and
get the "NT" name for the volume (which is what happens on network
volumes). If a name is retrieved a volume context will be created with
that name.
Arguments:
FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
opaque handles to this filter, instance and its associated volume.
Flags - Flags describing the reason for this attach request.
Return Value:
STATUS_SUCCESS - attach
STATUS_FLT_DO_NOT_ATTACH - do not attach
--*/
{
PDEVICE_OBJECT devObj = NULL;
PVOLUME_CONTEXT ctx = NULL;
NTSTATUS status;
ULONG retLen;
PUNICODE_STRING workingName;
USHORT size;
UCHAR volPropBuffer[sizeof(FLT_VOLUME_PROPERTIES)+512];
PFLT_VOLUME_PROPERTIES volProp = (PFLT_VOLUME_PROPERTIES)volPropBuffer;
PAGED_CODE();
UNREFERENCED_PARAMETER( Flags );
UNREFERENCED_PARAMETER( VolumeDeviceType );
UNREFERENCED_PARAMETER( VolumeFilesystemType );
try {
//
// Allocate a volume context structure.
//
status = FltAllocateContext( FltObjects->Filter,
FLT_VOLUME_CONTEXT,
sizeof(VOLUME_CONTEXT),
NonPagedPool,
&ctx );
if (!NT_SUCCESS(status)) {
//
// We could not allocate a context, quit now
//
leave;
}
//
// Always get the volume properties, so I can get a sector size
//
status = FltGetVolumeProperties( FltObjects->Volume,
volProp,
sizeof(volPropBuffer),
&retLen );
if (!NT_SUCCESS(status)) {
leave;
}
//
// Save the sector size in the context for later use. Note that
// we will pick a minimum sector size if a sector size is not
// specified.
//
ASSERT((volProp->SectorSize == 0) || (volProp->SectorSize >= MIN_SECTOR_SIZE));
ctx->SectorSize = max(volProp->SectorSize,MIN_SECTOR_SIZE);
//
// Init the buffer field (which may be allocated later).
//
ctx->Name.Buffer = NULL;
//
// Get the storage device object we want a name for.
//
status = FltGetDiskDeviceObject( FltObjects->Volume, &devObj );
if (NT_SUCCESS(status)) {
//
// Try and get the DOS name. If it succeeds we will have
// an allocated name buffer. If not, it will be NULL
//
status = RtlVolumeDeviceToDosName( devObj, &ctx->Name );
}
//
// If we could not get a DOS name, get the NT name.
//
if (!NT_SUCCESS(status)) {
ASSERT(ctx->Name.Buffer == NULL);
//
// Figure out which name to use from the properties
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -