示例#1
0
void EventManager::update()
{
	while(m_bufferCurPos != m_bufferAddPos)
	{
		const IEvent* evt = (IEvent*)(m_eventBuffer+m_bufferCurPos);
		FLT_ASSERT(evt!=0);

		EventQueues::iterator map_iter = m_events.find(evt->getUID());
		if(map_iter!=m_events.end())
		{
			const ReceiverList& receivers = map_iter->second;
			for(ReceiverList::const_iterator list_iter=receivers.begin(); list_iter!=receivers.end(); ++list_iter)
			{
				FLT_ASSERT((*list_iter)!=0);
				if((*list_iter)->onEvent(*evt))
					break;
			}
		}

		m_bufferCurPos += k_max_event_size;
		if(m_bufferCurPos >= k_event_buffer_size)
		{
			m_bufferCurPos = 0;
		}
	}
}
示例#2
0
UCHAR TxNotificationToMinorCode (
    _In_ ULONG TxNotification
    )
/*++

Routine Description:

    This routine has been written to convert a transaction notification code
    to an Irp minor code. This function is needed because RECORD_DATA has a
    UCHAR field for the Irp minor code whereas TxNotification is ULONG. As
    of now all this function does is compute log_base_2(TxNotification) + 1.
    That fits our need for now but might have to be evolved later. This
    function is intricately tied with the enumeration TRANSACTION_NOTIFICATION_CODES
    in mspyLog.h and the case statements related to transactions in the function
    PrintIrpCode (Minispy\User\mspyLog.c).

Arguments:

    TxNotification - The transaction notification received.

Return Value:

    0 if TxNotification is 0;
    log_base_2(TxNotification) + 1 otherwise.

--*/
{
    UCHAR count = 0;

    if (TxNotification == 0)
        return 0;

    //
    //  This assert verifies if no more than one flag is set
    //  in the TxNotification variable. TxNotification flags are
    //  supposed to be mutually exclusive. The assert below verifies
    //  if the value of TxNotification is a power of 2. If it is not
    //  then we will break.
    //

    FLT_ASSERT( !(( TxNotification ) & ( TxNotification - 1 )) );

    while (TxNotification) {

        count++;

        TxNotification >>= 1;

        //
        //  If we hit this assert then we have more notification codes than
        //  can fit in a UCHAR. We need to revaluate our approach for
        //  storing minor codes now.
        //

        FLT_ASSERT( count != 0 );
    }

    return ( count );
}
示例#3
0
	void Phy2dWorld::selectedActor(Phy2dActor* actor)
	{
		FLT_ASSERT(actor!=0);
		FLT_ASSERT(!actor->isSelected());

		if(actor!=0)
		{
			actor->setSelected(true);
			m_editorSelectedActors.push_back(actor);
		}
	}
示例#4
0
	void Phy2dWorld::deselectedActor(Phy2dActor* actor)
	{
		FLT_ASSERT(actor!=0);
		FLT_ASSERT(actor->isSelected());

		if(actor!=0)
		{
			actor->setSelected(false);
			array_t<Phy2dActor*>::iterator iter = find(m_editorSelectedActors.begin(), m_editorSelectedActors.end(), actor);
			m_editorSelectedActors.erase(iter);
		}
	}
示例#5
0
int Reader::ReadLine(char* cbuf, int buflen)
{
	int lineLength = 0;
	char c = 0;
	
	while(true)
	{
		int count = m_stream.Read(&c, sizeof(char));

		// End of stream and no character read?
		if(count <= 0 && lineLength == 0)
			return -1;

		FLT_ASSERT(buflen > lineLength);

		if(count == 0 || buflen < lineLength + 1)
			break;

		if(c == '\r')
		{
			// Also skip the following '\n' ?
			count = m_stream.Read(&c, sizeof(char));
			
			// Oups, need to go back by one char
			if(c != '\n' && count > 0)
			{
	//			int before = m_stream.Tell();
				m_stream.Seek(-1, io::cur);
//				int after = m_stream.Tell();
				//int diff = after - before;
			}
			
			break;
		}
		else if(c == '\n')
		{
			break;
		}
		else
		{
			cbuf[lineLength++] = c;
		}
	}
	
	FLT_ASSERT(buflen > lineLength);
	cbuf[lineLength] = 0;
	return lineLength;
}
示例#6
0
	void Phy2dWorld::setCameraZoomLimit(f32 minZoom, f32 maxZoom)
	{
		FLT_ASSERT(minZoom<=maxZoom && minZoom>0);
		
		m_cameraZoomMin = minZoom;	
		m_cameraZoomMax = maxZoom;
	}
示例#7
0
NTSTATUS
FltpDeviceControlHandler(_In_ PDEVICE_OBJECT DeviceObject,
                         _Inout_ PIRP Irp)
{
    PIO_STACK_LOCATION StackPtr;
    ULONG ControlCode;
    NTSTATUS Status;

    StackPtr = IoGetCurrentIrpStackLocation(Irp);
    FLT_ASSERT(StackPtr->MajorFunction == IRP_MJ_DEVICE_CONTROL);

    ControlCode = StackPtr->Parameters.DeviceIoControl.IoControlCode;
    switch (ControlCode)
    {
        case IOCTL_LOAD_FILTER:
            Status = HandleLoadUnloadIoctl(DeviceObject, Irp);
            break;

        case IOCTL_UNLOAD_FILTER:
            Status = HandleLoadUnloadIoctl(DeviceObject, Irp);
            break;

        case IOCTL_FIND_FIRST_FILTER:
            Status = HandleFindFirstIoctl(DeviceObject, Irp);
            break;

        default:
            Status = STATUS_INVALID_PARAMETER;
            break;
    }

    return Status;
}
NTSTATUS
DriverEntry (
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    This is the initialization routine for this miniFilter driver. This
    registers the miniFilter with FltMgr and initializes all
    its 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:

    Returns STATUS_SUCCESS.

--*/
{
    NTSTATUS status;

    UNREFERENCED_PARAMETER( RegistryPath );

    //
    //  Register with FltMgr
    //

    status = FltRegisterFilter( DriverObject,
                                &FilterRegistration,
                                &NullFilterData.FilterHandle );

    FLT_ASSERT( NT_SUCCESS( status ) );

    if (NT_SUCCESS( status )) {

        //
        //  Start filtering i/o
        //

        status = FltStartFiltering( NullFilterData.FilterHandle );

        if (!NT_SUCCESS( status )) {
            FltUnregisterFilter( NullFilterData.FilterHandle );
        }
    }
    return status;
}
示例#9
0
VOID FLTAPI
UcaInstanceContextCleanupCallback(_In_ PUCA_INSTANCE_CONTEXT InstanceContext,
                                  _In_ FLT_CONTEXT_TYPE ContextType)
{
    UNREFERENCED_PARAMETER(ContextType);

    PAGED_CODE();
    __debugbreak();
    FLT_ASSERT(ContextType == FLT_INSTANCE_CONTEXT);

    ExFreePoolWithTag(&InstanceContext->VolumeGuidName, UCA_POOL_TAG);
}
示例#10
0
文件: Fetch.c 项目: aleksk/LazyCopy
static
VOID
LcWriteCallback (
    _In_ PFLT_CALLBACK_DATA CallbackData,
    _In_ PFLT_CONTEXT       Context
    )
/*++

Summary:

    This function is a completion callback for the asynchronous I/O write operation.

Arguments:

    CallbackData - Pointer to the callback data structure for the I/O operation.

    Context      - Custom context pointer.

Return Value:

    None.

--*/
{
    PWRITE_CALLBACK_CONTEXT context = (PWRITE_CALLBACK_CONTEXT)Context;

    FLT_ASSERT(CallbackData != NULL);
    FLT_ASSERT(Context      != NULL);

    PAGED_CODE();

    context->Status       = CallbackData->IoStatus.Status;
    context->BytesWritten = NT_SUCCESS(context->Status)
                            ? (ULONG)CallbackData->IoStatus.Information
                            : 0;

    // Notify listeners that write operation has completed for the current chunk.
    KeSetEvent(context->Event, IO_NO_INCREMENT, FALSE);
}
示例#11
0
void EventManager::raiseEvent(const IEvent& event)
{
	int size = ((IEvent*)(&event))->getSize();

	FLT_ASSERT(size<k_max_event_size);

	memcpy( (m_eventBuffer+m_bufferAddPos), &event, size);
	m_bufferAddPos += k_max_event_size;

	if(m_bufferAddPos >= k_event_buffer_size)
	{
		m_bufferAddPos = 0;
	}
}
示例#12
0
VOID FLTAPI
UcaStreamContextCleanupCallback(_In_ PUCA_STREAM_CONTEXT StreamContext,
                                _In_ FLT_CONTEXT_TYPE ContextType)
{
    PAGED_CODE();

    //__debugbreak();

    FLT_ASSERT(ContextType == FLT_STREAM_CONTEXT || ContextType == FLT_FILE_CONTEXT);

    if (StreamContext->FileNameInfo)
    {
        FltReleaseFileNameInformation(StreamContext->FileNameInfo);
        StreamContext->FileNameInfo = NULL;
    }
}
示例#13
0
s32 StubDevice::getRandS32(s32 min, s32 max) const
{
	if (min > max)
	{
		int t		= min;
		min	= max;
		max	= t;
	}

	long long rnd	= getRandS32() >> 2;
	s32	 range		= max - min;
	
	s32 res = (s32)(min + (rnd % range));
	FLT_ASSERT(res >= min && res < max);

	return res;
}
示例#14
0
VOID 
NcSetShortName (
    _In_ PVOID Entry,
    _In_ PWSTR NewShortName,
    _In_ USHORT Length,
    _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets
    )
/*++

Routine Description:

    Sets a new short name into an entry if the information class
    supports short names.

Arguments:

    Entry - Pointer to the start of an entry.

    NewShortName - Pointer to the new shortname.

    Length - The length of the short name in bytes.

    Offsets - Offsets structure for the information class.

Return Value:

    None.

--*/
{
    PWSTR NamePtr;
    PCCHAR NameLength;

    PAGED_CODE();

    if( Offsets->ShortNamePresent ) {

        NamePtr = NcGetShortName( Entry, Offsets );
        NameLength = Add2Ptr( Entry, Offsets->ShortNameLengthDist );

        FLT_ASSERT( Length <= (12 * sizeof(WCHAR)) );

        RtlCopyMemory(NamePtr, NewShortName, Length );
        *NameLength = (UCHAR) Length;
    }
}
示例#15
0
NTSTATUS
HandleLoadUnloadIoctl(_In_ PDEVICE_OBJECT DeviceObject,
                      _Inout_ PIRP Irp)
{
    PIO_STACK_LOCATION StackPtr;
    UNICODE_STRING Name;
    PFILTER_NAME FilterName;
    ULONG BufferLength;
    ULONG ControlCode;

    /* Get the IOCTL data from the stack pointer */
    StackPtr = IoGetCurrentIrpStackLocation(Irp);
    BufferLength = StackPtr->Parameters.DeviceIoControl.InputBufferLength;
    ControlCode = StackPtr->Parameters.DeviceIoControl.IoControlCode;

    FLT_ASSERT(ControlCode == IOCTL_LOAD_FILTER || ControlCode == IOCTL_UNLOAD_FILTER);

    /* Make sure the buffer is valid */
    if (BufferLength < sizeof(FILTER_NAME))
        return STATUS_INVALID_PARAMETER;

    /* Convert the file name buffer into a string */
    FilterName = (PFILTER_NAME)Irp->AssociatedIrp.SystemBuffer;
    Name.Length = FilterName->Length;
    Name.MaximumLength = FilterName->Length;
    Name.Buffer = (PWCH)((PCHAR)FilterName + FIELD_OFFSET(FILTER_NAME, FilterName[0]));

    /* Forward the request to our Flt routines */
    if (ControlCode == IOCTL_LOAD_FILTER)
    {
        return FltLoadFilter(&Name);
    }
    else
    {
        return FltUnloadFilter(&Name);
    }
}
示例#16
0
VOID
SpyFreeRecord (
    _In_ PRECORD_LIST Record
    )
/*++

Routine Description:

    Free the given buffer

    NOTE:  This code must be NON-PAGED because it can be called on the
           paging path or at DPC level.

Arguments:

    Record - the buffer to free

Return Value:

    None.

--*/
{
    if (FlagOn(Record->LogRecord.RecordType,RECORD_TYPE_FLAG_STATIC)) {

        //
        // This was our static buffer, mark it available.
        //

        FLT_ASSERT(MiniFSWatcherData.StaticBufferInUse);
        MiniFSWatcherData.StaticBufferInUse = FALSE;

    } else {

        SpyFreeBuffer( Record );
    }
}
示例#17
0
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS status;

	UNREFERENCED_PARAMETER(RegistryPath);

	KdPrint(("Passthrough!DriverEntry: entered\n"));

	status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);

	FLT_ASSERT(NT_SUCCESS(status));

	if (NT_SUCCESS(status))
	{
		status = FltStartFiltering(gFilterHandle);
		if (!NT_SUCCESS(status))
		{
			FltUnregisterFilter(gFilterHandle);
		}
		KdPrint(("Passthrough!DriverEntry: start mini filter \n"));
	}

	return status;
}
示例#18
0
NTSTATUS
NcGenerateFileName (
    _In_ PFLT_INSTANCE Instance,
    _In_ PFILE_OBJECT FileObject,
    _In_opt_ PFLT_CALLBACK_DATA Data,
    _In_ FLT_FILE_NAME_OPTIONS NameOptions,
    _Out_ PBOOLEAN CacheFileNameInformation,
    _Inout_ PFLT_NAME_CONTROL OutputNameControl
    )
{
    //
    //  Status vars
    //

    NTSTATUS Status;

    //
    //  State lookup vars
    //

    BOOLEAN Opened = (BOOLEAN)(FileObject->FsContext != NULL);                                       // True if file object is opened.
    BOOLEAN ReturnShortName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_SHORT);   // True if the user is requesting short name
    BOOLEAN ReturnOpenedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_OPENED); // True if user is requesting opened name.
    BOOLEAN ReturnNormalizedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_NORMALIZED); // True if user is requesting normalized name.
    BOOLEAN IgnoreCase;
    FLT_FILE_NAME_OPTIONS NameQueryMethod = FltGetFileNameQueryMethod( NameOptions );
    FLT_FILE_NAME_OPTIONS NameFlags = FLT_VALID_FILE_NAME_FLAGS & NameOptions;

    //
    //  File name information
    //

    PFLT_FILE_NAME_INFORMATION LowerNameInfo = NULL; // File name as reported by lower name provider. Will always be down real mapping.
    PFLT_FILE_NAME_INFORMATION ShortInfo = NULL;  // We will use ShortInfo to store the short name if needed.

    //
    //  Contexts
    //
    
    PNC_INSTANCE_CONTEXT InstanceContext = NULL;

    //
    //  Overlap
    //
    
    NC_PATH_OVERLAP RealOverlap;
    UNICODE_STRING RealRemainder = EMPTY_UNICODE_STRING;

    //
    //  Temp storage
    //
    
    UNICODE_STRING MungedName = EMPTY_UNICODE_STRING;
    
    //
    //  Temp pointer
    //
    
    PUNICODE_STRING Name = NULL; // Pointer to the name we are going to use.

    PAGED_CODE();

    FLT_ASSERT( IoGetTopLevelIrp() == NULL );

    //
    //  This should never happen, but let's be safe.
    //

    if (!ReturnShortName &&
        !ReturnOpenedName &&
        !ReturnNormalizedName) {

        FLT_ASSERT( FALSE );
        Status = STATUS_NOT_SUPPORTED;
        goto NcGenerateFileNameCleanup;
    }

    RealOverlap.EntireFlags = 0;

    //
    //  To prevent infinite recursion, calls to FltGetFileNameInformation 
    //  from generate file name callbacks should not target current provider.
    //

    ClearFlag( NameFlags, FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER );

    //
    //  Fetch the instance context.
    //

    Status = FltGetInstanceContext( Instance, &InstanceContext );   

    if (!NT_SUCCESS( Status )) {

        goto NcGenerateFileNameCleanup;
    }

    //
    //  We need to know what the name provider under us thinks the file is called.
    //  If the caller wants the normalized name we query that, otherwise we query
    //  the opened name because we have to compare the full path of the file vs.
    //  the real mapping to determine if the file is mapped.
    //

    Status = NcGetFileNameInformation( Data,
                                       FileObject,
                                       Instance,
                                       (ReturnNormalizedName ? FLT_FILE_NAME_NORMALIZED
                                                             : FLT_FILE_NAME_OPENED) |
                                           NameQueryMethod |
                                           NameFlags,
                                       &LowerNameInfo );

    if (!NT_SUCCESS( Status )) {

        goto NcGenerateFileNameCleanup;
    }

    Status = FltParseFileNameInformation( LowerNameInfo );

    if (!NT_SUCCESS( Status )) {

        goto NcGenerateFileNameCleanup;
    }

    //
    //  Issues With Pre-open path:
    //
    //  1) Poison name cache below name provider:
    //    If a filter above a name provider calls FltGetFileNameInformation on a 
    //    file object in his precreate callback, fltmgr will call the name 
    //    provider's generate name callback before the name provider's pre create
    //    callback is invoked. Name providers by their nature change names in their
    //    pre-create. Because the name provider has not had the opportunity to 
    //    modify the name yet, we need to make sure that fltmgr does not cache the name we 
    //    return below us, so we set the FLT_FILE_NAME_DO_NOT_CACHE flag.
    //    //TODO: TRY TO GET ACROSS THAT THIS IS A NAME CHANGER PROBLEM, NOT ALL NAME PROVIDERS NEED TO.
    //

    if (!Opened) {

        SetFlag( NameFlags, FLT_FILE_NAME_DO_NOT_CACHE );

        if (Data) {

            //
            //  NT supports case sensitive and non-case sensitive naming in file systems.
            //  This is handled on a per-open basis. Weather an open is case senstive is 
            //  determined by the FO_OPENED_CASE_SENSITIVE flag on the file object.
            //  In pre-create the SL_CASE_SENSITIVE flag on the create IRP specifies the mode.
            //
            //  If this is on an unopened FileObject, it had better be pre-create so we know
            //  how to process the operation.  If we are queried on an unopened FileObject
            //  at any other time we have no way to handle the request.
            //

            FLT_ASSERT( Data->Iopb->MajorFunction == IRP_MJ_CREATE ||
                        Data->Iopb->MajorFunction == IRP_MJ_NETWORK_QUERY_OPEN );

            IgnoreCase = !BooleanFlagOn( Data->Iopb->OperationFlags, SL_CASE_SENSITIVE );

        } else {

            //
            //  If people do unsafe queries on preopened IOs, we cannot
            //  determine if the open is case sensitive or not.
            //  So we cannot determine if this open is down the mapping.
            //  fail.
            //

            FLT_ASSERT( FALSE );
            Status = STATUS_INVALID_PARAMETER;
            goto NcGenerateFileNameCleanup;

        }

    } else {

        //
        //  After a file has been opened, the case sensitivity is stored in the file object.
        //

        IgnoreCase = !BooleanFlagOn( FileObject->Flags, FO_OPENED_CASE_SENSITIVE );
    }

    //
    //  Calculate the overlap with the real mapping.
    //

    NcComparePath( &LowerNameInfo->Name,
                   &InstanceContext->Mapping.RealMapping,
                   &RealRemainder,
                   IgnoreCase,
                   TRUE,
                   &RealOverlap );

    //
    //  Whether we munge depends on what name is requested.
    //

    if (ReturnOpenedName ||
        ReturnNormalizedName) {

        if (Opened &&
            RealOverlap.InMapping) {

            //
            //  We munge the opened name if it overlaps with the real mapping.
            //  The returned path will be down the user mapping.
            //

            Status = NcConstructPath( &InstanceContext->Mapping.UserMapping,
                                      &RealRemainder,
                                      TRUE,
                                      &MungedName);

            if (!NT_SUCCESS( Status )) {

                goto NcGenerateFileNameCleanup;
            }

            Name = &MungedName;

        } else {

            //
            //  We return the queried result if the path is not in the
            //  mapping.
            //

            Name = &LowerNameInfo->Name;

        }

    } else if (ReturnShortName) {

        //
        //  Note that unlike opened names, a query for a shortname only returns
        //  the final component, not the full path.
        //

        // TODO: Assert not preopen

        if (RealOverlap.Match) {

            //
            //  The opened path is the mapping path.
            //  This means that if we queried the filesystem
            //  he would return the wrong path.
            //
            //  Luckily, we can just use the mapping.
            //

            Name = &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName;

        } else {

            //
            //  We have to query below us to get the short name.
            //

            Status = NcGetFileNameInformation( Data,
                                               FileObject,
                                               Instance,
                                               FLT_FILE_NAME_SHORT | 
                                                   NameQueryMethod |
                                                   NameFlags,
                                               &ShortInfo );

            if (!NT_SUCCESS( Status )) {

                goto NcGenerateFileNameCleanup;
            }

            Status = FltParseFileNameInformation( ShortInfo );

            if (!NT_SUCCESS(Status)) {

                goto NcGenerateFileNameCleanup;
            }

            //
            //  Set name to returned name.
            //

            Name = &ShortInfo->Name;
        }
    }

    FLT_ASSERT( Name != NULL );

    //
    //  Try to grow the namechanger's record to accommodate the result.
    //

    Status = FltCheckAndGrowNameControl( OutputNameControl, Name->Length );

    if (NT_SUCCESS( Status )) {

        //
        //  Copy the new name into the buffer.
        //

        RtlCopyUnicodeString( &OutputNameControl->Name, Name );
        *CacheFileNameInformation = TRUE;
    }

NcGenerateFileNameCleanup:

    if (LowerNameInfo != NULL) {

        FltReleaseFileNameInformation( LowerNameInfo );
    }

    if (ShortInfo != NULL) {

        FltReleaseFileNameInformation( ShortInfo );
    }

    if (InstanceContext != NULL) {

        FltReleaseContext( InstanceContext );
    }

    if (MungedName.Buffer != NULL) {

        ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG );
    }

    return Status;
}
示例#19
0
NTSTATUS
FmmIsImplicitVolumeLock( 
    _In_ PFLT_CALLBACK_DATA Cbd,
    _Out_ PBOOLEAN IsLock
    )
/*++

Routine Description:

    This routine determines if an open is a implcit volume lock.

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

    IsLock                - Supplies a pointer to a user allocated boolean
                            which is used to tell the user wheather the
                            operation is an implied volume lock.
Return Value:
 
    Returns STATUS_SUCCESS if the the function determined wheather or not
    the operation was a volume lock. On STATUS_SUCCESS it is safe to check 
    IsLock to get the answer. Otherwise, the check failed and we dont know
    if it is a lock or not. STATUS_INVALID_PARAMETER indicates that the
    volume's file system type is unrecognized by the check function. This is
    an error code.

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    PFMM_INSTANCE_CONTEXT instanceContext = NULL;
    USHORT shareAccess;
    ACCESS_MASK prevAccess;

    PAGED_CODE();

    //
    //  Get the instance context so we know 
    //  which file system we are attached to.
    //

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

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

    FLT_ASSERT( instanceContext != NULL );

    //
    //  Now check to see if the open is an implied volume lock
    //  on this filesystem.
    //

    shareAccess = Cbd->Iopb->Parameters.Create.ShareAccess;
    prevAccess = Cbd->Iopb->Parameters.Create.SecurityContext->DesiredAccess;

    switch (instanceContext->FilesystemType) {

        case FLT_FSTYPE_REFS:
            *IsLock = ((!BooleanFlagOn( shareAccess, FILE_SHARE_WRITE | FILE_SHARE_DELETE)) &&
                       (BooleanFlagOn( prevAccess,(FILE_WRITE_DATA | FILE_APPEND_DATA) )));
            status = STATUS_SUCCESS;
            break;

        case FLT_FSTYPE_NTFS:
            *IsLock = ((!BooleanFlagOn( shareAccess, FILE_SHARE_WRITE | FILE_SHARE_DELETE)) &&
                          (BooleanFlagOn( prevAccess,(FILE_WRITE_DATA | FILE_APPEND_DATA) )));
            status = STATUS_SUCCESS;
            break;

        case FLT_FSTYPE_FAT:
            *IsLock = (!BooleanFlagOn( shareAccess, FILE_SHARE_WRITE | FILE_SHARE_DELETE));
            status = STATUS_SUCCESS;
            break;

        default:
            status = STATUS_INVALID_PARAMETER;
            break;
    }

FmmIsImplicitVolumeLockCleanup:

    if (instanceContext != NULL ) {

        FltReleaseContext( instanceContext );
    }

    return status;
}
示例#20
0
NTSTATUS 
NcGetFileNameInformation(
    _In_opt_ PFLT_CALLBACK_DATA Data,
    _In_opt_ PFILE_OBJECT FileObject,
    _In_opt_ PFLT_INSTANCE Instance,
    _In_ FLT_FILE_NAME_OPTIONS NameOptions,
    _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation 
    )
/*++

Routine Description:

    This function is a wrapper to call the correct variant of
    FltGetFileNameInformation depending on the information we happen to
    have available.

Arguments:

    Data - Pointer to the callback data structure associated with a request.
        This is optional, but if not specified, FileObject and Instance must
        be supplied.

    FileObject - Pointer to the file object to query a name on.  Optional,
        but if not supplied, Data must be supplied.

    Instance - Pointer to the instance of our filter to query the name on.
        Optional, but if not supplied, Data must be supplied.

    NameOptions - FLT_FILE_NAME_* flags for this request.

    FileNameInformation - On output, contains the file name information
        resulting from this query.  On failure, contents are undefined.
        On success, caller is responsible for releasing this with
        FltReleaseFileNameInformation.

Return Value:

    Returns the status of the operation.

--*/
{
    NTSTATUS Status;

    PAGED_CODE();

    FLT_ASSERT( Data || FileObject );

    *FileNameInformation = NULL;

    if (ARGUMENT_PRESENT( Data )) {

        Status = FltGetFileNameInformation( Data,
                                            NameOptions,
                                            FileNameInformation );

    } else if (ARGUMENT_PRESENT( FileObject )) {

        Status = FltGetFileNameInformationUnsafe( FileObject,
                                                  Instance,
                                                  NameOptions,
                                                  FileNameInformation );
    //
    //  This should never happen, as either Data or FileObject must be non-NULL.
    //

    } else {

        FLT_ASSERT( FALSE );
        Status = STATUS_INVALID_PARAMETER;
    }

    return Status;
}
示例#21
0
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;
}
VOID
FmmInstanceTeardownComplete (
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
    )
/*++

Routine Description:

    This routine is called at the end of instance teardown.

Arguments:

    FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
        opaque handles to this filter, instance and its associated volume.

    Flags - Reason why this instance is been deleted.

Return Value:

    None.

--*/
{
    PFMM_INSTANCE_CONTEXT instanceContext;
    NTSTATUS status;

    UNREFERENCED_PARAMETER( Flags );

    PAGED_CODE();

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

    status = FltGetInstanceContext( FltObjects->Instance,
                                    &instanceContext );

    if (NT_SUCCESS( status )) {

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

        FmmAcquireResourceExclusive( &instanceContext->MetadataResource );

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

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


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

            //
            //  Close the metadata file
            //

            FmmCloseMetadata( instanceContext );
        }


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

        FmmReleaseResource( &instanceContext->MetadataResource );

        FltReleaseContext( instanceContext );
    }

    DebugTrace( DEBUG_TRACE_INSTANCES,
                ("[Fmm]: Instance teardown complete ended (Instance = %p)\n",
                 FltObjects->Instance) );
}
示例#23
0
文件: Fetch.c 项目: aleksk/LazyCopy
static
_Check_return_
NTSTATUS
LcFetchFileByChunks (
    _In_  PCFLT_RELATED_OBJECTS FltObjects,
    _In_  HANDLE                SourceFileHandle,
    _In_  PLARGE_INTEGER        SourceFileSize,
    _Out_ PLARGE_INTEGER        BytesCopied
    )
/*++

Summary:

    This function copies the original file from the 'SourceFileHandle' to the currently opened
    file ('FltObjects->FileObject') by chunks.

    It maintains its own list of chunks, and extends it, if there are no chunks available to read into.
    Write operation goes from one chunk to another in a sequential order. If the next chunk is empty,
    write waits for the read to be completed, and proceeds.

    There are simple rules for chunks allocation:
    1. Up to two chunks are initially allocated:
       a) If the file is smaller than the 'ChunkSize', only one chunk is allocated with buffer
          that is equal to the file size.
       b) If the file is larger than the 'ChunkSize', two chunks are allocated, taking the
          file size into account for the second chunk size.
    2. If all chunks currently allocated are full and awaiting to be written to a disk, and
       the current amount of chunks is lesser than 'MaxChunks', an additional chunk is allocated.

    There is a corner case, when the actual file size differs from the reported one. In this case
    one of the chunks in the list will be smaller than the 'ChunkSize'.
    For example, 'MaxChunks' is 3, ChunkSize is '10', file size reported is '12', and actual file
    size is '25'.
    Two chunks will be initially allocated: [1] 10b; [2] (12-10)=2b.
    Later on, when all of them will be filled in with the data, and EOF will not be received,
    because the actual size is 25b, another chunk [3] of size 10b (ChunkSize) will be allocated.
    In total, there will be three chunks: 10b, 2b, and 10b.
    We don't reallocate the 2nd chunk, because this driver is supposed to be used with a proper
    filesystems, but making this modification might be a valuable TODO item.

    Let's look at how chunks work.
    All chunks are stored in the doubly-linked list. [Head] node doesn't contain any buffer to
    store data in. Refer to the 'FILE_CHUNK' structure for details.
    MSDN about lists: http://msdn.microsoft.com/en-us/library/windows/hardware/ff563802(v=vs.85).aspx

    For large files we will have two chunks from the beginning.
    [Head] <-> [1] <-> [2] <-> [Head]

    There are pointers for [R]ead and [W]rite.

    When the first chunk is being read, the list will look like the following:
    [Head] <-> [1] <-> [2] <-> [Head]
      [W]      [R]

    [W] is awaiting for the [1] to be filled in with the data before writing it to the disk.

    When the [1] chunk is filled with the data:
    [Head] <-> [1*] <-> [2] <-> [Head]
                [W]     [R]

    [1] is full and is being written to a disk, and we're reading into chunk [2].
    Let's also assume that the reads are faster then writes. When the [2] chunk is
    full, there are no free chunks available:
    [Head] <-> [1*] <-> [2*] <-> [Head]
                [W]      [R]

    If the current amount of chunks is lesser than the 'MaxChunks' value, a new chunk will be
    allocated before the next [R] node. In this case it will be added before [Head] to the end
    of the list, and read will continue:
    [Head] <-> [1*] <-> [2*] <-> [3] <-> [Head]
                [W]              [R]

    Then [W] and [R] finish, and [W] moves to the [2] chunk.
    [Head] <-> [1] <-> [2*] <-> [3*] <-> [Head]
                        [W]      [R]

    [R] sees that [1] chunk is available, and reads into it:
    [Head] <-> [1] <-> [2*] <-> [3*] <-> [Head]
               [R]      [W]

    After [R] finishes reading, there are no free chunks again:
    [Head] <-> [1*] <-> [2*] <-> [3*] <-> [Head]
               [R]       [W]

    A new chunk can be allocated again before the [2]:
    [Head] <-> [1*] <-> [4] <-> [2*] <-> [3*] <-> [Head]
                        [R]      [W]

    With this approach, [R] will fill chunks [1]->[2]->[3]->[1]->[4], and write will
    write them in the same order.
    I.e. allocating a new chunk before the next filled chunk (if the amount of chunks
    is lesser than the 'MaxChunks') makes sure that the data is written sequentially,
    and there is no need to constantly seek in the file.

Arguments:

    FltObjects       - Pointer to the 'FLT_RELATED_OBJECTS' data structure containing
                       opaque handles to this filter, instance, its associated volume and
                       file object.

    SourceFileHandle - Handle to the source file to copy content from.

    SourceFileSize   - Size of the source file.

    BytesCopied      - Pointer to the LARGE_INTEGER structure that receives the amount
                       of bytes copied.

Return Value:

    The return value is the status of the operation.

--*/
{
    NTSTATUS               status                = STATUS_SUCCESS;

    LIST_ENTRY             chunksListHead        = { 0 };
    ULONG                  chunkListLength       = 0;

    // State of the R/W operations.
    BOOLEAN                readComplete          = FALSE;
    BOOLEAN                writeComplete         = FALSE;
    PFILE_CHUNK            readChunk             = NULL;
    PFILE_CHUNK            writeChunk            = NULL;
    BOOLEAN                eof                   = FALSE;
    BOOLEAN                waitingForRead        = FALSE;
    KEVENT                 writeEvent            = { 0 };

    WRITE_CALLBACK_CONTEXT writeCallbackContext  = { 0 };

    LARGE_INTEGER          waitTimeout           = { 0 };
    LARGE_INTEGER          zeroTimeout           = { 0 };

    IO_STATUS_BLOCK        statusBlock           = { 0 };

    LARGE_INTEGER          remainingBytes        = { 0 };
    LARGE_INTEGER          totalBytesRead        = { 0 };
    LARGE_INTEGER          totalBytesWritten     = { 0 };
    LARGE_INTEGER          sourceFileOffset      = { 0 };
    LARGE_INTEGER          destinationFileOffset = { 0 };

    PAGED_CODE();

    FLT_ASSERT(FltObjects          != NULL);
    FLT_ASSERT(SourceFileHandle    != NULL);
    FLT_ASSERT(SourceFileSize      != NULL);
    FLT_ASSERT(SourceFileSize->QuadPart > 0);
    FLT_ASSERT(BytesCopied         != NULL);
    FLT_ASSERT(KeGetCurrentIrql()  == PASSIVE_LEVEL);

    *BytesCopied = RtlConvertLongToLargeInteger(0);

    __try
    {
        // Set the relative timeout (1 stands for 100 nanoseconds).
        waitTimeout           = RtlConvertLongToLargeInteger(-10000);
        waitTimeout.QuadPart *= TimeoutMilliseconds;

        KeInitializeEvent(&writeEvent, NotificationEvent, TRUE);
        writeCallbackContext.Event = &writeEvent;

        remainingBytes.QuadPart = SourceFileSize->QuadPart;

        NT_IF_FAIL_LEAVE(LcInitializeChunksList(FltObjects->Instance, &chunksListHead, remainingBytes, &chunkListLength));

        for (;;)
        {
            if (waitingForRead)
            {
                // Wait for the read operation to finish.
                NT_IF_FAIL_LEAVE(ZwWaitForSingleObject(SourceFileHandle, FALSE, &waitTimeout));
                readComplete = TRUE;
            }
            else
            {
                readComplete = ZwWaitForSingleObject(SourceFileHandle, FALSE, &zeroTimeout) == STATUS_SUCCESS;
            }

            writeComplete = KeReadStateEvent(&writeEvent) != 0;

            if (!eof && readComplete)
            {
                // If it's not the first read, update status of the current chunk.
                if (readChunk != NULL)
                {
                    status = statusBlock.Status;

                    if (NT_SUCCESS(status) || status == STATUS_END_OF_FILE)
                    {
                        ULONG bytesRead = (ULONG)statusBlock.Information;

                        readChunk->BytesInBuffer   = bytesRead;

                        remainingBytes.QuadPart   -= bytesRead;
                        totalBytesRead.QuadPart   += bytesRead;
                        sourceFileOffset.QuadPart += bytesRead;

                        if (status == STATUS_END_OF_FILE || bytesRead < readChunk->BufferSize)
                        {
                            eof    = TRUE;
                            status = STATUS_SUCCESS;

                            // Will not be used later in this case, only to have the proper data here.
                            remainingBytes.QuadPart = 0;
                        }
                    }

                    NT_IF_FAIL_LEAVE(status);
                }

                // Move to the next available chunk and schedule read.
                if (!eof)
                {
                    // If the remote file system returned an invalid file size, when we started reading it,
                    // this value might be negative. Set it to the default, so the newly allocated chunk
                    // will have the maximum allowed size.
                    if (remainingBytes.QuadPart <= 0)
                    {
                        remainingBytes.QuadPart = ChunkSize;
                    }

                    NT_IF_FAIL_LEAVE(LcGetNextAvailableChunk(
                        FltObjects->Instance,
                        &chunksListHead,
                        &readChunk,
                        &chunkListLength,
                        TRUE,              // Read operation.
                        &remainingBytes,
                        &writeEvent,
                        &waitTimeout));

                    // Schedule read operation for the current chunk.
                    status = ZwReadFile(
                        SourceFileHandle,
                        NULL,
                        NULL,
                        NULL,
                        &statusBlock,
                        readChunk->Buffer,
                        readChunk->BufferSize,
                        &sourceFileOffset,
                        NULL);

                    NT_IF_FALSE_LEAVE(status == STATUS_PENDING || status == STATUS_SUCCESS, status);
                }
            }

            if (writeComplete)
            {
                if (!waitingForRead)
                {
                    // If it's not the first write, update status of the current chunk.
                    if (writeChunk != NULL)
                    {
                        NT_IF_FAIL_LEAVE(writeCallbackContext.Status);

                        writeChunk->BytesInBuffer       = 0;
                        totalBytesWritten.QuadPart     += writeCallbackContext.BytesWritten;
                        destinationFileOffset.QuadPart += writeCallbackContext.BytesWritten;
                    }

                    NT_IF_FAIL_LEAVE(LcGetNextAvailableChunk(
                        FltObjects->Instance,
                        &chunksListHead,
                        &writeChunk,
                        &chunkListLength,
                        FALSE,             // Write operation.
                        NULL,
                        NULL,
                        NULL));
                }

                waitingForRead = FALSE;

                // If we don't have any data in the current chunk, restart from the beginning of the loop.
                if (writeChunk->BytesInBuffer == 0)
                {
                    if (eof)
                    {
                        // We're done!
                        break;
                    }
                    else
                    {
                        // Since we're waiting for the read to complete for the current chunk,
                        // don't change the chunk position on next iteration.
                        waitingForRead = TRUE;

                        continue;
                    }
                }

                KeClearEvent(&writeEvent);

                NT_IF_FAIL_LEAVE(FltWriteFile(
                    FltObjects->Instance,
                    FltObjects->FileObject,
                    &destinationFileOffset,
                    writeChunk->BytesInBuffer,
                    writeChunk->Buffer,
                    FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
                    NULL,
                    (PFLT_COMPLETED_ASYNC_IO_CALLBACK)&LcWriteCallback,
                    &writeCallbackContext));
            }
        }

        *BytesCopied = totalBytesWritten;
    }
    __finally
    {
        LcClearChunksList(FltObjects->Instance, &chunksListHead);
    }

    return status;
}
示例#24
0
USHORT
SpyAddRecordName(
	_Inout_ PLOG_RECORD LogRecord,
	_In_ PUNICODE_STRING Name,
	_In_ USHORT ByteOffset
)
/*++

Routine Description:

Sets the given file name in the LogRecord.

NOTE:  This code must be NON-PAGED because it can be called on the
paging path.

Arguments:

LogRecord - The record in which to set the name.

Name - The name to insert

Return Value:

None.

--*/
{

	PWCHAR printPointer = (PWCHAR)LogRecord->Names;
	SHORT charsToSkip = ByteOffset / sizeof(WCHAR);
	SHORT wcharsCopied;
	USHORT stringLength;

	if (Name == NULL || charsToSkip >= MAX_NAME_WCHARS_LESS_NULL)
	{
		return 0;
	}

#pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
	wcharsCopied = (SHORT)_snwprintf(printPointer + charsToSkip,
		MAX_NAME_WCHARS_LESS_NULL - charsToSkip,
		L"%wZ",
		Name);

	if (wcharsCopied >= 0)
	{
		stringLength = ByteOffset + (wcharsCopied * sizeof(WCHAR));
	}
	else 
	{

		//
		//  There wasn't enough buffer space, so manually truncate in a NULL
		//  because we can't trust _snwprintf to do so in that case.
		//

		stringLength = MAX_NAME_SPACE_LESS_NULL;
		printPointer[MAX_NAME_WCHARS_LESS_NULL] = UNICODE_NULL;
	}

	//
	//  We will always round up log-record length to sizeof(PVOID) so that
	//  the next log record starts on the right PVOID boundary to prevent
	//  IA64 alignment faults.  The length of the record of course
	//  includes the additional NULL at the end.
	//

	LogRecord->Length = ROUND_TO_SIZE((sizeof(LOG_RECORD) +
		stringLength +
		sizeof(UNICODE_NULL)),
		sizeof(PVOID));

	FLT_ASSERT(LogRecord->Length <= MAX_LOG_RECORD_LENGTH);

	return stringLength + sizeof(UNICODE_NULL);
}
示例#25
0
文件: Fetch.c 项目: aleksk/LazyCopy
NTSTATUS
LcFetchRemoteFile (
    _In_  PCFLT_RELATED_OBJECTS FltObjects,
    _In_  PUNICODE_STRING       SourceFile,
    _In_  PUNICODE_STRING       TargetFile,
    _In_  BOOLEAN               UseCustomHandler,
    _Out_ PLARGE_INTEGER        BytesCopied
    )
/*++

Summary:

    This function copies the remote file content to the current file object.

    In order for the remote file to be fetched, make sure that the network redirector
    device is used, i.e. the 'SourceFile' root points to the '\Device\Mup\<path>'.

Arguments:

    FltObjects       - Pointer to the 'FLT_RELATED_OBJECTS' data structure containing
                       opaque handles to this filter, instance, its associated volume and
                       file object.

    SourceFile       - Path to the file to fetch content from.

    TargetFile       - Path to the file to store content to.

    UseCustomHandler - Whether the file should be fetched by the user-mode client.

    BytesCopied      - The amount of bytes copied.

Return Value:

    The return value is the status of the operation.

--*/
{
    NTSTATUS                     status           = STATUS_SUCCESS;
    HANDLE                       sourceFileHandle = NULL;
    IO_STATUS_BLOCK              statusBlock      = { 0 };
    FILE_STANDARD_INFORMATION    standardInfo     = { 0 };
    FILE_END_OF_FILE_INFORMATION eofInfo          = { 0 };

    PAGED_CODE();

    IF_FALSE_RETURN_RESULT(FltObjects  != NULL, STATUS_INVALID_PARAMETER_1);
    IF_FALSE_RETURN_RESULT(SourceFile  != NULL, STATUS_INVALID_PARAMETER_2);
    IF_FALSE_RETURN_RESULT(TargetFile  != NULL, STATUS_INVALID_PARAMETER_3);
    IF_FALSE_RETURN_RESULT(BytesCopied != NULL, STATUS_INVALID_PARAMETER_5);

    FLT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    *BytesCopied = RtlConvertLongToLargeInteger(0);

    __try
    {
        LOG((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "[LazyCopy] Fetching content from: '%wZ' -> '%wZ'\n", SourceFile, TargetFile));

        if (UseCustomHandler)
        {
            NT_IF_FAIL_LEAVE(LcFetchFileInUserMode(SourceFile, TargetFile, BytesCopied));
        }
        else
        {
            //
            // Open the source file and make sure it's not empty.
            //

            NT_IF_FAIL_LEAVE(LcOpenFile(SourceFile, TargetFile, &sourceFileHandle));

            NT_IF_FAIL_LEAVE(ZwQueryInformationFile(sourceFileHandle, &statusBlock, &standardInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation));
            if (standardInfo.EndOfFile.QuadPart == 0)
            {
                // No need to copy an empty file.
                __leave;
            }

            // Extend the target file, so all readers that wait for the content to be copied will get the actual file size information.
            // Remote file system may return incorrect information, but we are doing it only for the cases, when multiple threads
            // try to access the same file, while we are fetching it.
            eofInfo.EndOfFile.QuadPart = standardInfo.EndOfFile.QuadPart;
            NT_IF_FAIL_LEAVE(FltSetInformationFile(FltObjects->Instance, FltObjects->FileObject, &eofInfo, sizeof(eofInfo), FileEndOfFileInformation));

            //
            // Copy source file contents into the local (target) file.
            //

            NT_IF_FAIL_LEAVE(LcFetchFileByChunks(
                FltObjects,
                sourceFileHandle,
                &standardInfo.EndOfFile,
                BytesCopied));
        }
    }
    __finally
    {
        if (sourceFileHandle != NULL)
        {
            ZwClose(sourceFileHandle);
        }
    }

    return status;
}
示例#26
0
文件: Fetch.c 项目: aleksk/LazyCopy
static
_Check_return_
NTSTATUS
LcOpenFile (
    _In_  PUNICODE_STRING SourceFile,
    _In_  PUNICODE_STRING TargetFile,
    _Out_ PHANDLE         Handle
    )
/*++

Summary:

    This function tries to open the 'FilePath' given.

    If open operation fails in the current context, it asks for the user-mode service
    to open that file.

Arguments:

    SourceFile - Path to the file to open.

    TargetFile - Path to the file the content should be stored to.

    Handle     - Receives handle to the opened file.

Return Value:

    The return value is the status of the operation.

--*/
{
    NTSTATUS          status           = STATUS_SUCCESS;
    IO_STATUS_BLOCK   statusBlock      = { 0 };
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    HANDLE            fileHandle       = NULL;

    PAGED_CODE();

    FLT_ASSERT(SourceFile != NULL);
    FLT_ASSERT(TargetFile != NULL);
    FLT_ASSERT(Handle     != NULL);

    EventWriteFile_Open_Start(NULL, SourceFile->Buffer);

    __try
    {
        // The current minifilter instance may not be attached to the target volume,
        // so the ZwOpenFile/ZwReadFile functions should be used here instead of the FltCreateFile/FltReadFile.
        InitializeObjectAttributes(&objectAttributes, SourceFile, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

        // Open file for asynchronous reads.
        status = ZwOpenFile(
            &fileHandle,
            GENERIC_READ,
            &objectAttributes,
            &statusBlock,
            FILE_SHARE_READ,
            FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY);

        // Open operation may fail, if a remote file is opened by a system, which does not have access to the remote share.
        // If this happens, we want the user-mode client to open it for us.
        if (!NT_SUCCESS(status) && status == STATUS_ACCESS_DENIED)
        {
            NTSTATUS notificationStatus = STATUS_SUCCESS;

            LOG((DPFLTR_IHVDRIVER_ID, DPFLTR_WARNING_LEVEL, "[LazyCopy] '%wZ' cannot be accessed by the system, trying to use user-mode service instead.\n", FilePath));

            notificationStatus = LcOpenFileInUserMode(SourceFile, TargetFile, &fileHandle);

            // Return original status, if error occurred while sending notification to the user-mode client.
            status = notificationStatus == STATUS_PORT_DISCONNECTED || notificationStatus == STATUS_TIMEOUT
                     ? status
                     : notificationStatus;
        }
    }
    __finally
    {
        if (NT_SUCCESS(status))
        {
            *Handle = fileHandle;

            // Make sure it's not closed by the code below.
            fileHandle = NULL;
        }

        if (fileHandle != NULL)
        {
            ZwClose(fileHandle);
        }
    }

    EventWriteFile_Open_Stop(NULL);

    return status;
}
示例#27
0
FLT_PREOP_CALLBACK_STATUS
NcEnumerateDirectory (
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
    )
/*++

Routine Description:

    Routine is invoked when a directory enumeration is issued by the
    user.

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 context for the completion routine for this
        operation.

Return Value:

    The return value is the Status of the operation.

--*/
{
    //TODO WE SHOULD CONSIDER MOVING THIS TO POST BECAUSE NTFS WILL TAKE CARE
    //     OF SYNC.
    FLT_PREOP_CALLBACK_STATUS ReturnValue;
    NTSTATUS Status;

    PNC_INSTANCE_CONTEXT InstanceContext = NULL;
    PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL;
    PNC_DIR_QRY_CONTEXT DirCtx = NULL;

    PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL;

    NC_PATH_OVERLAP RealOverlap;
    NC_PATH_OVERLAP UserOverlap;

    BOOLEAN Reset = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN );
    BOOLEAN FirstQuery;
    BOOLEAN Single = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RETURN_SINGLE_ENTRY );
    BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags,
                                         FO_OPENED_CASE_SENSITIVE );
    
    FILE_INFORMATION_CLASS InformationClass = 
        Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass;

    PVOID UserBuffer;
    ULONG BufferSize; //size for user and system buffers.

    BOOLEAN Unlock = FALSE;

    //Vars for moving data into user buffer.
    ULONG NumEntriesCopied;
    ULONG UserBufferOffset;
    ULONG LastEntryStart;
    BOOLEAN MoreRoom;
    PNC_CACHE_ENTRY NextEntry;

    DIRECTORY_CONTROL_OFFSETS Offsets;

    BOOLEAN FoundStructureOffsets;

    UNREFERENCED_PARAMETER( CompletionContext );

    PAGED_CODE();

    FLT_ASSERT( IoGetTopLevelIrp() == NULL );

    FoundStructureOffsets = NcDetermineStructureOffsets( &Offsets,
                                                         InformationClass );

    if (!FoundStructureOffsets) {

        Status = STATUS_INVALID_PARAMETER;
        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  Get our instance context.
    //

    Status = FltGetInstanceContext( FltObjects->Instance,
                                    &InstanceContext );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  Get the directory's name.
    //

    Status = NcGetFileNameInformation( Data,
                                       NULL,
                                       NULL,
                                       FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT,
                                       &FileNameInformation ); 

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    Status = FltParseFileNameInformation( FileNameInformation );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  See if the directory is parent of either mapping.
    //

    NcComparePath( &FileNameInformation->Name,
                   &InstanceContext->Mapping.UserMapping,
                   NULL,
                   IgnoreCase,
                   TRUE,
                   &UserOverlap );

    NcComparePath( &FileNameInformation->Name,
                   &InstanceContext->Mapping.RealMapping,
                   NULL,
                   IgnoreCase,
                   TRUE,
                   &RealOverlap );

    if (!(UserOverlap.Parent || RealOverlap.Parent )) {

        //
        //  We are not interested in this directory
        //  because it is not the parent of either
        //  mapping. This means we can just passthrough.
        //

        Status = STATUS_SUCCESS;
        ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
        goto NcEnumerateDirectoryCleanup;
    }

    Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter,
                                                  FltObjects->Instance,
                                                  FltObjects->FileObject,
                                                  &HandleContext );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    FLT_ASSERT( HandleContext != NULL );

    DirCtx = &HandleContext->DirectoryQueryContext;
    _Analysis_assume_( DirCtx != NULL );

    //
    //  Before looking at the context, we have to acquire the lock.
    //
    
    NcLockStreamHandleContext( HandleContext );
    Unlock = TRUE;

    //
    //  We don't allow multiple outstanding enumeration requests on
    //  a single handle.
    //
    //  TODO: This needs to change.
    //

    if (DirCtx->EnumerationOutstanding) {

        Status = STATUS_UNSUCCESSFUL;
        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;

    }

    DirCtx->EnumerationOutstanding = TRUE;

    //
    //  Now drop the lock.  We're protected by the EnumerationOutstanding
    //  flag; nobody else can muck with the enumeration context structure.
    //

    NcUnlockStreamHandleContext( HandleContext );
    Unlock = FALSE;

    //
    //  Now we need to initialize or clear the cache and query options.
    //
    
    Status = NcStreamHandleContextEnumSetup( DirCtx,
                                             InstanceContext,
                                             &Offsets,
                                             Data,
                                             FltObjects,
                                             UserOverlap,
                                             &FirstQuery );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  Prepare to populate the user buffer.
    //

    UserBuffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;

    BufferSize = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length;

    //
    //  Lets copy data into the user buffer.
    //

    NumEntriesCopied = 0;
    UserBufferOffset = 0;

    do {

        //
        //  If there is no cache entry, populate it.
        //

        if (DirCtx->Cache.Buffer == NULL) {

            Status = NcPopulateCacheEntry( FltObjects->Instance,
                                           FltObjects->FileObject,
                                           Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length,
                                           Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass,
                                           Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName,
                                           Reset,
                                           &DirCtx->Cache);

            //
            //  We only want to reset the cache once.
            //

            Reset = FALSE;

            //
            //  There was a problem populating cache, pass up to user.
            //

            if (!NT_SUCCESS( Status )) {

                ReturnValue = FLT_PREOP_COMPLETE;
                goto NcEnumerateDirectoryCleanup;
            }

        }

        NextEntry = NcDirEnumSelectNextEntry( DirCtx, &Offsets, IgnoreCase );

        if (NextEntry == NULL) {

            //
            //  There are no more entries.
            //

            break;
        }

        if (NcSkipName( &Offsets, 
                        DirCtx, 
                        RealOverlap, 
                        &InstanceContext->Mapping,
                        IgnoreCase )) {

            //
            //  This entry is the real mapping path. That means we have to mask it...
            //  We will say there is more room and continue.
            //

            MoreRoom = TRUE;

        } else {

            //
            //  We are keeping this entry!
            //

            try {

                LastEntryStart = UserBufferOffset;
                UserBufferOffset = NcCopyDirEnumEntry( UserBuffer,
                                                       UserBufferOffset,
                                                       BufferSize,
                                                       NextEntry,
                                                       &Offsets,
                                                       &MoreRoom );

            } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) {

                Status = STATUS_INVALID_USER_BUFFER;
                ReturnValue = FLT_PREOP_COMPLETE;
                goto NcEnumerateDirectoryCleanup;
            }

            if (MoreRoom) {

                NumEntriesCopied++;
            }

        }// end of "we are copying entry"

    } while (MoreRoom && 
             (Single ? (NumEntriesCopied < 1) : TRUE));

    if (NumEntriesCopied > 0) {

        //
        //  Now we know what the last entry in the user buffer is going to be.
        //  Set its NextEntryOffset to 0, so that the user knows its the last element.
        //

        try {

            NcSetNextEntryOffset( Add2Ptr(UserBuffer, LastEntryStart),
                                  &Offsets, 
                                  TRUE );

        } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) {

            Status = STATUS_INVALID_USER_BUFFER;
            ReturnValue = FLT_PREOP_COMPLETE;
            goto NcEnumerateDirectoryCleanup;
        }
    }

    //
    //  We finished copying data.
    //

    ReturnValue = FLT_PREOP_COMPLETE;

    if (NumEntriesCopied == 0) {

        if (FirstQuery) {

            Status = STATUS_NO_SUCH_FILE;

        } else {

            Status = STATUS_NO_MORE_FILES;
        }

    } else {

        Status = STATUS_SUCCESS;
    }

    ReturnValue = FLT_PREOP_COMPLETE;
    goto NcEnumerateDirectoryCleanup;

NcEnumerateDirectoryCleanup:

    if (ReturnValue == FLT_PREOP_COMPLETE) {
 
        //
        //  We need to write back results of query.
        //
 
        Data->IoStatus.Status = Status;
 
        if (NT_SUCCESS( Status )) {
 
            //success
            Data->IoStatus.Information = UserBufferOffset;

        } else {
 
            //failure
            Data->IoStatus.Information = 0;
        }
    }
 
    if (InstanceContext != NULL) {

        FltReleaseContext( InstanceContext );
    }
 
    if (DirCtx != NULL) {
        
        if (!Unlock) {
            NcLockStreamHandleContext( HandleContext );
            Unlock = TRUE;
        }

        FLT_ASSERT( DirCtx->EnumerationOutstanding );
        DirCtx->EnumerationOutstanding = FALSE;

        NcUnlockStreamHandleContext( HandleContext );
        Unlock = FALSE;

        FltReleaseContext( HandleContext );
    }

    FLT_ASSERT( !Unlock );
 
    if (FileNameInformation != NULL) {

        FltReleaseFileNameInformation( FileNameInformation );
    }
 
    return ReturnValue;
}
示例#28
0
	bool AnimationTrack::loadFromXML(TiXmlElement *xmlNodeTrack)
	{
		xmlNodeTrack->QueryStringAttribute("name",&m_name);			
		stringc dataType;
		xmlNodeTrack->QueryStringAttribute("dataType",&dataType);
		m_dataType = stringToDataType(dataType);
		
		TiXmlHandle hXmlNode(xmlNodeTrack);

		//load keyframes data
		TiXmlElement* xmlNodeTimes = hXmlNode.FirstChild( "times" ).Element();
		if(xmlNodeTimes!=0)
		{
			int kfNum = 0;

			//times
			const char* timesStr = xmlNodeTimes->GetText();
			if(timesStr!=0)
			{
				float *times=0;
				kfNum = StringUtil::splitOutFloats(times, timesStr);

				for(int i=0; i<kfNum; ++i)
				{
					KeyFrame* kf = createKeyFrame();
					if(kf!=0)
					{
						kf->setTime(times[i]);
						m_keyFrames.push_back(kf);
					}
				}

				delete times;
			}

			//at least has 1 kf
			if(kfNum>0)
			{
				//KF datas
				float *kfDatas=0;
				TiXmlElement* xmlNodeKFs = hXmlNode.FirstChild( "keyframes" ).Element();
				if(xmlNodeKFs!=0)
				{
					int valueNum = StringUtil::splitOutFloats(kfDatas, xmlNodeKFs->GetText());
					u32 dataElemNum = m_keyFrames[0]->getDataElementNum();
					FLT_ASSERT(dataElemNum>0 && valueNum/dataElemNum==kfNum);					
					
					for(int i=0; i<kfNum; ++i)
					{
						m_keyFrames[i]->loadValue(kfDatas, i);						
					}

					delete kfDatas;
				}

				//interp datas
				TiXmlElement* xmlNodeInterps = hXmlNode.FirstChild( "interps" ).Element();
				if(xmlNodeInterps!=0)
				{
					array_t<stringc> strs;
					strs = StringUtil::split(xmlNodeInterps->GetText(), ",", kfNum);
										
					FLT_ASSERT(strs.size()==kfNum);					

					for(int i=0; i<kfNum; ++i)
					{
						m_keyFrames[i]->setInterpTypeByString(strs[i]);						
					}					
				}
			}

			//create a computed frame, for interpolation
			m_computedFrame = createKeyFrame();
		}

		return true;
	}
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;
}