Compartilhar via


Função CfGetPlaceholderRangeInfoForHydration (cfapi.h)

Obtém informações de intervalo sobre um arquivo ou pasta de espaço reservado. Essas informações de intervalo são idênticas ao que CfGetPlaceholderRangeInfo retorna. No entanto, não é necessário um fileHandle como um parâmetro. Em vez disso, ele usa ConnectionKey, TransferKey e FileId para identificar o arquivo e o fluxo para quais informações de intervalo estão sendo solicitadas.

A plataforma fornece ConnectionKey, TransferKey e FileId para todas as funções de retorno de chamada registradas por meio do CfConnectSyncRoot e o provedor pode usar esses parâmetros para obter informações de intervalo sobre um espaço reservado do CF_CALLBACK_TYPE_FETCH_DATA retorno de chamada sem exigir que ele abra um identificador para o arquivo.

Se o arquivo não for um espaço reservado para arquivos de nuvem, a API falhará. Em caso de êxito, as informações de intervalo são retornadas de acordo com o InfoClass específico solicitado.

Observação

Essa API só estará disponível se a PlatformVersion.IntegrationNumber obtida de CfGetPlatformInfo for 0x600 ou superior.

Sintaxe

HRESULT CfGetPlaceholderRangeInfoForHydration(
  [in]            CF_CONNECTION_KEY               ConnectionKey,
  [in]            CF_TRANSFER_KEY                 TransferKey,
  [in]            LARGE_INTEGER                   FileId,
  [in]            CF_PLACEHOLDER_RANGE_INFO_CLASS InfoClass,
  [in]            LARGE_INTEGER                   StartingOffset,
  [in]            LARGE_INTEGER                   RangeLength,
  [out]           PVOID                           InfoBuffer,
  [in]            DWORD                           InfoBufferSize,
  [out, optional] PDWORD                          InfoBufferWritten
);

Parâmetros

[in] ConnectionKey

Um identificador opaco criado por CfConnectSyncRoot para uma raiz de sincronização gerenciada pelo provedor de sincronização. Ele é retornado também em CF_CALLBACK_INFO no retorno de chamada CF_CALLBACK_TYPE_FETCH_DATA e outros retornos de chamada.

[in] TransferKey

O identificador opaco para o arquivo de espaço reservado para o qual CF_CALLBACK_TYPE_FETCH_DATA retorno de chamada foi invocado. Ele também é retornado em CF_CALLBACK_INFO no retorno de chamada CF_CALLBACK_TYPE_FETCH_DATA . Como alternativa, isso poderá ser obtido por CfGetTransferKey se a API não estiver sendo invocada de CF_CALLBACK_TYPE_FETCH_DATA Retorno de Chamada.

[in] FileId

Uma ID exclusiva de todo o volume mantida pelo sistema de arquivos de 64bits do arquivo/diretório do espaço reservado a ser atendido. Assim como TransferKey, isso é retornado em CF_CALLBACK_INFO no CF_CALLBACK_TYPE_FETCH_DATA e outros retornos de chamada para que o provedor não precise recuperá-lo novamente.

[in] InfoClass

Tipos do intervalo de dados de espaço reservado. O valor pode ser um dos seguintes:

Value Description
CF_PLACEHOLDER_RANGE_INFO_ONDISK Dados em disco são dados que são físicos presentes no arquivo. Esse é um super conjunto de outros tipos de intervalos.
CF_PLACEHOLDER_RANGE_INFO_VALIDATED Os dados validados são um subconjunto dos dados em disco que estão atualmente em sincronia com a nuvem.
CF_PLACEHOLDER_RANGEINFO_MODIFIED Os dados modificados são um subconjunto dos dados em disco que atualmente não estão em sincronia com a nuvem (ou seja, modificados ou acrescentados).)

[in] StartingOffset

Deslocamento do ponto inicial do intervalo de dados. StartingOffset e RangeLength especificam um intervalo no arquivo de espaço reservado cujas informações conforme descrito pelo parâmetro InfoClass são solicitadas

[in] RangeLength

Comprimento do intervalo de dados. Um provedor pode especificar CF_EOF para RangeLength indicar que o intervalo para o qual as informações são solicitadas é de StartingOffset até o final do arquivo.

[out] InfoBuffer

Ponteiro para um buffer que receberá os dados. O buffer é uma matriz de estruturas de CF_FILE_RANGE , que são pares de deslocamento/comprimento, descrevendo os intervalos solicitados.

[in] InfoBufferSize

O comprimento do InfoBuffer em bytes.

[out, optional] InfoBufferWritten

Recebe o número de bytes retornados no InfoBuffer.

Valor de retorno

Se essa função for bem-sucedida, ela retornará S_OK. Caso contrário, ele retornará um código de erro HRESULT . Alguns códigos de erro comuns são listados na tabela a seguir:

Código do erro Meaning
HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) Isso significa que StartingOffset>= a posição do final do arquivo.
HRESULT_FROM_WIN32( ERROR_MORE_DATA ) Isso implica que a próxima entrada de CF_FILE_RANGE não se encaixa no buffer fornecido. O chamador deve verificar se alguma entrada é recebida ou não usando o valor InfoBufferWritten retornado.

Observações

Embora já exista uma API para consultar intervalos de arquivos hidratados de um espaço reservado, uma nova API era necessária para melhorar a confiabilidade da plataforma.

A API existente, CfGetPlaceholderRangeInfo, requer um identificador aberto para um arquivo e dispara um FSCTL_HSM_CONTROL usando esse identificador. Provedores/Mecanismos de Sincronização normalmente usam essa API para avaliar quais partes do arquivo não são hidratadas do contexto de um retorno de chamada CF_CALLBACK_TYPE_FETCH_DATA invocado pelo filtro para hidratar o arquivo para satisfazer uma E/S.

Um mini filtro na pilha de E/S pode emitir uma verificação de dados no arquivo quando o mecanismo de provedor/sincronização tenta abrir um identificador para o arquivo a ser passado como um parâmetro para CfGetPlaceholderRangeInfo. Como alternativa, um minifiltro pode bloquear o FSCTL_HSM_CONTROL que o CfGetPlaceholderRangeInfo dispara internamente.

O filtro cldflt foi projetado para invocar apenas um CF_CALLBACK_TYPE_FETCH_DATA retorno de chamada por intervalo de arquivos necessário para hidratar o arquivo. Como resultado de qualquer um dos casos acima, a verificação de dados está presa atrás do CF_CALLBACK_TYPE_FETCH_DATA original ou o CF_CALLBACK_TYPE_FETCH_DATA está preso atrás do FSCTL bloqueado. Isso causa um deadlock no caminho da hidratação.

Portanto, essa API é necessária. Ele executa a mesma funcionalidade que CfGetPlaceholderRangeInfo, mas se comunica com o filtro diretamente usando portas de mensagem de filtro ignorando a pilha de E/S intermediária. Portanto, nenhum minifiltro intermediário pode obstruir o CreateFile ou o FSCTL_HSM_CONTROL.

Observe que o chamador sempre tem a ConnectionKey obtida por meio de CfConnectSyncRoot. Ele pode obter TransferKey via CfGetTransferKey e obter FileId usando GetFileInformationByHandle. Mas essa abordagem precisa de um identificador para ser aberta ao arquivo e, portanto, não é diferente do uso de CfGetPlaceholderRangeInfo.

Para resumir, quando as informações de intervalo são necessárias do contexto de um retorno de chamada CF_CALLBACK_TYPE_FETCH_DATA , essa API deve ser usada. Em todos os outros casos, incluindo quando o provedor deseja hidratar o arquivo sem ser solicitado pelo filtro, CfGetPlaceholderRangeInfo deve ser usado. A plataforma não pode reconhecer qual API é chamada em um contexto específico e, portanto, o ônus está no provedor/Mecanismo de Sincronização para fazer a coisa certa.

Exemplos

Este é um exemplo simples em que a função passa um InfoBuffer suficiente para recuperar apenas uma entrada CF_FILE_RANGE de cada vez. Na prática, o chamador pode passar um InfoBuffer que pode corresponder a várias entradas de CF_FILE_RANGE por invocação da API. O código de erro HRESULT_FROM_WIN32( ERROR_MORE_DATA ) pode ser usado para passar um buffer maior, se necessário.

#include <cfapi.h>

// ******************************************************************************************************
// From within the CF_CALLBACK_TYPE_FETCH_DATA Callback, the provider can use
// g_PlatformInfo.IntegrationNumber to see if the new API is supported. If it is, the provider can pass
// ConnectionKey, TransferKey and FileId along with other parameters to obtain information about file
// ranges which have already been hydrated.
// *******************************************************************************************************

// The provider could obtain file ranges that are hydrated like this:
std::vector<CF_FILE_RANGE> hydratedRanges = GetFileRangesFromCallback( CallbackInfo->ConnectionKey,
                                                                       CallbackInfo->TransferKey,
                                                                       CallbackInfo->FileId,
                                                                       CF_PLACEHOLDER_RANGE_INFO_ONDISK
                                                                       0,
                                                                       CF_EOF);

// Based on these hydratedRanges, the provider can chose to hydrate only ranges which aren’t on the disk.

// ******************************************************************************************************
// Implementation of a function that eventually calls this API.
// ******************************************************************************************************

typedef HRESULT( __stdcall* t_CfGetPlaceholderRangeInfoForHydration )(
    CF_CONNECTION_KEY ConnectionKey,
    CF_TRANSFER_KEY TransferKey,
    LARGE_INTEGER FileId,
    CF_PLACEHOLDER_RANGE_INFO_CLASS InfoClass,
    LARGE_INTEGER StartingOffset,
    LARGE_INTEGER RangeLength,
    PVOID InfoBuffer,
    DWORD InfoBufferSize,
    PDWORD InfoBufferWritten );

t_CfGetPlaceholderRangeInfoForHydration _CfGetPlaceholderRangeInfoForHydration = nullptr;

std::vector<CF_FILE_RANGE>
GetFileRangesFromCallback( CF_CONNECTION_KEY ConnectionKey,
                           CF_TRANSFER_KEY TransferKey,
                           LARGE_INTEGER FileId,
                           CF_PLACEHOLDER_RANGE_INFO_CLASS RangeInfoClass,
                           long long StartOffset,
                           long long Length,
                           PBOOLEAN UseOldAPI )
{

    long long StartOffset = 0;
    CF_FILE_RANGE fileRange;
    long long Length = 0;
    LARGE_INTEGER queryOffset = ll2li( StartOffset );
    LARGE_INTEGER queryLength = ll2li( Length );
    DWORD inforBufferWritten = 0;

    // This will contain all the hydrated ranges in the file if the function succeeds.
    std::vector<CF_FILE_RANGE> ranges;
    bool stop = false;

    CF_PLATFORM_INFO platformInfo;

    hr = (CfGetPlatformInfo( &platformInfo ));
    if(FAILED(hr)) {
        *UseOldAPI = TRUE;
        return ranges; //empty.
    }

    if (platformInfo.IntegrationNumber < 600) {
        *UseOldAPI = TRUE;
        return ranges; //empty.
    }

    wil::unique_hmodule CloudFilesApi( LoadLibrary( L"cldapi.dll" ) );
    THROW_LAST_ERROR_IF_NULL( CloudFilesApi );

    _CfGetPlaceholderRangeInfoForHydration = reinterpret_cast<t_CfGetPlaceholderRangeInfoForHydration>(
            GetProcAddress( CloudFilesApi.get(), "CfGetPlaceholderRangeInfoForHydration" ) );
    THROW_LAST_ERROR_IF_NULL( _CfGetPlaceholderRangeInfoForHydration );

    while ( !stop ) {

        hr = _CfGetPlaceholderRangeInfoForHydration ( ConnectionKey,
                                                      TransferKey,
                                                      FileId,
                                                      RangeInfoClass,
                                                      queryOffset,
                                                      queryLength,
                                                      &fileRange,
                                                      sizeof( fileRange ),
                                                      &infoBufferWritten );

        if ( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) ||
             hr == HRESULT_FROM_WIN32( ERROR_MORE_DATA ) ) {

            // We need to break the loop only if there is no more data.
            if ( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) ) {
                stop = true;
            }

            hr = S_OK;
        }

        if ( FAILED( hr ) || infoBufferWritten == 0 ) {
            return ranges;
        }

        ranges.push_back( fileRange );
        queryOffset.QuadPart = fileRange.StartingOffset.QuadPart + fileRange.Length.QuadPart;

        if ( Length != CF_EOF && queryOffset.QuadPart >= ( StartOffset + Length ) ) {
            stop = true;
        } else if ( Length != CF_EOF) {
            // Update the new query length
            queryLength.QuadPart = StartOffset + Length - queryOffset.QuadPart
        
            if ( queryLength.QuadPart <= 0 ) {
                stop = true;
            }
        }
    }

    return ranges;
}

Requirements

Requirement Value
Header cfapi.h
Library cldapi.lib

Consulte também

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey