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, ele não usa 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 o PlatformVersion.IntegrationNumber
obtido 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 64 bits do arquivo/diretório de 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:
Valor | Descrição |
---|---|
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 de partida 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.
Retornar valor
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 | Significado |
---|---|
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. |
Comentários
Embora já exista uma API para consultar intervalos de arquivos hidratados de um espaço reservado, uma nova API foi necessária para melhorar a confiabilidade da plataforma.
A API existente, CfGetPlaceholderRangeInfo, requer um identificador aberto para um arquivo e, em seguida, 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 minifiltro na pilha de E/S pode emitir a 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 uma 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 por meio de CfGetTransferKey e obter FileId usando GetFileInformationByHandle. Mas essa abordagem precisa de um identificador para ser aberta ao arquivo e, portanto, não é diferente de usar 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 por vez. Na prática, o chamador pode passar um InfoBuffer que pode corresponder a várias entradas 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;
}
Requisitos
Requisito | Valor |
---|---|
Cabeçalho | cfapi.h |