RBOOL
    collector_1_deinitialize
    (

    )
{
    RBOOL isSuccess = FALSE;
    RU32 status = 0;

    status = PsSetCreateProcessNotifyRoutineEx( CreateProcessNotifyEx, TRUE );

    if( NT_SUCCESS( status ) )
    {
        isSuccess = TRUE;
    }
    else
    {
        rpal_debug_kernel( "Failed to deinitialize: 0x%08X", status );
    }

    return isSuccess;
}
static
FLT_POSTOP_CALLBACK_STATUS
    FileSetInfoFilterPostCallback
    (
        PFLT_CALLBACK_DATA Data,
        PCFLT_RELATED_OBJECTS FltObjects,
        PVOID CompletionContext,
        FLT_POST_OPERATION_FLAGS Flags
    )
{
    FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING;
    KLOCK_QUEUE_HANDLE hMutex = { 0 };
    PFLT_FILE_NAME_INFORMATION fileInfoSrc = NULL;
    PFLT_FILE_NAME_INFORMATION fileInfoDst = NULL;
    RU32 pid = 0;
    RU64 ts = 0;
    RU32 createOptions = 0;
    RU32 createDispositions = 0;
    PFILE_RENAME_INFORMATION renameInfo = NULL;
    _fileContext* context = NULL;

    UNREFERENCED_PARAMETER( FltObjects );
    UNREFERENCED_PARAMETER( CompletionContext );
    UNREFERENCED_PARAMETER( Flags );

    // We only care about user mode for now.
    if( UserMode != Data->RequestorMode ||
        STATUS_SUCCESS != Data->IoStatus.Status )
    {
        return status;
    }

    if( FileRenameInformation == Data->Iopb->Parameters.SetFileInformation.FileInformationClass )
    {
        if( NULL != ( fileInfoSrc = (PFLT_FILE_NAME_INFORMATION)CompletionContext ) )
        {
            //rpal_debug_kernel( "MOVE OLD: %wZ", fileInfoSrc->Name );
        }
        else
        {
            rpal_debug_kernel( "Failed to get src file name info" );
        }

        renameInfo = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;

        if( !NT_SUCCESS( FltGetDestinationFileNameInformation( FltObjects->Instance,
                                                               FltObjects->FileObject,
                                                               renameInfo->RootDirectory,
                                                               renameInfo->FileName,
                                                               renameInfo->FileNameLength,
                                                               FLT_FILE_NAME_NORMALIZED |
                                                               FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP,
                                                               &fileInfoDst ) ) )
        {
            rpal_debug_kernel( "Failed to get dst file name info" );
        }
        else
        {
            //rpal_debug_kernel( "MOVE TO: %wZ", fileInfoDst->Name );
        }

        pid = (RU32)FltGetRequestorProcessId( Data );
        ts = rpal_time_getLocal();

        createOptions = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF;
        createDispositions = ( Data->Iopb->Parameters.Create.Options & 0xFF000000 ) >> 24;

        KeAcquireInStackQueuedSpinLock( &g_collector_2_mutex, &hMutex );

        g_files[ g_nextFile ].pid = pid;
        g_files[ g_nextFile ].ts = ts;
        g_files[ g_nextFile ].uid = KERNEL_ACQ_NO_USER_ID;

        // For compability with the user mode API we report file moves
        // as two different operations.

        // First we report the old file name.
        g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_RENAME_OLD;

        if( NULL != fileInfoSrc )
        {
            copyUnicodeStringToBuffer( &fileInfoSrc->Name,
                                       g_files[ g_nextFile ].path );

            FltReleaseFileNameInformation( fileInfoSrc );
        }

        g_nextFile++;
        if( g_nextFile == _NUM_BUFFERED_FILES )
        {
            g_nextFile = 0;
        }

        // Now report the new file name.
        g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_RENAME_NEW;

        if( NULL != fileInfoDst )
        {
            copyUnicodeStringToBuffer( &fileInfoDst->Name,
                                       g_files[ g_nextFile ].path );

            FltReleaseFileNameInformation( fileInfoDst );
        }

        g_nextFile++;
        if( g_nextFile == _NUM_BUFFERED_FILES )
        {
            g_nextFile = 0;
        }

        KeReleaseInStackQueuedSpinLock( &hMutex );
    }
    else if( FileDispositionInformationEx == Data->Iopb->Parameters.SetFileInformation.FileInformationClass ||
static
FLT_POSTOP_CALLBACK_STATUS
    FileCreateFilterPostCallback
    (
        PFLT_CALLBACK_DATA Data,
        PCFLT_RELATED_OBJECTS FltObjects,
        PVOID CompletionContext,
        FLT_POST_OPERATION_FLAGS Flags
    )
{
    FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING;
    KLOCK_QUEUE_HANDLE hMutex = { 0 };
    PFLT_FILE_NAME_INFORMATION fileInfo = NULL;
    RU32 pid = 0;
    RU64 ts = 0;
    RU32 createOptions = 0;
    RU32 createDispositions = 0;
    _fileContext* context = NULL;
    
    UNREFERENCED_PARAMETER( FltObjects );
    UNREFERENCED_PARAMETER( CompletionContext );
    UNREFERENCED_PARAMETER( Flags );

    // We only care about user mode for now.
    if( UserMode != Data->RequestorMode ||
        STATUS_SUCCESS != Data->IoStatus.Status )
    {
        return status;
    }

    if( FILE_CREATED == Data->IoStatus.Information )
    {
        pid = (RU32)FltGetRequestorProcessId( Data );
        ts = rpal_time_getLocal();
        
        if( !NT_SUCCESS( FltGetFileNameInformation( Data,
                                                    FLT_FILE_NAME_NORMALIZED |
                                                    FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP,
                                                    &fileInfo ) ) )
        {
            rpal_debug_kernel( "Failed to get file name info" );
            fileInfo = NULL;
        }
        else
        {
            //rpal_debug_kernel( "NEW: %wZ", fileInfo->Name );
        }

        if( NULL != ( context = _getOrSetContext( Data ) ) )
        {
            context->isNew = TRUE;
            FltReleaseContext( (PFLT_CONTEXT)context );
        }

        KeAcquireInStackQueuedSpinLock( &g_collector_2_mutex, &hMutex );

        g_files[ g_nextFile ].pid = pid;
        g_files[ g_nextFile ].ts = ts;
        g_files[ g_nextFile ].uid = KERNEL_ACQ_NO_USER_ID;
        g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_ADDED;

        if( NULL != fileInfo )
        {
            copyUnicodeStringToBuffer( &fileInfo->Name,
                                       g_files[ g_nextFile ].path );

            FltReleaseFileNameInformation( fileInfo );
        }

        g_nextFile++;
        if( g_nextFile == _NUM_BUFFERED_FILES )
        {
            g_nextFile = 0;
        }

        KeReleaseInStackQueuedSpinLock( &hMutex );
    }

    createOptions = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF;
    createDispositions = ( Data->Iopb->Parameters.Create.Options & 0xFF000000 ) >> 24;

    if( IS_FLAG_ENABLED( createOptions, FILE_DELETE_ON_CLOSE ) )
    {
        if( NULL != ( context = _getOrSetContext( Data ) ) )
        {
            context->isDelete = TRUE;
            FltReleaseContext( (PFLT_CONTEXT)context );
        }
    }

    return status;
}