diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /filesys/miniFilter/swapBuffers | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'filesys/miniFilter/swapBuffers')
| -rw-r--r-- | filesys/miniFilter/swapBuffers/ReadMe.md | 15 | ||||
| -rw-r--r-- | filesys/miniFilter/swapBuffers/swapBuffers.c | 2334 | ||||
| -rw-r--r-- | filesys/miniFilter/swapBuffers/swapBuffers.inf | 95 | ||||
| -rw-r--r-- | filesys/miniFilter/swapBuffers/swapBuffers.rc | 10 | ||||
| -rw-r--r-- | filesys/miniFilter/swapBuffers/swapBuffers.sln | 28 | ||||
| -rw-r--r-- | filesys/miniFilter/swapBuffers/swapBuffers.vcxproj | 180 | ||||
| -rw-r--r-- | filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters | 31 |
7 files changed, 2693 insertions, 0 deletions
diff --git a/filesys/miniFilter/swapBuffers/ReadMe.md b/filesys/miniFilter/swapBuffers/ReadMe.md new file mode 100644 index 00000000..da19b5ed --- /dev/null +++ b/filesys/miniFilter/swapBuffers/ReadMe.md @@ -0,0 +1,15 @@ +SwapBuffer File System Minifilter Driver +======================================== + +The SwapBuffers minifilter demonstrates how to switch buffers between reads and writes of data. This technique is particularly useful for encryption filters because they have to encrypt data before writing it to disk and decrypt it after reading it from disk. Because encryption/decryption has to be done transparently, you cannot use system-supplied buffers directly, so intermediate buffers have to be introduced. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + +Design and Operation +-------------------- + +The *SwapBuffers* minifilter introduces a new buffer before a read/write or directory control operations. The corresponding operation is then performed on the new buffer instead of the buffer that was originally provided. After the operation completes, the contents of the new buffer are copied back in to the original buffer. + +For more information on file system minifilter design, start with the [File System Minifilter Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff540402) section in the Installable File Systems Design Guide. + diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.c b/filesys/miniFilter/swapBuffers/swapBuffers.c new file mode 100644 index 00000000..47893870 --- /dev/null +++ b/filesys/miniFilter/swapBuffers/swapBuffers.c @@ -0,0 +1,2334 @@ +/*++ + +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 + ); + +DRIVER_INITIALIZE DriverEntry; +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, + _Flt_CompletionContext_Outptr_ 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, + _Flt_CompletionContext_Outptr_ 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, + _Flt_CompletionContext_Outptr_ 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 : \ + ((int)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 = STATUS_SUCCESS; + 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. + // + + FLT_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 + // + +#pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "Used to maintain compatability with Win 2k") + status = RtlVolumeDeviceToDosName( devObj, &ctx->Name ); + } + + // + // If we could not get a DOS name, get the NT name. + // + + if (!NT_SUCCESS(status)) { + + FLT_ASSERT(ctx->Name.Buffer == NULL); + + // + // Figure out which name to use from the properties + // + + if (volProp->RealDeviceName.Length > 0) { + + workingName = &volProp->RealDeviceName; + + } else if (volProp->FileSystemDeviceName.Length > 0) { + + 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 + // + +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "ctx->Name.Buffer will not be leaked because it is freed in CleanupVolumeContext") + 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; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER( ContextType ); + + FLT_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. + +--*/ +{ + PAGED_CODE(); + + 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; + + // + // Default to NonPagedPoolNx for non paged pool allocations where supported. + // + + ExInitializeDriverRuntime( DrvRtPoolNxOptIn ); + + // + // 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 )) { + + goto SwapDriverEntryExit; + } + + // + // Start filtering i/o + // + + status = FltStartFiltering( gFilterHandle ); + + if (! NT_SUCCESS( status )) { + + FltUnregisterFilter( gFilterHandle ); + goto SwapDriverEntryExit; + } + +SwapDriverEntryExit: + + if(! NT_SUCCESS( status )) { + + ExDeleteNPagedLookasideList( &Pre2PostContextList ); + } + + return status; +} + + +NTSTATUS +FilterUnload ( + _In_ 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. + +--*/ +{ + PAGED_CODE(); + + 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( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ 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 aligned nonPaged memory for the buffer we are swapping + // to. This is really only necessary for noncached IO but we always + // do it here for simplification. If we fail to get the memory, just + // don't swap buffers on this operation. + // + + newBuf = FltAllocatePoolAlignedWithTag( FltObjects->Instance, + NonPagedPool, + (SIZE_T) 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 + // buffer to the post operation callback. + // + + p2pCtx = ExAllocateFromNPagedLookasideList( &Pre2PostContextList ); + + if (p2pCtx == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreReadBuffers: %wZ Failed to allocate pre2Post context structure\n", + &volCtx->Name) ); + + leave; + } + + // + // Log that we are swapping + // + + LOG_PRINT( LOGFL_READ, + ("SwapBuffers!SwapPreReadBuffers: %wZ newB=%p newMdl=%p oldB=%p oldMdl=%p len=%d\n", + &volCtx->Name, + newBuf, + newMdl, + iopb->Parameters.Read.ReadBuffer, + iopb->Parameters.Read.MdlAddress, + readLen) ); + + // + // Update the buffer pointers and MDL address, mark we have changed + // something. + // + + iopb->Parameters.Read.ReadBuffer = newBuf; + iopb->Parameters.Read.MdlAddress = newMdl; + FltSetCallbackDataDirty( Data ); + + // + // Pass state to our post-operation callback. + // + + p2pCtx->SwappedBuffer = newBuf; + p2pCtx->VolCtx = volCtx; + + *CompletionContext = p2pCtx; + + // + // Return we want a post-operation callback + // + + retValue = FLT_PREOP_SUCCESS_WITH_CALLBACK; + + } finally { + + // + // If we don't want a post-operation callback, then cleanup state. + // + + if (retValue != FLT_PREOP_SUCCESS_WITH_CALLBACK) { + + if (newBuf != NULL) { + + FltFreePoolAlignedWithTag( FltObjects->Instance, + newBuf, + BUFFER_SWAP_TAG ); + } + + if (newMdl != NULL) { + + IoFreeMdl( newMdl ); + } + + if (volCtx != NULL) { + + FltReleaseContext( volCtx ); + } + } + } + + return retValue; +} + + +FLT_POSTOP_CALLBACK_STATUS +SwapPostReadBuffers( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine does postRead buffer swap handling + +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 - The completion context set in the pre-operation routine. + + Flags - Denotes whether the completion is successful or is being drained. + +Return Value: + + FLT_POSTOP_FINISHED_PROCESSING + FLT_POSTOP_MORE_PROCESSING_REQUIRED + +--*/ +{ + PVOID origBuf; + PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; + FLT_POSTOP_CALLBACK_STATUS retValue = FLT_POSTOP_FINISHED_PROCESSING; + PPRE_2_POST_CONTEXT p2pCtx = CompletionContext; + BOOLEAN cleanupAllocatedBuffer = TRUE; + + // + // This system won't draining an operation with swapped buffers, verify + // the draining flag is not set. + // + + FLT_ASSERT(!FlagOn(Flags, FLTFL_POST_OPERATION_DRAINING)); + + try { + + // + // If the operation failed or the count is zero, there is no data to + // copy so just return now. + // + + if (!NT_SUCCESS(Data->IoStatus.Status) || + (Data->IoStatus.Information == 0)) { + + LOG_PRINT( LOGFL_READ, + ("SwapBuffers!SwapPostReadBuffers: %wZ newB=%p No data read, status=%x, info=%Iu\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Status, + Data->IoStatus.Information) ); + + leave; + } + + // + // We need to copy the read data back into the users buffer. Note + // that the parameters passed in are for the users original buffers + // not our swapped buffers. + // + + if (iopb->Parameters.Read.MdlAddress != NULL) { + + // + // This should be a simple MDL. We don't expect chained MDLs + // this high up the stack + // + + FLT_ASSERT( ((PMDL)iopb->Parameters.Read.MdlAddress)->Next == NULL); + + // + // Since there is a MDL defined for the original buffer, get a + // system address for it so we can copy the data back to it. + // We must do this because we don't know what thread context + // we are in. + // + + origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.Read.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (origBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostReadBuffers: %wZ Failed to get system address for MDL: %p\n", + &p2pCtx->VolCtx->Name, + iopb->Parameters.Read.MdlAddress) ); + + // + // If we failed to get a SYSTEM address, mark that the read + // failed and return. + // + + Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Data->IoStatus.Information = 0; + leave; + } + + } else if (FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_SYSTEM_BUFFER) || + FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_FAST_IO_OPERATION)) { + + // + // If this is a system buffer, just use the given address because + // it is valid in all thread contexts. + // If this is a FASTIO operation, we can just use the + // buffer (inside a try/except) since we know we are in + // the correct thread context (you can't pend FASTIO's). + // + + origBuf = iopb->Parameters.Read.ReadBuffer; + + } else { + + // + // They don't have a MDL and this is not a system buffer + // or a fastio so this is probably some arbitrary user + // buffer. We can not do the processing at DPC level so + // try and get to a safe IRQL so we can do the processing. + // + + if (FltDoCompletionProcessingWhenSafe( Data, + FltObjects, + CompletionContext, + Flags, + SwapPostReadBuffersWhenSafe, + &retValue )) { + + // + // This operation has been moved to a safe IRQL, the called + // routine will do (or has done) the freeing so don't do it + // in our routine. + // + + cleanupAllocatedBuffer = FALSE; + + } else { + + // + // We are in a state where we can not get to a safe IRQL and + // we do not have a MDL. There is nothing we can do to safely + // copy the data back to the users buffer, fail the operation + // and return. This shouldn't ever happen because in those + // situations where it is not safe to post, we should have + // a MDL. + // + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostReadBuffers: %wZ Unable to post to a safe IRQL\n", + &p2pCtx->VolCtx->Name) ); + + Data->IoStatus.Status = STATUS_UNSUCCESSFUL; + Data->IoStatus.Information = 0; + } + + leave; + } + + // + // We either have a system buffer or this is a fastio operation + // so we are in the proper context. Copy the data handling an + // exception. + // + + try { + + RtlCopyMemory( origBuf, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information ); + + } except (EXCEPTION_EXECUTE_HANDLER) { + + // + // The copy failed, return an error, failing the operation. + // + + Data->IoStatus.Status = GetExceptionCode(); + Data->IoStatus.Information = 0; + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostReadBuffers: %wZ Invalid user buffer, oldB=%p, status=%x\n", + &p2pCtx->VolCtx->Name, + origBuf, + Data->IoStatus.Status) ); + } + + } finally { + + // + // If we are supposed to, cleanup the allocated memory and release + // the volume context. The freeing of the MDL (if there is one) is + // handled by FltMgr. + // + + if (cleanupAllocatedBuffer) { + + LOG_PRINT( LOGFL_READ, + ("SwapBuffers!SwapPostReadBuffers: %wZ newB=%p info=%Iu Freeing\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information) ); + + FltFreePoolAlignedWithTag( FltObjects->Instance, + p2pCtx->SwappedBuffer, + BUFFER_SWAP_TAG ); + + FltReleaseContext( p2pCtx->VolCtx ); + + ExFreeToNPagedLookasideList( &Pre2PostContextList, + p2pCtx ); + } + } + + return retValue; +} + + +FLT_POSTOP_CALLBACK_STATUS +SwapPostReadBuffersWhenSafe ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + We had an arbitrary users buffer without a MDL so we needed to get + to a safe IRQL so we could lock it and then copy the data. + +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 - Contains state from our PreOperation callback + + Flags - Denotes whether the completion is successful or is being drained. + +Return Value: + + FLT_POSTOP_FINISHED_PROCESSING - This is always returned. + +--*/ +{ + PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; + PPRE_2_POST_CONTEXT p2pCtx = CompletionContext; + PVOID origBuf; + NTSTATUS status; + + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( Flags ); + FLT_ASSERT(Data->IoStatus.Information != 0); + + // + // This is some sort of user buffer without a MDL, lock the user buffer + // so we can access it. This will create a MDL for it. + // + + status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS(status)) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostReadBuffersWhenSafe: %wZ Could not lock user buffer, oldB=%p, status=%x\n", + &p2pCtx->VolCtx->Name, + iopb->Parameters.Read.ReadBuffer, + status) ); + + // + // If we can't lock the buffer, fail the operation + // + + Data->IoStatus.Status = status; + Data->IoStatus.Information = 0; + + } else { + + // + // Get a system address for this buffer. + // + + origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.Read.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (origBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostReadBuffersWhenSafe: %wZ Failed to get system address for MDL: %p\n", + &p2pCtx->VolCtx->Name, + iopb->Parameters.Read.MdlAddress) ); + + // + // If we couldn't get a SYSTEM buffer address, fail the operation + // + + Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Data->IoStatus.Information = 0; + + } else { + + // + // Copy the data back to the original buffer. Note that we + // don't need a try/except because we will always have a system + // buffer address. + // + + RtlCopyMemory( origBuf, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information ); + } + } + + // + // Free allocated memory and release the volume context + // + + LOG_PRINT( LOGFL_READ, + ("SwapBuffers!SwapPostReadBuffersWhenSafe: %wZ newB=%p info=%Iu Freeing\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information) ); + + FltFreePoolAlignedWithTag( FltObjects->Instance, + p2pCtx->SwappedBuffer, + BUFFER_SWAP_TAG ); + + FltReleaseContext( p2pCtx->VolCtx ); + + ExFreeToNPagedLookasideList( &Pre2PostContextList, + p2pCtx ); + + return FLT_POSTOP_FINISHED_PROCESSING; +} + + +FLT_PREOP_CALLBACK_STATUS +SwapPreDirCtrlBuffers( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This routine demonstrates how to swap buffers for the Directory Control + operations. The reason this routine is here is because directory change + notifications are long lived and this allows you to see how FltMgr + handles long lived IRP operations that have swapped buffers when the + mini-filter is unloaded. It does this by canceling the IRP. + + 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; + + try { + + // + // If they are trying to get ZERO bytes, then don't do anything and + // we don't need a post-operation callback. + // + + if (iopb->Parameters.DirectoryControl.QueryDirectory.Length == 0) { + + leave; + } + + // + // Get our volume context. If we can't get it, just return. + // + + status = FltGetVolumeContext( FltObjects->Filter, + FltObjects->Volume, + &volCtx ); + + if (!NT_SUCCESS(status)) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreDirCtrlBuffers: Error getting volume context, status=%x\n", + status) ); + + leave; + } + + // + // 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, + iopb->Parameters.DirectoryControl.QueryDirectory.Length, + BUFFER_SWAP_TAG ); + + if (newBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreDirCtrlBuffers: %wZ Failed to allocate %d bytes of memory.\n", + &volCtx->Name, + iopb->Parameters.DirectoryControl.QueryDirectory.Length) ); + + leave; + } + + // + // Zero the new buffer so as not to potentially expose any sensitive + // data to the user. + // + + RtlZeroMemory( newBuf, iopb->Parameters.DirectoryControl.QueryDirectory.Length ); + + + // + // We need to build a MDL because Directory Control Operations are always IRP operations. + // + + + // + // 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, + iopb->Parameters.DirectoryControl.QueryDirectory.Length, + FALSE, + FALSE, + NULL ); + + if (newMdl == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreDirCtrlBuffers: %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 + // buffer to the post operation callback. + // + + p2pCtx = ExAllocateFromNPagedLookasideList( &Pre2PostContextList ); + + if (p2pCtx == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreDirCtrlBuffers: %wZ Failed to allocate pre2Post context structure\n", + &volCtx->Name) ); + + leave; + } + + // + // Log that we are swapping + // + + LOG_PRINT( LOGFL_DIRCTRL, + ("SwapBuffers!SwapPreDirCtrlBuffers: %wZ newB=%p newMdl=%p oldB=%p oldMdl=%p len=%d\n", + &volCtx->Name, + newBuf, + newMdl, + iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer, + iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress, + iopb->Parameters.DirectoryControl.QueryDirectory.Length) ); + + // + // Update the buffer pointers and MDL address + // + + iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer = newBuf; + iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress = newMdl; + FltSetCallbackDataDirty( Data ); + + // + // Pass state to our post-operation callback. + // + + p2pCtx->SwappedBuffer = newBuf; + p2pCtx->VolCtx = volCtx; + + *CompletionContext = p2pCtx; + + // + // Return we want a post-operation callback + // + + retValue = FLT_PREOP_SUCCESS_WITH_CALLBACK; + + } finally { + + // + // If we don't want a post-operation callback, then cleanup state. + // + + if (retValue != FLT_PREOP_SUCCESS_WITH_CALLBACK) { + + if (newBuf != NULL) { + + ExFreePool( newBuf ); + } + + if (newMdl != NULL) { + + IoFreeMdl( newMdl ); + } + + if (volCtx != NULL) { + + FltReleaseContext( volCtx ); + } + } + } + + return retValue; +} + + +FLT_POSTOP_CALLBACK_STATUS +SwapPostDirCtrlBuffers( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine does the post Directory Control buffer swap handling. + +Arguments: + + This routine does postRead buffer swap handling + 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 - The completion context set in the pre-operation routine. + + Flags - Denotes whether the completion is successful or is being drained. + +Return Value: + + FLT_POSTOP_FINISHED_PROCESSING + FLT_POSTOP_MORE_PROCESSING_REQUIRED + +--*/ +{ + PVOID origBuf; + PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; + FLT_POSTOP_CALLBACK_STATUS retValue = FLT_POSTOP_FINISHED_PROCESSING; + PPRE_2_POST_CONTEXT p2pCtx = CompletionContext; + BOOLEAN cleanupAllocatedBuffer = TRUE; + + // + // Verify we are not draining an operation with swapped buffers + // + + FLT_ASSERT(!FlagOn(Flags, FLTFL_POST_OPERATION_DRAINING)); + + try { + + // + // If the operation failed or the count is zero, there is no data to + // copy so just return now. + // + + if (!NT_SUCCESS(Data->IoStatus.Status) || + (Data->IoStatus.Information == 0)) { + + LOG_PRINT( LOGFL_DIRCTRL, + ("SwapBuffers!SwapPostDirCtrlBuffers: %wZ newB=%p No data read, status=%x, info=%Ix\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Status, + Data->IoStatus.Information) ); + + leave; + } + + // + // We need to copy the read data back into the users buffer. Note + // that the parameters passed in are for the users original buffers + // not our swapped buffers + // + + if (iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL) { + + // + // There is a MDL defined for the original buffer, get a + // system address for it so we can copy the data back to it. + // We must do this because we don't know what thread context + // we are in. + // + + origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (origBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostDirCtrlBuffers: %wZ Failed to get system address for MDL: %p\n", + &p2pCtx->VolCtx->Name, + iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress) ); + + // + // If we failed to get a SYSTEM address, mark that the + // operation failed and return. + // + + Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Data->IoStatus.Information = 0; + leave; + } + + } else if (FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_SYSTEM_BUFFER) || + FlagOn(Data->Flags,FLTFL_CALLBACK_DATA_FAST_IO_OPERATION)) { + + // + // If this is a system buffer, just use the given address because + // it is valid in all thread contexts. + // If this is a FASTIO operation, we can just use the + // buffer (inside a try/except) since we know we are in + // the correct thread context. + // + + origBuf = iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer; + + } else { + + // + // They don't have a MDL and this is not a system buffer + // or a fastio so this is probably some arbitrary user + // buffer. We can not do the processing at DPC level so + // try and get to a safe IRQL so we can do the processing. + // + + if (FltDoCompletionProcessingWhenSafe( Data, + FltObjects, + CompletionContext, + Flags, + SwapPostDirCtrlBuffersWhenSafe, + &retValue )) { + + // + // This operation has been moved to a safe IRQL, the called + // routine will do (or has done) the freeing so don't do it + // in our routine. + // + + cleanupAllocatedBuffer = FALSE; + + } else { + + // + // We are in a state where we can not get to a safe IRQL and + // we do not have a MDL. There is nothing we can do to safely + // copy the data back to the users buffer, fail the operation + // and return. This shouldn't ever happen because in those + // situations where it is not safe to post, we should have + // a MDL. + // + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostDirCtrlBuffers: %wZ Unable to post to a safe IRQL\n", + &p2pCtx->VolCtx->Name) ); + + Data->IoStatus.Status = STATUS_UNSUCCESSFUL; + Data->IoStatus.Information = 0; + } + + leave; + } + + // + // We either have a system buffer or this is a fastio operation + // so we are in the proper context. Copy the data handling an + // exception. + // + // NOTE: Due to a bug in FASTFAT where it is returning the wrong + // length in the information field (it is sort) we are always + // going to copy the original buffer length. Please note that + // this is a potential security problem because we will copy + // more than what was touched by the FS. So we have to make + // sure the buffer is clean before calling into the FS or we + // risk exposing sensitive data to the user. + // + + try { + + RtlCopyMemory( origBuf, + p2pCtx->SwappedBuffer, + /*Data->IoStatus.Information*/ + iopb->Parameters.DirectoryControl.QueryDirectory.Length ); + + } except (EXCEPTION_EXECUTE_HANDLER) { + + Data->IoStatus.Status = GetExceptionCode(); + Data->IoStatus.Information = 0; + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostDirCtrlBuffers: %wZ Invalid user buffer, oldB=%p, status=%x, info=%Iu\n", + &p2pCtx->VolCtx->Name, + origBuf, + Data->IoStatus.Status, + Data->IoStatus.Information) ); + } + + } finally { + + // + // If we are supposed to, cleanup the allocate memory and release + // the volume context. The freeing of the MDL (if there is one) is + // handled by FltMgr. + // + + if (cleanupAllocatedBuffer) { + + LOG_PRINT( LOGFL_DIRCTRL, + ("SwapBuffers!SwapPostDirCtrlBuffers: %wZ newB=%p info=%Iu Freeing\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information) ); + + ExFreePool( p2pCtx->SwappedBuffer ); + FltReleaseContext( p2pCtx->VolCtx ); + + ExFreeToNPagedLookasideList( &Pre2PostContextList, + p2pCtx ); + } + } + + return retValue; +} + + +FLT_POSTOP_CALLBACK_STATUS +SwapPostDirCtrlBuffersWhenSafe ( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + We had an arbitrary users buffer without a MDL so we needed to get + to a safe IRQL so we could lock it and then copy the data. + +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 - The buffer we allocated and swapped to + + Flags - Denotes whether the completion is successful or is being drained. + +Return Value: + + FLT_POSTOP_FINISHED_PROCESSING - This is always returned. + +--*/ +{ + PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; + PPRE_2_POST_CONTEXT p2pCtx = CompletionContext; + PVOID origBuf; + NTSTATUS status; + + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( Flags ); + FLT_ASSERT(Data->IoStatus.Information != 0); + + // + // This is some sort of user buffer without a MDL, lock the + // user buffer so we can access it + // + + status = FltLockUserBuffer( Data ); + + if (!NT_SUCCESS(status)) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostDirCtrlBuffersWhenSafe: %wZ Could not lock user buffer, oldB=%p, status=%x\n", + &p2pCtx->VolCtx->Name, + iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer, + status) ); + + // + // If we can't lock the buffer, fail the operation + // + + Data->IoStatus.Status = status; + Data->IoStatus.Information = 0; + + } else { + + // + // Get a system address for this buffer. + // + + origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (origBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPostDirCtrlBuffersWhenSafe: %wZ Failed to get System address for MDL: %p\n", + &p2pCtx->VolCtx->Name, + iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress) ); + + // + // If we couldn't get a SYSTEM buffer address, fail the operation + // + + Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Data->IoStatus.Information = 0; + + } else { + + // + // Copy the data back to the original buffer + // + // NOTE: Due to a bug in FASTFAT where it is returning the wrong + // length in the information field (it is short) we are + // always going to copy the original buffer length. + // + + RtlCopyMemory( origBuf, + p2pCtx->SwappedBuffer, + /*Data->IoStatus.Information*/ + iopb->Parameters.DirectoryControl.QueryDirectory.Length ); + } + } + + // + // Free the memory we allocated and return + // + + LOG_PRINT( LOGFL_DIRCTRL, + ("SwapBuffers!SwapPostDirCtrlBuffersWhenSafe: %wZ newB=%p info=%Iu Freeing\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information) ); + + ExFreePool( p2pCtx->SwappedBuffer ); + FltReleaseContext( p2pCtx->VolCtx ); + + ExFreeToNPagedLookasideList( &Pre2PostContextList, + p2pCtx ); + + return FLT_POSTOP_FINISHED_PROCESSING; +} + + +FLT_PREOP_CALLBACK_STATUS +SwapPreWriteBuffers( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Flt_CompletionContext_Outptr_ PVOID *CompletionContext + ) +/*++ + +Routine Description: + + This routine demonstrates how to swap buffers for the WRITE 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 + FLT_PREOP_COMPLETE - +--*/ +{ + 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; + PVOID origBuf; + NTSTATUS status; + ULONG writeLen = iopb->Parameters.Write.Length; + + try { + + // + // If they are trying to write ZERO bytes, then don't do anything and + // we don't need a post-operation callback. + // + + if (writeLen == 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!SwapPreWriteBuffers: 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)) { + + writeLen = (ULONG)ROUND_TO_SIZE(writeLen,volCtx->SectorSize); + } + + // + // Allocate aligned nonPaged memory for the buffer we are swapping + // to. This is really only necessary for noncached IO but we always + // do it here for simplification. If we fail to get the memory, just + // don't swap buffers on this operation. + // + + newBuf = FltAllocatePoolAlignedWithTag( FltObjects->Instance, + NonPagedPool, + (SIZE_T) writeLen, + BUFFER_SWAP_TAG ); + + if (newBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreWriteBuffers: %wZ Failed to allocate %d bytes of memory.\n", + &volCtx->Name, + writeLen) ); + + leave; + } + + // + // We only need to build a MDL for IRP operations. We don't need to + // do this for a FASTIO operation because it is a waste of time 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, + writeLen, + FALSE, + FALSE, + NULL ); + + if (newMdl == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreWriteBuffers: %wZ Failed to allocate MDL.\n", + &volCtx->Name) ); + + leave; + } + + // + // setup the MDL for the non-paged pool we just allocated + // + + MmBuildMdlForNonPagedPool( newMdl ); + } + + // + // If the users original buffer had a MDL, get a system address. + // + + if (iopb->Parameters.Write.MdlAddress != NULL) { + + // + // This should be a simple MDL. We don't expect chained MDLs + // this high up the stack + // + + FLT_ASSERT( ((PMDL)iopb->Parameters.Write.MdlAddress)->Next == NULL); + + origBuf = MmGetSystemAddressForMdlSafe( iopb->Parameters.Write.MdlAddress, + NormalPagePriority | MdlMappingNoExecute ); + + if (origBuf == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreWriteBuffers: %wZ Failed to get system address for MDL: %p\n", + &volCtx->Name, + iopb->Parameters.Write.MdlAddress) ); + + // + // If we could not get a system address for the users buffer, + // then we are going to fail this operation. + // + + Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Data->IoStatus.Information = 0; + retValue = FLT_PREOP_COMPLETE; + leave; + } + + } else { + + // + // There was no MDL defined, use the given buffer address. + // + + origBuf = iopb->Parameters.Write.WriteBuffer; + } + + // + // Copy the memory, we must do this inside the try/except because we + // may be using a users buffer address + // + + try { + + RtlCopyMemory( newBuf, + origBuf, + writeLen ); + + } except (EXCEPTION_EXECUTE_HANDLER) { + + // + // The copy failed, return an error, failing the operation. + // + + Data->IoStatus.Status = GetExceptionCode(); + Data->IoStatus.Information = 0; + retValue = FLT_PREOP_COMPLETE; + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreWriteBuffers: %wZ Invalid user buffer, oldB=%p, status=%x\n", + &volCtx->Name, + origBuf, + Data->IoStatus.Status) ); + + leave; + } + + // + // We are ready to swap buffers, get a pre2Post context structure. + // We need it to pass the volume context and the allocate memory + // buffer to the post operation callback. + // + + p2pCtx = ExAllocateFromNPagedLookasideList( &Pre2PostContextList ); + + if (p2pCtx == NULL) { + + LOG_PRINT( LOGFL_ERRORS, + ("SwapBuffers!SwapPreWriteBuffers: %wZ Failed to allocate pre2Post context structure\n", + &volCtx->Name) ); + + leave; + } + + // + // Set new buffers + // + + LOG_PRINT( LOGFL_WRITE, + ("SwapBuffers!SwapPreWriteBuffers: %wZ newB=%p newMdl=%p oldB=%p oldMdl=%p len=%d\n", + &volCtx->Name, + newBuf, + newMdl, + iopb->Parameters.Write.WriteBuffer, + iopb->Parameters.Write.MdlAddress, + writeLen) ); + + iopb->Parameters.Write.WriteBuffer = newBuf; + iopb->Parameters.Write.MdlAddress = newMdl; + FltSetCallbackDataDirty( Data ); + + // + // Pass state to our post-operation callback. + // + + p2pCtx->SwappedBuffer = newBuf; + p2pCtx->VolCtx = volCtx; + + *CompletionContext = p2pCtx; + + // + // Return we want a post-operation callback + // + + retValue = FLT_PREOP_SUCCESS_WITH_CALLBACK; + + } finally { + + // + // If we don't want a post-operation callback, then free the buffer + // or MDL if it was allocated. + // + + if (retValue != FLT_PREOP_SUCCESS_WITH_CALLBACK) { + + if (newBuf != NULL) { + + FltFreePoolAlignedWithTag( FltObjects->Instance, + newBuf, + BUFFER_SWAP_TAG ); + + } + + if (newMdl != NULL) { + + IoFreeMdl( newMdl ); + } + + if (volCtx != NULL) { + + FltReleaseContext( volCtx ); + } + } + } + + return retValue; +} + + +FLT_POSTOP_CALLBACK_STATUS +SwapPostWriteBuffers( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags + ) +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + +--*/ +{ + PPRE_2_POST_CONTEXT p2pCtx = CompletionContext; + + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( Flags ); + + LOG_PRINT( LOGFL_WRITE, + ("SwapBuffers!SwapPostWriteBuffers: %wZ newB=%p info=%Iu Freeing\n", + &p2pCtx->VolCtx->Name, + p2pCtx->SwappedBuffer, + Data->IoStatus.Information) ); + + // + // Free allocate POOL and volume context + // + + FltFreePoolAlignedWithTag( FltObjects->Instance, + p2pCtx->SwappedBuffer, + BUFFER_SWAP_TAG ); + + FltReleaseContext( p2pCtx->VolCtx ); + + ExFreeToNPagedLookasideList( &Pre2PostContextList, + p2pCtx ); + + return FLT_POSTOP_FINISHED_PROCESSING; +} + + +VOID +ReadDriverParameters ( + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This routine tries to read the driver-specific parameters from + the registry. These values will be found in the registry location + indicated by the RegistryPath passed in. + +Arguments: + + RegistryPath - the path key passed to the driver during driver entry. + +Return Value: + + None. + +--*/ +{ + OBJECT_ATTRIBUTES attributes; + HANDLE driverRegKey; + NTSTATUS status; + ULONG resultLength; + UNICODE_STRING valueName; + UCHAR buffer[sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + sizeof( LONG )]; + + // + // If this value is not zero then somebody has already explicitly set it + // so don't override those settings. + // + + if (0 == LoggingFlags) { + + // + // Open the desired registry key + // + + InitializeObjectAttributes( &attributes, + RegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &driverRegKey, + KEY_READ, + &attributes ); + + if (!NT_SUCCESS( status )) { + + return; + } + + // + // Read the given value from the registry. + // + + RtlInitUnicodeString( &valueName, L"DebugFlags" ); + + status = ZwQueryValueKey( driverRegKey, + &valueName, + KeyValuePartialInformation, + buffer, + sizeof(buffer), + &resultLength ); + + if (NT_SUCCESS( status )) { + + LoggingFlags = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data)); + } + + // + // Close the registry entry + // + + ZwClose(driverRegKey); + } +} + diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.inf b/filesys/miniFilter/swapBuffers/swapBuffers.inf new file mode 100644 index 00000000..d6a5fc3a --- /dev/null +++ b/filesys/miniFilter/swapBuffers/swapBuffers.inf @@ -0,0 +1,95 @@ +;;; +;;; SwapBuffers +;;; +;;; +;;; Copyright (c) 2001, Microsoft Corporation +;;; + +[Version] +signature = "$Windows NT$" +Class = "Encryption" ;This is determined by the work this filter driver does +ClassGuid = {a0a701c0-a511-42ff-aa6c-06dc0395576f} ;This value is determined by the Class +Provider = %Msft% +DriverVer = 06/16/2007,1.0.0.3 +CatalogFile = swapbuffers.cat + + +[DestinationDirs] +DefaultDestDir = 12 +MiniFilter.DriverFiles = 12 ;%windir%\system32\drivers + +;; +;; Default install sections +;; + +[DefaultInstall] +OptionDesc = %ServiceDescription% +CopyFiles = MiniFilter.DriverFiles + +[DefaultInstall.Services] +AddService = %ServiceName%,,MiniFilter.Service + +;; +;; Default uninstall sections +;; + +[DefaultUninstall] +DelFiles = MiniFilter.DriverFiles + +[DefaultUninstall.Services] +DelService = SwapBuffers,0x200 ;Ensure service is stopped before deleting + +; +; Services Section +; + +[MiniFilter.Service] +DisplayName = %ServiceName% +Description = %ServiceDescription% +ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\ +Dependencies = "FltMgr" +ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER +;StartType = 0 ;SERVICE_BOOT_START +StartType = 3 ;SERVICE_DEMAND_START +ErrorControl = 1 ;SERVICE_ERROR_NORMAL +LoadOrderGroup = "FSFilter Encryption" +AddReg = MiniFilter.AddRegistry + +; +; Registry Modifications +; + +[MiniFilter.AddRegistry] +HKR,,"SupportedFeatures",0x00010001,0x3 +HKR,"Instances","DefaultInstance",0x00000000,%Instance1.Name% +HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude% +HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags% + +; +; Copy Files +; + +[MiniFilter.DriverFiles] +%DriverName%.sys + +[SourceDisksFiles] +swapbuffers.sys = 1,, + +[SourceDisksNames] +1 = %DiskId1%,,, + +;; +;; String Section +;; + +[Strings] +Msft = "Microsoft Corporation" +ServiceDescription = "Swap Buffers Sample Mini-Filter Driver" +ServiceName = "SwapBuffers" +DriverName = "SwapBuffers" +DiskId1 = "SwapBuffers Device Installation Disk" + +;Instances specific information. +Instance1.Name = "SwapBuffers Instance" +Instance1.Altitude = "141000" +Instance1.Flags = 0x0 ; allow automatic attachments diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.rc b/filesys/miniFilter/swapBuffers/swapBuffers.rc new file mode 100644 index 00000000..436c15cf --- /dev/null +++ b/filesys/miniFilter/swapBuffers/swapBuffers.rc @@ -0,0 +1,10 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "SwapBuffers Filter Driver" +#define VER_INTERNALNAME_STR "swapBuffers.sys" + +#include "common.ver" diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.sln b/filesys/miniFilter/swapBuffers/swapBuffers.sln new file mode 100644 index 00000000..88ca2992 --- /dev/null +++ b/filesys/miniFilter/swapBuffers/swapBuffers.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swapBuffers", "swapBuffers.vcxproj", "{A7B7D32A-A301-4497-A68B-349341047B69}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|Win32.Build.0 = Debug|Win32 + {A7B7D32A-A301-4497-A68B-349341047B69}.Release|Win32.ActiveCfg = Release|Win32 + {A7B7D32A-A301-4497-A68B-349341047B69}.Release|Win32.Build.0 = Release|Win32 + {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|x64.ActiveCfg = Debug|x64 + {A7B7D32A-A301-4497-A68B-349341047B69}.Debug|x64.Build.0 = Debug|x64 + {A7B7D32A-A301-4497-A68B-349341047B69}.Release|x64.ActiveCfg = Release|x64 + {A7B7D32A-A301-4497-A68B-349341047B69}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj new file mode 100644 index 00000000..3c7b7151 --- /dev/null +++ b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{A7B7D32A-A301-4497-A68B-349341047B69}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{3AA28CE9-14ED-49C0-9FC7-A918130F15DA}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>swapBuffers</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>swapBuffers</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>swapBuffers</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>swapBuffers</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib</AdditionalDependencies> + </Link> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib</AdditionalDependencies> + </Link> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib</AdditionalDependencies> + </Link> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\fltMgr.lib</AdditionalDependencies> + </Link> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE;POOL_NX_OPTIN=1</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="swapBuffers.c" /> + <ResourceCompile Include="swapBuffers.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters new file mode 100644 index 00000000..eba4de22 --- /dev/null +++ b/filesys/miniFilter/swapBuffers/swapBuffers.vcxproj.Filters @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{35572264-BD73-4FA0-88AC-7FCC7C0917C7}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{FF6920BD-0267-4DBD-B420-DED4DD132F5C}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{2BAFD988-E41F-4DB0-A580-19F92CFFE2F4}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{0D9FC8FE-1009-48A7-8A94-DD71E176AEE9}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="swapBuffers.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="swapBuffers.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file |
