示例#1
0
NTSTATUS
FmmReacquireMetadataFileReferences (
    __inout PFLT_CALLBACK_DATA Cbd
    )
/*++

Routine Description:

    This routine re-acquires references to the metadata file on the specified instance.

Arguments:

    Cbd                 - Supplies a pointer to the callbackData which
                          declares the requested operation.

Return Value:

    Status

Note:

    This routine takes care of the synchronization needed to access the metadata
    file object and handle


    This routine will also NULL the MetadataOpenTriggerFileObject in the instance context
    if it was successfully able to open the metadata file references.


--*/
{

    NTSTATUS status = STATUS_SUCCESS;
    PFMM_INSTANCE_CONTEXT instanceContext = NULL;

    PAGED_CODE();

    //
    //  Get the instance context
    //

    status = FltGetInstanceContext( Cbd->Iopb->TargetInstance,
                                    &instanceContext );
    if (!NT_SUCCESS( status )) {

        DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
                    ("[Fmm]: FmmReacquireMetadataFileReferences -> Failed to get instance context.\n") );

        goto FmmReacquireMetadataFileReferencesCleanup;
    }

    //
    //  Acquire exclusive access to the instance context
    //

    FmmAcquireResourceExclusive( &instanceContext->MetadataResouce );

    if (FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION)) {

        //
        //  If this instance context is in a transition state, it implies that
        //  the instance context lock has been released while sending an operation
        //  down to the file system. The reason for doing so is to prevent a potential
        //  deadlock if an underlying filter sends an IO to the top of the filter
        //  stack while we are holding the resource
        //
        //  We have managed to acquire this resource in this state of transition.
        //  It would be incorrect to use or modify the instance context in any way
        //  in this situation. So we simply let go.
        //

        status = STATUS_FILE_LOCK_CONFLICT;

        DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
                    ("[Fmm]: FmmReacquireMetadataFileReferences -> Failed to get exclusive access to instance context since it is in a state of transition.\n") );
    } else {

        //
        //  Re-open the metadata only if the trigger file object match the file object that
        //  caused this function to be called
        //

        if (instanceContext->MetadataOpenTriggerFileObject == Cbd->Iopb->TargetFileObject) {

            //
            //  Open the filter metadata file (do not read the file since we already have
            //  stuff in memory and do not create if the file does not exist
            //

            if (!FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED )) {

                DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS,
                            ("[Fmm]: FmmReacquireMetadataFileReferences -> Re-acquiring references to metadata handle and file object (InstanceContext = %p, VolumeFileObject = %p)\n",
                             instanceContext,
                             Cbd->Iopb->TargetFileObject) );

                status = FmmOpenMetadata( instanceContext,
                                                 FALSE );

                //
                //  Reset the trigger file object since the volume open failed.
                //

                instanceContext->MetadataOpenTriggerFileObject = NULL;

            } else {

                DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS,
                            ("[Fmm]: FmmReacquireMetadataFileReferences -> Exit without attempting to re-acquire references to metadata handle and file object (InstanceContext = %p, VolumeFileObject = %p, MetadataOpenTriggerFileObject = %p, MetadataAlreadyOpen = 0x%x)\n",
                             instanceContext,
                             Cbd->Iopb->TargetFileObject,
                             instanceContext->MetadataOpenTriggerFileObject,
                             FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED )) );
            }
        } else {


            DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS,
                        ("[Fmm]: FmmReacquireMetadataFileReferences -> Exit without attempting to re-acquire references to metadata handle and file object (InstanceContext = %p, VolumeFileObject = %p, MetadataOpenTriggerFileObject = %p, MetadataAlreadyOpen = 0x%x)\n",
                         instanceContext,
                         Cbd->Iopb->TargetFileObject,
                         instanceContext->MetadataOpenTriggerFileObject,
                         FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED )) );
        }
    }

    //
    //  Relinquish exclusive access to the instance context
    //

    FmmReleaseResource( &instanceContext->MetadataResouce );


FmmReacquireMetadataFileReferencesCleanup:

    //
    // Release the references we have acquired
    //

    if (instanceContext != NULL) {

        FltReleaseContext( instanceContext );
    }


    return status;;

}
NTSTATUS
FmmInstanceSetup (
    _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. This
    gives us a chance to decide if we need to attach to this volume or not.

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

--*/
{
    PFMM_INSTANCE_CONTEXT instanceContext = NULL;
    PDEVICE_OBJECT diskDeviceObject;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER( VolumeDeviceType );

    PAGED_CODE();

    DebugTrace( DEBUG_TRACE_INSTANCES,
                ("[Fmm]: Instance setup started (Volume = %p, Instance = %p)\n",
                 FltObjects->Volume,
                 FltObjects->Instance) );

    //
    //  Check if the file system mounted is ntfs or fat
    //
    //  The sample picks NTFS, FAT and ReFS as examples. The metadata
    //  handling demostrated in the sample can be applied
    //  to any file system
    //

    if (VolumeFilesystemType != FLT_FSTYPE_NTFS && VolumeFilesystemType != FLT_FSTYPE_FAT && VolumeFilesystemType != FLT_FSTYPE_REFS) {

        //
        //  An unknown file system is mounted which we do not care
        //

        DebugTrace( DEBUG_TRACE_INSTANCES,
                    ("[Fmm]: Unsupported file system mounted (Volume = %p, Instance = %p)\n",
                     FltObjects->Volume,
                     FltObjects->Instance) );

        status = STATUS_NOT_SUPPORTED;
        goto FmmInstanceSetupCleanup;
    }

    //
    //  Get the disk device object and make sure it is a disk device type and does not
    //  have any of the device characteristics we do not support.
    //
    //  The sample picks the device characteristics to demonstrate how to access and
    //  check the device characteristics in order to make a decision to attach. The
    //  metadata handling demostrated in the sample is not limited to the
    //  characteristics we have used in the sample.
    //

    status = FltGetDiskDeviceObject( FltObjects->Volume, &diskDeviceObject );

    if (!NT_SUCCESS( status )) {

        DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR,
                    ("[Fmm]: Failed to get device object (Volume = %p, Status = 0x%08X)\n",
                     FltObjects->Volume,
                     status) );
        goto FmmInstanceSetupCleanup;
    }

    if (diskDeviceObject->DeviceType != FILE_DEVICE_DISK ||
        FlagOn( diskDeviceObject->Characteristics, FMM_UNSUPPORTED_DEVICE_CHARACS )) {

        DebugTrace( DEBUG_TRACE_INSTANCES,
                    ("[Fmm]: Unsupported device type or device characteristics (Volume = %p, Instance = %p DiskDeviceObjectDeviceTYpe = 0x%x, DiskDeviceObjectCharacteristics = 0x%x)\n",
                     FltObjects->Volume,
                     FltObjects->Instance,
                     diskDeviceObject->DeviceType,
                     diskDeviceObject->Characteristics) );

        ObDereferenceObject( diskDeviceObject );
        status = STATUS_NOT_SUPPORTED;
        goto FmmInstanceSetupCleanup;
    }

    ObDereferenceObject( diskDeviceObject );

    //
    //  Allocate and initialize the context for this volume
    //

    status = FltAllocateContext( FltObjects->Filter,
                                 FLT_INSTANCE_CONTEXT,
                                 FMM_INSTANCE_CONTEXT_SIZE,
                                 NonPagedPool,
                                 &instanceContext );

    if( !NT_SUCCESS( status )) {

        DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR,
                    ("[Fmm]: Failed to allocate instance context (Volume = %p, Instance = %p, Status = 0x%08X)\n",
                     FltObjects->Volume,
                     FltObjects->Instance,
                     status) );

        goto FmmInstanceSetupCleanup;
    }

    FLT_ASSERT( instanceContext != NULL );

    RtlZeroMemory( instanceContext, FMM_INSTANCE_CONTEXT_SIZE );

    instanceContext->Flags = 0;
    instanceContext->Instance = FltObjects->Instance;
    instanceContext->FilesystemType = VolumeFilesystemType;
    instanceContext->Volume = FltObjects->Volume;
    ExInitializeResourceLite( &instanceContext->MetadataResource );


    //
    //  Set the instance context.
    //

    status = FltSetInstanceContext( FltObjects->Instance,
                                    FLT_SET_CONTEXT_KEEP_IF_EXISTS,
                                    instanceContext,
                                    NULL );

    if( !NT_SUCCESS( status )) {

        DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR,
                    ("[Fmm]: Failed to set instance context (Volume = %p, Instance = %p, Status = 0x%08X)\n",
                     FltObjects->Volume,
                     FltObjects->Instance,
                     status) );
        goto FmmInstanceSetupCleanup;
    }

    //
    //  Acquire exclusive access to the instance context
    //

    FmmAcquireResourceExclusive( &instanceContext->MetadataResource );

    //
    //  Sanity - the instance context cannot be in a transition state during instance setup
    //

    FLT_ASSERT( !FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION) );

    //
    //  Open the filter metadata on disk
    //
    //  The sample will attach to volume if it finds its metadata file on the volume.
    //  If this is a manual attachment then the sample filter will create its metadata
    //  file and attach to the volume.
    //

    status = FmmOpenMetadata( instanceContext,
                              BooleanFlagOn( Flags, FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT ) );

    //
    //  Relinquish exclusive access to the instance context
    //

    FmmReleaseResource( &instanceContext->MetadataResource );

    if (!NT_SUCCESS( status )) {

        goto FmmInstanceSetupCleanup;
    }


FmmInstanceSetupCleanup:

    //
    //  If FltAllocateContext suceeded then we MUST release the context,
    //  irrespective of whether FltSetInstanceContext suceeded or not.
    //
    //  FltAllocateContext increments the ref count by one.
    //  A successful FltSetInstanceContext increments the ref count by one
    //  and also associates the context with the file system object
    //
    //  FltReleaseContext decrements the ref count by one.
    //
    //  When FltSetInstanceContext succeeds, calling FltReleaseContext will
    //  leave the context with a ref count of 1 corresponding to the internal
    //  reference to the context from the file system structures
    //
    //  When FltSetInstanceContext fails, calling FltReleaseContext will
    //  leave the context with a ref count of 0 which is correct since
    //  there is no reference to the context from the file system structures
    //

    if ( instanceContext != NULL ) {

        FltReleaseContext( instanceContext );
    }


    if (NT_SUCCESS( status )) {

        DebugTrace( DEBUG_TRACE_INSTANCES,
                    ("[Fmm]: Instance setup complete (Volume = %p, Instance = %p). Filter will attach to the volume.\n",
                     FltObjects->Volume,
                     FltObjects->Instance) );
    } else {

        DebugTrace( DEBUG_TRACE_INSTANCES,
                    ("[Fmm]: Instance setup complete (Volume = %p, Instance = %p). Filter will not attach to the volume.\n",
                     FltObjects->Volume,
                     FltObjects->Instance) );
    }

    //
    //  If this is an automatic attachment (mount, load, etc) and we are not 
    //  attaching to this volume because we do not support attaching to this 
    //  volume, then simply return STATUS_FLT_DO_NOT_ATTACH. If we return 
    //  anything else fltmgr logs an event log indicating failure to attach. 
    //  Since this failure to attach is not really an error, we do not want 
    //  this failure to be logged as an error in the event log. For all other
    //  error codes besides the ones we consider "normal", if is ok for fltmgr
    //  to actually log the failure to attach.
    //
    //  If this is a manual attach attempt that we have failed then we want to 
    //  give the user a clear indication of why the attachment failed. Hence in 
    //  this case, we will not override the error status with STATUS_FLT_DO_NOT_ATTACH
    //  irrespective of the cause of the failure to attach
    //

    if (status == STATUS_NOT_SUPPORTED && 
       !FlagOn( Flags, FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT )) {

        status = STATUS_FLT_DO_NOT_ATTACH;
    }

    return status;
}