EXTERN_C static NTSTATUS ScvnpWriteFile(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ const wchar_t *OutPathW, _In_ void *Buffer, _In_ ULONG BufferSize, _In_ ULONG CreateDisposition) { PAGED_CODE(); UNICODE_STRING outPath = {}; RtlInitUnicodeString(&outPath, OutPathW); OBJECT_ATTRIBUTES objAttr = RTL_INIT_OBJECT_ATTRIBUTES( &outPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE); HANDLE fileHandle = nullptr; IO_STATUS_BLOCK ioStatus = {}; auto status = FltCreateFile( FltObjects->Filter, FltObjects->Instance, &fileHandle, GENERIC_WRITE, &objAttr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL, 0, CreateDisposition, FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, nullptr, 0, 0); if (status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_DELETE_PENDING) { return status; } if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltCreateFile failed (%08x) for %S", status, OutPathW); return status; } PFILE_OBJECT fileObject = nullptr; status = ObReferenceObjectByHandle(fileHandle, 0, nullptr, KernelMode, reinterpret_cast<void **>(&fileObject), nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("ObReferenceObjectByHandle failed (%08x) for %S", status, OutPathW); goto End; } status = FltWriteFile(FltObjects->Instance, fileObject, nullptr, BufferSize, Buffer, 0, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltWriteFile failed (%08x) for %S", status, OutPathW); goto End; } End: if (fileObject) { ObDereferenceObject(fileObject); } if (fileHandle) { FltClose(fileHandle); } return status; }
EXTERN_C static NTSTATUS ScvnpReadFile(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Out_ void *Buffer, _In_ ULONG BufferSize) { PAGED_CODE(); // Use an existing file object when it is NOT IRP_MJ_CLEANUP. if (Data->Iopb->MajorFunction != IRP_MJ_CLEANUP) { LARGE_INTEGER byteOffset = {}; auto status = FltReadFile(FltObjects->Instance, FltObjects->FileObject, &byteOffset, BufferSize, Buffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltReadFile failed (%08x)", status); return status; } return status; } PFILE_OBJECT fileObject = nullptr; // Make a new file object since the file is already out of the current IO // path. PFLT_FILE_NAME_INFORMATION fileNameInformation = nullptr; auto status = FltGetFileNameInformationUnsafe( FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED, &fileNameInformation); if (!NT_SUCCESS(status)) { return status; } OBJECT_ATTRIBUTES objAttr = RTL_INIT_OBJECT_ATTRIBUTES( &fileNameInformation->Name, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE); HANDLE fileHandle = nullptr; IO_STATUS_BLOCK ioStatus = {}; status = FltCreateFile( FltObjects->Filter, FltObjects->Instance, &fileHandle, GENERIC_READ, &objAttr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, nullptr, 0, 0); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltCreateFile failed (%08x) for %wZ", status, &fileNameInformation->Name); goto End; } status = ObReferenceObjectByHandle(fileHandle, 0, nullptr, KernelMode, reinterpret_cast<void **>(&fileObject), nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("ObReferenceObjectByHandle failed (%08x) for %wZ", status, &fileNameInformation->Name); goto End; } status = FltReadFile(FltObjects->Instance, fileObject, nullptr, BufferSize, Buffer, 0, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { LOG_ERROR_SAFE("FltReadFile failed (%08x) for %wZ", status, &fileNameInformation->Name); goto End; } End: if (fileObject) { ObDereferenceObject(fileObject); } if (fileHandle) { FltClose(fileHandle); } if (fileNameInformation) { FltReleaseFileNameInformation(fileNameInformation); } return status; }
VOID CreateADirectory(PFLT_INSTANCE pInstance, PUNICODE_STRING pDirectoryPath) { NTSTATUS status; OBJECT_ATTRIBUTES directoryAttributesObject; IO_STATUS_BLOCK directoryIoStatusBlock; LARGE_INTEGER allocate; HANDLE hDirectory; allocate.QuadPart = 0x1000; InitializeObjectAttributes( &directoryAttributesObject, pDirectoryPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL ); /* You can't use FltCreateFile here */ /* Instance may not be the same instance we want to write to eg a flash drive writing a file to a ntfs partition */ status = ZwCreateFile( &hDirectory, 0, &directoryAttributesObject, &directoryIoStatusBlock, &allocate, 0, 0, FILE_CREATE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT|FILE_WRITE_THROUGH, NULL, 0 ); /* status = FltCreateFile( fileManager.pFilter, pInstance, &hDirectory, 0, &directoryAttributesObject, &directoryIoStatusBlock, &allocate, 0, 0, FILE_CREATE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT|FILE_WRITE_THROUGH, NULL, 0, 0 ); */ if(NT_SUCCESS(status) && NT_SUCCESS(directoryIoStatusBlock.Status)) { FltClose(hDirectory); } else { if(status != STATUS_OBJECT_NAME_COLLISION) { DbgPrint("CaptureFileMonitor: CreateADirectory ERROR %08x & %08x\n", status, directoryIoStatusBlock.Status); } } }
NTSTATUS CopyFile( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PUNICODE_STRING pCompleteFileName ) { NTSTATUS status; UNICODE_STRING tempDeletedFilePath; OBJECT_ATTRIBUTES tempDeletedObject; IO_STATUS_BLOCK ioStatusTempDeleted; LARGE_INTEGER allocate; FILE_STANDARD_INFORMATION fileStandardInformation; HANDLE tempDeletedHandle; ULONG returnedLength; allocate.QuadPart = 0x10000; InitializeObjectAttributes( &tempDeletedObject, pCompleteFileName, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = FltQueryInformationFile( FltObjects->Instance, Data->Iopb->TargetFileObject, &fileStandardInformation, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, &returnedLength ); if(NT_SUCCESS(status)) { allocate.QuadPart = fileStandardInformation.AllocationSize.QuadPart; } else { DbgPrint("CaptureFileMonitor: ERROR - Could not get files allocation size\n"); return status; } status = FltCreateFile( FltObjects->Filter, NULL, &tempDeletedHandle, GENERIC_WRITE, &tempDeletedObject, &ioStatusTempDeleted, &allocate, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_NON_DIRECTORY_FILE, NULL, 0, 0 ); if(NT_SUCCESS(status)) { PVOID handleFileObject; PVOID pFileBuffer; LARGE_INTEGER offset; ULONG bytesRead = 0; ULONG bytesWritten = 0; offset.QuadPart = 0; status = ObReferenceObjectByHandle( tempDeletedHandle, 0, NULL, KernelMode, &handleFileObject, NULL); if(!NT_SUCCESS(status)) { DbgPrint("CaptureFileMonitor: ERROR - ObReferenceObjectByHandle - FAILED - %08x\n", status); return status; } pFileBuffer = ExAllocatePoolWithTag(NonPagedPool, 65536, FILE_POOL_TAG); if(pFileBuffer != NULL) { ObReferenceObject(Data->Iopb->TargetFileObject); do { IO_STATUS_BLOCK IoStatusBlock; bytesWritten = 0; status = FltReadFile( FltObjects->Instance, Data->Iopb->TargetFileObject, &offset, 65536, pFileBuffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, &bytesRead , NULL, NULL ); if(NT_SUCCESS(status) && bytesRead > 0) { /* You can't use FltWriteFile here */ /* Instance may not be the same instance we want to write to eg a flash drive writing a file to a ntfs partition */ status = ZwWriteFile( tempDeletedHandle, NULL, NULL, NULL, &IoStatusBlock, pFileBuffer, bytesRead, &offset, NULL ); if(NT_SUCCESS(status)) { //DbgPrint("WriteFile: FltReadFile - %08x\n", status); } /* status = FltWriteFile( FltObjects->Instance, handleFileObject, &offset, bytesRead, pFileBuffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, &bytesWritten, NULL, NULL ); */ } else { //DbgPrint("CopyFile: FltReadFile - %08x\n", status); break; } offset.QuadPart += bytesRead; } while(bytesRead == 65536); ObDereferenceObject(Data->Iopb->TargetFileObject); ExFreePoolWithTag(pFileBuffer, FILE_POOL_TAG); } ObDereferenceObject(handleFileObject); FltClose(tempDeletedHandle); } else { if(status != STATUS_OBJECT_NAME_COLLISION) { DbgPrint("CaptureFileMonitor: ERROR - FltCreateFile FAILED - %08x\n",status); return status; } } return STATUS_SUCCESS; }
NTSTATUS NcEnumerateDirectorySetupInjection ( _Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PNC_INSTANCE_CONTEXT InstanceContext, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ FILE_INFORMATION_CLASS InformationClass ) /*++ Routine Description: Sets up directory enumeration context cache so that we are ready to perform injection. Arguments: DirQryCtx - Pointer to directory query context (on the stream handle.) FltObjects - FltObjects structure for this operation. InstanceContext - Instance Context for this operation. Offsets - Offsets structure for this information class. InformationClass - The information class for this operation. Return Value: Returns STATUS_SUCCESS on success, otherwise an appropriate error code. --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES RealParentAttributes; HANDLE RealParentHandle = 0; //close always PFILE_OBJECT RealParentFileObj = NULL; IO_STATUS_BLOCK RealParentStatusBlock; char * QueryBuffer = NULL; //free on error, when no injection ULONG QueryBufferLength = 0; USHORT NameLength; ULONG QueryBufferLengthRead; BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, FO_OPENED_CASE_SENSITIVE ); PAGED_CODE(); // // If the user has specified a search string, and if our user mapping // should not be returned in this search string, return success. We // don't need to inject anything. // if (DirQryCtx->SearchString.Length > 0 && !FsRtlIsNameInExpression( &DirQryCtx->SearchString, &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName, IgnoreCase, NULL ) && !FsRtlIsNameInExpression( &DirQryCtx->SearchString, &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName, IgnoreCase, NULL )) { Status = STATUS_SUCCESS; goto NcEnumerateDirectorySetupCleanup; } // // Initialize insertion info. // // We have to insert the final component of the real mapping // as the final component of the user mapping. To do this we // will open the parent of the real mapping, and query the real // mapping. // Then we will overwrite the real mapping's name with // the final component of the user mapping. This data will be // stored in the DirQryCtx for later injection. // // // Open parent of real mapping. // InitializeObjectAttributes( &RealParentAttributes, &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, OBJ_KERNEL_HANDLE, NULL, NULL); Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter FltObjects->Instance, // InstanceOffsets &RealParentHandle, // Returned Handle &RealParentFileObj, // Returned FileObject FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access &RealParentAttributes, // object attributes &RealParentStatusBlock, // Returned IOStatusBlock 0, // Allocation Size FILE_ATTRIBUTE_NORMAL, // File Attributes 0, // Share Access FILE_OPEN, // Create Disposition FILE_DIRECTORY_FILE, // Create Options NULL, // Ea Buffer 0, // EA Length IO_IGNORE_SHARE_ACCESS_CHECK, // Flags FltObjects->FileObject ); // Transaction state if (!NT_SUCCESS( Status )) { goto NcEnumerateDirectorySetupCleanup; } // // Allocate Buffer to store mapping data. // NameLength = Max( InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length, InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length ); QueryBufferLength = Offsets->FileNameDist + NameLength; QueryBuffer = ExAllocatePoolWithTag( PagedPool, QueryBufferLength, NC_DIR_QRY_CACHE_TAG ); if (QueryBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto NcEnumerateDirectorySetupCleanup; } // // Query the information from the parent of the real mapping. // Status = NcQueryDirectoryFile( FltObjects->Instance, RealParentFileObj, QueryBuffer, QueryBufferLength, InformationClass, TRUE,//Return single entry &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName, FALSE,//restart scan &QueryBufferLengthRead); if (Status == STATUS_NO_SUCH_FILE) { // // The user mapping does not exist, this is allowed. It means we // have nothing to inject. // DirQryCtx->InjectionEntry.Buffer = NULL; DirQryCtx->InjectionEntry.CurrentOffset = 0; ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG ); QueryBuffer = NULL; Status = STATUS_SUCCESS; } else if (!NT_SUCCESS( Status )) { // // An unexpected error occurred, return code. // goto NcEnumerateDirectorySetupCleanup; } else { // // Now we have to munge the real mapping directory entry into a // user mapping directory entry. // NcSetFileName( QueryBuffer, InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer, InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length, Offsets, TRUE ); NcSetShortName( QueryBuffer, InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Buffer, InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Length, Offsets ); FLT_ASSERT( DirQryCtx->InjectionEntry.Buffer == NULL ); // // Set the injection entry up in the cache. // DirQryCtx->InjectionEntry.Buffer = QueryBuffer; DirQryCtx->InjectionEntry.CurrentOffset = 0; } NcEnumerateDirectorySetupCleanup: if (!NT_SUCCESS( Status )) { if(QueryBuffer != NULL) { ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG ); } } if (RealParentHandle != NULL) { FltClose( RealParentHandle ); } if (RealParentFileObj != NULL) { ObDereferenceObject( RealParentFileObj ); } return Status; }
NTSTATUS FmmOpenMetadata ( __in PFMM_INSTANCE_CONTEXT InstanceContext, __in BOOLEAN CreateIfNotPresent ) /*++ Routine Description: This routine opens or creates the Fmm metadata on the specified instance. Arguments: InstanceContext - Supplies the instance context for this instance. CreateIfNotPresent - Supplies if the directory entry must be created if it is not present Return Value: Returns the status of this operation. Note: The caller must hold the instance context resource exclusive when this routine is called. --*/ { OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatus; UNICODE_STRING fileName; NTSTATUS status; ULONG length; PAGED_CODE(); DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Opening metadata file ... (Volume = %p, CreateIfNotPresent = %X)\n", InstanceContext->Volume, CreateIfNotPresent) ); status = STATUS_SUCCESS; fileName.Buffer = NULL; // // Get the volume name and construct the full metadata filename. // length = FMM_DEFAULT_VOLUME_NAME_LENGTH + FMM_METADATA_FILE_NAME_LENGTH; #pragma warning(push) #pragma warning(disable:4127) // Conditional expression is constant while (TRUE) { #pragma warning(pop) fileName.MaximumLength = (USHORT)length; status = FmmAllocateUnicodeString( &fileName ); if (!NT_SUCCESS( status )) { goto FmmOpenMetadataCleanup; } status = FltGetVolumeName( InstanceContext->Volume, &fileName, &length ); if (NT_SUCCESS( status )) { status = RtlAppendUnicodeToString( &fileName, FMM_METADATA_FILE_NAME ); if (NT_SUCCESS( status )) { break; } } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: Failed to get volume name (Volume = %p, Status = 0x%x)\n", InstanceContext->Volume, status) ); } if (status != STATUS_BUFFER_TOO_SMALL) { goto FmmOpenMetadataCleanup;; } // // Free the filename buffer since a bigger one will be allocated // above // FmmFreeUnicodeString( &fileName ); length += FMM_METADATA_FILE_NAME_LENGTH; } // // Initialize the object attributes and open the file. // InitializeObjectAttributes( &objectAttributes, &fileName, OBJ_KERNEL_HANDLE, NULL, NULL ); RetryFltCreateFile: DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Calling FltCreateFile for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); status = FltCreateFile( Globals.Filter, InstanceContext->Instance, &InstanceContext->MetadataHandle, FILE_ALL_ACCESS, &objectAttributes, &ioStatus, (PLARGE_INTEGER) NULL, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, FILE_SHARE_READ, (CreateIfNotPresent ? FILE_OPEN_IF : FILE_OPEN), 0L, NULL, 0L, 0 ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: FltCreateFile failure for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); if (CreateIfNotPresent && (status == STATUS_OBJECT_PATH_NOT_FOUND)) { // // We need to create the metadata file and the creation failed // because the SystemVolumeInformation folder does not exist. // So, create the folder and try again. // DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Creating SystemVolumeInformation folder for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); status = FltCreateSystemVolumeInformationFolder( InstanceContext->Instance ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); if (NT_SUCCESS( status )) { // // We have sucessfully created the SystemVolumeInformation folder // Try to create the metadata file again // goto RetryFltCreateFile; } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: FltCreateSystemVolumeInformationFolder failure for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); } } goto FmmOpenMetadataCleanup; } // // Retrieve the FileObject from the handle created // status = ObReferenceObjectByHandle( InstanceContext->MetadataHandle, STANDARD_RIGHTS_REQUIRED, *IoFileObjectType, KernelMode, &InstanceContext->MetadataFileObject, NULL ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: Failure to get file object from handle for metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); goto FmmOpenMetadataCleanup; } if (ioStatus.Information == FILE_CREATED) { // // New metadata was created // DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Created new metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // The filter may want to do some initialization on the newly created // metadata file here like adding a header to the file // } else { // // Existing metadata was opened // DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Opened existing metadata file %wZ (Volume = %p, Status = 0x%x)\n", &fileName, InstanceContext->Volume, status) ); // // The filter may want to do some sanity checks on the metadata file here // like validating the header of the file // } // // Here the filter may read the metadata contents and initialize // its in memory data structures with the data from the metadata // file // FmmOpenMetadataCleanup: if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS | DEBUG_TRACE_ERROR, ("[Fmm]: Failed to open metadata (Volume = %p, Status = 0x%x)\n", InstanceContext->Volume, status) ); // // CLose the handle and dereference the file object // if (InstanceContext->MetadataHandle) { // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); FltClose( InstanceContext->MetadataHandle ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); InstanceContext->MetadataHandle = NULL; if (InstanceContext->MetadataFileObject) { ObDereferenceObject( InstanceContext->MetadataFileObject ); InstanceContext->MetadataFileObject = NULL; } } } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Metadata successfully opened (Volume = %p)\n", InstanceContext->Volume) ); // // Set flags to indicate successful open of filter metadata // SetFlag( InstanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED ); } if (fileName.Buffer != NULL) { FmmFreeUnicodeString( &fileName ); } return status; }
VOID FmmCloseMetadata ( __in PFMM_INSTANCE_CONTEXT InstanceContext ) /*++ Routine Description: This routine closes the filters handle to the metadata file. Arguments: InstanceContext - Instance context for this instance. Return Value: Void. Note: The caller must hold the instance context resource when this routine is called. --*/ { PAGED_CODE(); ASSERT( InstanceContext->MetadataHandle ); ASSERT( InstanceContext->MetadataFileObject ); DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: Closing metadata file ... (Volume = %p)\n", InstanceContext->Volume ) ); // // Dereference the file object and close the file handle. // ObDereferenceObject( InstanceContext->MetadataFileObject ); InstanceContext->MetadataFileObject = NULL; // // Mark the beginning of a file system operation // FmmBeginFileSystemOperation( InstanceContext ); FltClose( InstanceContext->MetadataHandle ); // // Mark the end of a file system operation // FmmEndFileSystemOperation( InstanceContext ); InstanceContext->MetadataHandle = NULL; // // Reset flag to indicate filter metadata is closed // ClearFlag( InstanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED ); }