Condividi tramite


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

Vedi anche

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey