Función CfGetPlaceholderRangeInfoForHydration (cfapi.h)
Obtiene información de intervalo sobre un archivo o carpeta de marcador de posición. Esta información de intervalo es idéntica a la que devuelve CfGetPlaceholderRangeInfo . Sin embargo, no toma un fileHandle como parámetro. En su lugar, usa ConnectionKey, TransferKey y FileId para identificar el archivo y la secuencia para la que se solicita información de intervalo.
La plataforma proporciona ConnectionKey, TransferKey y FileId a todas las funciones de devolución de llamada registradas a través de CfConnectSyncRoot y el proveedor podría usar estos parámetros para obtener información de intervalo sobre un marcador de posición de la devolución de llamada de CF_CALLBACK_TYPE_FETCH_DATA sin necesidad de abrir un identificador para el archivo.
Si el archivo no es un marcador de posición de archivos en la nube, se producirá un error en la API. Si se ejecuta correctamente, se devuelve información de intervalo según la infoclass específica solicitada.
Nota
Esta API solo está disponible si el PlatformVersion.IntegrationNumber
obtenido de CfGetPlatformInfo es 0x600
o superior.
Sintaxis
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
Identificador opaco creado por CfConnectSyncRoot para una raíz de sincronización administrada por el proveedor de sincronización. También se devuelve en CF_CALLBACK_INFO en la devolución de llamada CF_CALLBACK_TYPE_FETCH_DATA y otras devoluciones de llamada.
[in] TransferKey
Identificador opaco del archivo de marcador de posición para el que se ha invocado CF_CALLBACK_TYPE_FETCH_DATA devolución de llamada. También se devuelve en CF_CALLBACK_INFO en la devolución de llamada CF_CALLBACK_TYPE_FETCH_DATA . Como alternativa, CfGetTransferKey puede obtener esto si la API no se invoca desde CF_CALLBACK_TYPE_FETCH_DATA devolución de llamada.
[in] FileId
Identificador único de todo el volumen mantenido por el sistema de archivos de 64 bits del archivo o directorio del marcador de posición que se va a atender. Al igual que TransferKey, esto se devuelve en CF_CALLBACK_INFO en el CF_CALLBACK_TYPE_FETCH_DATA y otras devoluciones de llamada para que el proveedor no tenga que recuperarlo de nuevo.
[in] InfoClass
Tipos del intervalo de datos de marcador de posición. El valor puede ser uno de los siguientes:
Valor | Descripción |
---|---|
CF_PLACEHOLDER_RANGE_INFO_ONDISK | Los datos en disco son datos que están presentes físicamente en el archivo. Se trata de un superconjunto de otros tipos de intervalos. |
CF_PLACEHOLDER_RANGE_INFO_VALIDATED | Los datos validados son un subconjunto de los datos en disco que están sincronizados actualmente con la nube. |
CF_PLACEHOLDER_RANGEINFO_MODIFIED | Los datos modificados son un subconjunto de los datos en disco que actualmente no están sincronizados con la nube (es decir, modificados o anexados). |
[in] StartingOffset
Desplazamiento del punto inicial del intervalo de datos. StartingOffset y RangeLength especifican un intervalo en el archivo de marcador de posición cuya información se describe en el parámetro InfoClass se solicita.
[in] RangeLength
Longitud del intervalo de datos. Un proveedor puede especificar CF_EOF
para RangeLength para indicar que el intervalo para el que se solicita información es de StartingOffset al final del archivo.
[out] InfoBuffer
Puntero a un búfer que recibirá los datos. El búfer es una matriz de estructuras de CF_FILE_RANGE , que son pares de desplazamiento y longitud, que describen los intervalos solicitados.
[in] InfoBufferSize
Longitud de InfoBuffer en bytes.
[out, optional] InfoBufferWritten
Recibe el número de bytes devueltos en InfoBuffer.
Valor devuelto
Si esta función se ejecuta correctamente, devuelve S_OK
. De lo contrario, devuelve un código de error de HRESULT. Algunos códigos de error comunes se enumeran en la tabla siguiente:
Código de error | Significado |
---|---|
HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) | Esto significa que StartingOffset>= la posición del final del archivo. |
HRESULT_FROM_WIN32( ERROR_MORE_DATA ) | Esto implica que la siguiente entrada CF_FILE_RANGE no cabe en el búfer proporcionado. El autor de la llamada debe comprobar si se recibe alguna entrada o no utilizando el valor infoBufferWritten devuelto. |
Comentarios
Aunque ya existe una API para consultar intervalos de archivos hidratados de un marcador de posición, se necesitaba una nueva API para mejorar la confiabilidad de la plataforma.
La API existente, CfGetPlaceholderRangeInfo, requiere un identificador abierto para un archivo y, a continuación, desencadena un FSCTL_HSM_CONTROL mediante ese identificador. Los proveedores o motores de sincronización usan normalmente esta API para evaluar qué partes del archivo no se hidratan del contexto de una devolución de llamada de CF_CALLBACK_TYPE_FETCH_DATA invocada por el filtro para hidratar el archivo para satisfacer una E/S.
Un mini filtro en la pila de E/S podría emitir un examen de datos en el archivo cuando el motor de proveedor o sincronización intenta abrir un identificador para el archivo que se va a pasar como parámetro a CfGetPlaceholderRangeInfo. Como alternativa, un filtro mini podría bloquear el FSCTL_HSM_CONTROL que CfGetPlaceholderRangeInfo desencadena internamente.
El filtro cldflt está diseñado para invocar solo una CF_CALLBACK_TYPE_FETCH_DATA devolución de llamada por intervalo de archivos necesario para hidratar el archivo. Como resultado de cualquiera de los casos anteriores, el examen de datos se bloquea detrás del CF_CALLBACK_TYPE_FETCH_DATA original o el CF_CALLBACK_TYPE_FETCH_DATA está bloqueado detrás del FSCTL bloqueado. Esto provoca un interbloqueo en la ruta de hidratación.
Por lo tanto, esta API es necesaria. Realiza la misma funcionalidad que CfGetPlaceholderRangeInfo, pero se comunica directamente con el filtro mediante puertos de mensaje de filtro pasando la pila de E/S intermedia. Por lo tanto, ningún mini filtro intermedio puede obstruir createFile o el FSCTL_HSM_CONTROL.
Tenga en cuenta que el autor de la llamada siempre tiene connectionKey obtenido a través de CfConnectSyncRoot. Puede obtener TransferKey a través de CfGetTransferKey y obtener FileId mediante GetFileInformationByHandle. Sin embargo, este enfoque necesita un identificador que se abra en el archivo y, por tanto, no es diferente del uso de CfGetPlaceholderRangeInfo.
En resumen, cuando se necesita información de intervalo desde el contexto de una devolución de llamada de CF_CALLBACK_TYPE_FETCH_DATA , se debe usar esta API. En todos los demás casos, incluido cuando el proveedor quiere hidratar el archivo sin ser solicitado por el filtro, se debe usar CfGetPlaceholderRangeInfo . La plataforma no puede reconocer a qué API se llama en un contexto específico y, por lo tanto, la responsabilidad está en el proveedor o el motor de sincronización para hacer lo correcto.
Ejemplos
Este es un ejemplo sencillo en el que la función pasa un InfoBuffer suficiente para recuperar solo una entrada de CF_FILE_RANGE cada vez. En la práctica, el autor de la llamada podría pasar un infoBuffer que podría corresponder a varias entradas de CF_FILE_RANGE por invocación de la API. El código de error HRESULT_FROM_WIN32( ERROR_MORE_DATA ) se podría usar para pasar un búfer más grande si es necesario.
#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 |
---|---|
Header | cfapi.h |