Funzione CfGetPlaceholderRangeInfoForHydration (cfapi.h)
Ottiene informazioni sull'intervallo su un file o una cartella segnaposto. Queste informazioni sull'intervallo sono identiche a quanto restituito da CfGetPlaceholderRangeInfo . Tuttavia, non accetta un fileHandle come parametro. Usa invece ConnectionKey, TransferKey e FileId per identificare il file e il flusso per cui vengono richieste informazioni sull'intervallo.
La piattaforma fornisce ConnectionKey, TransferKey e FileId a tutte le funzioni di callback registrate tramite CfConnectSyncRoot e il provider può usare questi parametri per ottenere informazioni sull'intervallo su un segnaposto dal callback CF_CALLBACK_TYPE_FETCH_DATA senza richiedere l'apertura di un handle al file.
Se il file non è un segnaposto per i file cloud, l'API avrà esito negativo. In caso di esito positivo, le informazioni sull'intervallo vengono restituite in base alla specifica InfoClass richiesta.
Nota
Questa API è disponibile solo se l'oggetto PlatformVersion.IntegrationNumber
ottenuto da CfGetPlatformInfo è 0x600
o versione successiva.
Sintassi
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
);
Parametri
[in] ConnectionKey
Handle opaco creato da CfConnectSyncRoot per una radice di sincronizzazione gestita dal provider di sincronizzazione. Viene restituito anche in CF_CALLBACK_INFO nel callback CF_CALLBACK_TYPE_FETCH_DATA e in altri callback.
[in] TransferKey
Handle opaco per il file segnaposto per il quale è stato richiamato CF_CALLBACK_TYPE_FETCH_DATA callback. Viene restituito anche in CF_CALLBACK_INFO nel callback CF_CALLBACK_TYPE_FETCH_DATA . Questa opzione può essere ottenuta in alternativa da CfGetTransferKey se l'API non viene richiamata da CF_CALLBACK_TYPE_FETCH_DATA Callback.
[in] FileId
ID univoco a livello di volume gestito dal file system a 64 bit del file o della directory segnaposto da gestire. Come TransferKey, viene restituito in CF_CALLBACK_INFO nel CF_CALLBACK_TYPE_FETCH_DATA e in altri callback in modo che il provider non deve recuperarlo di nuovo.
[in] InfoClass
Tipi dell'intervallo di dati segnaposto. I possibili valori sono i seguenti:
Valore | Descrizione |
---|---|
CF_PLACEHOLDER_RANGE_INFO_ONDISK | I dati su disco sono dati fisici presenti nel file. Si tratta di un super set di altri tipi di intervalli. |
CF_PLACEHOLDER_RANGE_INFO_VALIDATED | I dati convalidati sono un subset dei dati su disco attualmente sincronizzati con il cloud. |
CF_PLACEHOLDER_RANGEINFO_MODIFIED | I dati modificati sono un subset dei dati su disco attualmente non sincronizzati con il cloud (ad esempio, modificati o aggiunti). |
[in] StartingOffset
Offset del punto iniziale dell'intervallo di dati. StartingOffset e RangeLength specificano un intervallo nel file segnaposto le cui informazioni, come descritto dal parametro InfoClass , vengono richieste
[in] RangeLength
Lunghezza dell'intervallo di dati. Un provider può specificare CF_EOF
per RangeLength per indicare che l'intervallo per cui sono richieste informazioni è da StartingOffset alla fine del file.
[out] InfoBuffer
Puntatore a un buffer che riceverà i dati. Il buffer è una matrice di strutture CF_FILE_RANGE , ovvero coppie di offset/lunghezza, che descrivono gli intervalli richiesti.
[in] InfoBufferSize
Lunghezza di InfoBuffer in byte.
[out, optional] InfoBufferWritten
Riceve il numero di byte restituiti in InfoBuffer.
Valore restituito
Se questa funzione ha esito positivo, restituisce S_OK
. In caso contrario, restituisce un codice di errore HRESULT . Nella tabella seguente sono elencati alcuni codici di errore comuni:
Codice di errore | Significato |
---|---|
HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) | Ciò significa che StartingOffset>= la posizione della fine del file. |
HRESULT_FROM_WIN32( ERROR_MORE_DATA ) | Ciò implica che la voce di CF_FILE_RANGE successiva non rientra nel buffer fornito. Il chiamante deve verificare se una voce viene ricevuta o meno utilizzando il valore InfoBufferWritten restituito. |
Commenti
Anche se esiste già un'API per eseguire query su intervalli di file idratati di un segnaposto, è necessaria una nuova API per migliorare l'affidabilità della piattaforma.
L'API esistente , CfGetPlaceholderRangeInfo, richiede un handle aperto in un file e quindi attiva un FSCTL_HSM_CONTROL usando tale handle. I provider/motori di sincronizzazione usano normalmente questa API per valutare quali parti del file non vengono idratate dal contesto di un CF_CALLBACK_TYPE_FETCH_DATA callback richiamato dal filtro per idratare il file per soddisfare un I/O.
Un mini filtro nello stack di I/O potrebbe eseguire l'analisi dei dati nel file quando il motore di provider/sincronizzazione tenta di aprire un handle per il file da passare come parametro a CfGetPlaceholderRangeInfo. In alternativa, un mini filtro potrebbe bloccare il FSCTL_HSM_CONTROL che CfGetPlaceholderRangeInfo attiva internamente.
Il filtro cldflt è progettato per richiamare un solo CF_CALLBACK_TYPE_FETCH_DATA callback per ogni intervallo di file necessario per idratare il file. In seguito a uno dei casi precedenti, l'analisi dei dati è bloccata dietro l'CF_CALLBACK_TYPE_FETCH_DATA originale o la CF_CALLBACK_TYPE_FETCH_DATA è bloccata dietro il BLOCKEDTL bloccato.As a result of either of above case, either the data scan is stuck behind the original CF_CALLBACK_TYPE_FETCH_DATA or the CF_CALLBACK_TYPE_FETCH_DATA is stuck behind the blocked MDFTL. Ciò causa un deadlock nel percorso di idratazione.
Di conseguenza, questa API è necessaria. Esegue la stessa funzionalità di CfGetPlaceholderRangeInfo, ma comunica con il filtro direttamente usando le porte dei messaggi di filtro ignorando lo stack di I/O intermedio. Pertanto, nessun filtro mini intermedio può ostruire il CreateFile o il FSCTL_HSM_CONTROL.
Si noti che il chiamante ha sempre connectionKey ottenuto tramite CfConnectSyncRoot. Può ottenere TransferKey tramite CfGetTransferKey e ottenere FileId usando GetFileInformationByHandle. Tuttavia, questo approccio richiede l'apertura di un handle al file e pertanto non è diverso dall'uso di CfGetPlaceholderRangeInfo.
Per riepilogare, quando sono necessarie informazioni sull'intervallo dal contesto di un callback CF_CALLBACK_TYPE_FETCH_DATA , questa API deve essere usata. In tutti gli altri casi, incluso quando il provider vuole idratare il file senza essere richiesto dal filtro, è consigliabile usare CfGetPlaceholderRangeInfo . La piattaforma non è in grado di riconoscere quale API viene chiamata in un contesto specifico e quindi l'uso è sul provider/motore di sincronizzazione per eseguire la cosa giusta.
Esempio
Questo è un semplice esempio in cui la funzione passa un InfoBuffer sufficiente per recuperare una sola voce CF_FILE_RANGE alla volta. In pratica, il chiamante potrebbe passare un InfoBuffer che potrebbe corrispondere a più CF_FILE_RANGE voci per chiamata dell'API. Il codice di errore HRESULT_FROM_WIN32( ERROR_MORE_DATA ) può essere usato per passare un buffer più grande, se necessario.
#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;
}
Requisiti
Requisito | Valore |
---|---|
Intestazione | cfapi.h |