Partager via


Fonction CfGetPlaceholderRangeInfoForHydration (cfapi.h)

Obtient des informations de plage sur un fichier ou un dossier d’espace réservé. Ces informations de plage sont identiques à ce que cfGetPlaceholderRangeInfo retourne. Toutefois, il ne prend pas de fileHandle comme paramètre. Au lieu de cela, il utilise ConnectionKey, TransferKey et FileId pour identifier le fichier et le flux pour lesquels les informations de plage sont demandées.

La plateforme fournit ConnectionKey, TransferKey et FileId à toutes les fonctions de rappel inscrites via CfConnectSyncRoot , et le fournisseur peut utiliser ces paramètres pour obtenir des informations de plage sur un espace réservé à partir du rappel CF_CALLBACK_TYPE_FETCH_DATA sans qu’il soit obligé d’ouvrir un handle dans le fichier.

Si le fichier n’est pas un espace réservé de fichiers cloud, l’API échoue. En cas de réussite, les informations de plage sont retournées en fonction de l’InfoClasse spécifique demandée.

Notes

Cette API n’est disponible que si le PlatformVersion.IntegrationNumber obtenu à partir de CfGetPlatformInfo est 0x600 ou supérieur.

Syntaxe

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
);

Paramètres

[in] ConnectionKey

Handle opaque créé par CfConnectSyncRoot pour une racine de synchronisation gérée par le fournisseur de synchronisation. Il est également retourné dans CF_CALLBACK_INFO dans le rappel CF_CALLBACK_TYPE_FETCH_DATA et d’autres rappels.

[in] TransferKey

Handle opaque du fichier d’espace réservé pour lequel CF_CALLBACK_TYPE_FETCH_DATA rappel a été appelé. Il est également retourné dans CF_CALLBACK_INFO dans le rappel CF_CALLBACK_TYPE_FETCH_DATA . Vous pouvez également l’obtenir par CfGetTransferKey si l’API n’est pas appelée à partir de CF_CALLBACK_TYPE_FETCH_DATA Callback.

[in] FileId

ID unique à l’échelle du volume géré par le système de fichiers 64 bits du fichier/répertoire d’espace réservé à traiter. Comme TransferKey, il est retourné dans CF_CALLBACK_INFO dans le CF_CALLBACK_TYPE_FETCH_DATA et d’autres rappels afin que le fournisseur n’ait pas à la récupérer à nouveau.

[in] InfoClass

Types de la plage de données d’espace réservé. Il peut s'agir de l'une des valeurs suivantes :

Valeur Description
CF_PLACEHOLDER_RANGE_INFO_ONDISK Les données sur disque sont des données physiques présentes dans le fichier. Il s’agit d’un super ensemble d’autres types de plages.
CF_PLACEHOLDER_RANGE_INFO_VALIDATED Les données validées sont un sous-ensemble des données sur disque actuellement synchronisées avec le cloud.
CF_PLACEHOLDER_RANGEINFO_MODIFIED Les données modifiées sont un sous-ensemble des données sur disque qui ne sont actuellement pas synchronisées avec le cloud (c’est-à-dire modifiées ou ajoutées).

[in] StartingOffset

Décalage du point de départ de la plage de données. StartingOffset et RangeLength spécifient une plage dans le fichier d’espace réservé dont les informations, comme décrit par le paramètre InfoClass, sont demandées

[in] RangeLength

Longueur de la plage de données. Un fournisseur peut spécifier CF_EOFpour RangeLength pour indiquer que la plage pour laquelle les informations sont demandées est de StartingOffset à la fin du fichier.

[out] InfoBuffer

Pointeur vers une mémoire tampon qui recevra les données. La mémoire tampon est un tableau de structures CF_FILE_RANGE , qui sont des paires offset/longueur, décrivant les plages demandées.

[in] InfoBufferSize

Longueur d’InfoBuffer en octets.

[out, optional] InfoBufferWritten

Reçoit le nombre d’octets retournés dans InfoBuffer.

Valeur retournée

Si cette fonction réussit, elle retourne S_OK. Sinon, elle retourne un code d’erreur HRESULT. Certains codes d’erreur courants sont répertoriés dans le tableau suivant :

Code d'erreur Signification
HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) Cela signifie que StartingOffset>= la position de la fin du fichier.
HRESULT_FROM_WIN32( ERROR_MORE_DATA ) Cela implique que l’entrée CF_FILE_RANGE suivante ne tient pas dans la mémoire tampon fournie. L’appelant doit vérifier si une entrée est reçue ou non à l’aide de la valeur InfoBufferWritten retournée.

Remarques

Bien qu’il existe déjà une API pour interroger les plages de fichiers hydratés d’un espace réservé, une nouvelle API était nécessaire pour améliorer la fiabilité de la plateforme.

L’API existante, CfGetPlaceholderRangeInfo, nécessite un handle ouvert dans un fichier, puis déclenche un FSCTL_HSM_CONTROL à l’aide de ce handle. Les fournisseurs/moteurs de synchronisation utilisent normalement cette API pour évaluer quelles parties du fichier ne sont pas hydratées à partir du contexte d’un rappel CF_CALLBACK_TYPE_FETCH_DATA appelé par le filtre pour hydrater le fichier afin de satisfaire une E/S.

Un mini filtre dans la pile d’E/S peut émettre une analyse des données sur le fichier lorsque le fournisseur/moteur de synchronisation tente d’ouvrir un handle au fichier à passer en tant que paramètre à CfGetPlaceholderRangeInfo. Un mini filtre peut également bloquer les FSCTL_HSM_CONTROL que CfGetPlaceholderRangeInfo déclenche en interne.

Le filtre cldflt est conçu pour appeler un seul rappel CF_CALLBACK_TYPE_FETCH_DATA par plage de fichiers requise pour hydrater le fichier. En raison de l’un des cas ci-dessus, l’analyse des données est bloquée derrière le CF_CALLBACK_TYPE_FETCH_DATA d’origine ou le CF_CALLBACK_TYPE_FETCH_DATA est bloqué derrière le FSCTL bloqué. Cela provoque un blocage dans le chemin d’hydratation.

Par conséquent, cette API est nécessaire. Il exécute les mêmes fonctionnalités que CfGetPlaceholderRangeInfo, mais communique directement au filtre à l’aide de ports de message de filtre contournant la pile d’E/S intermédiaire. Par conséquent, aucun mini filtre intermédiaire ne peut obstruer le CreateFile ou le FSCTL_HSM_CONTROL.

Notez que l’appelant dispose toujours du ConnectionKey obtenu via CfConnectSyncRoot. Il peut obtenir TransferKey via CfGetTransferKey et obtenir FileId à l’aide de GetFileInformationByHandle. Toutefois, cette approche a besoin d’un handle pour être ouvert au fichier et n’est donc pas différente de l’utilisation de CfGetPlaceholderRangeInfo.

Pour résumer, lorsque des informations de plage sont nécessaires à partir du contexte d’un rappel CF_CALLBACK_TYPE_FETCH_DATA , cette API doit être utilisée. Dans tous les autres cas, y compris lorsque le fournisseur souhaite hydrater le fichier sans être demandé par le filtre, CfGetPlaceholderRangeInfo doit être utilisé. La plateforme ne peut pas reconnaître quelle API est appelée dans un contexte spécifique et il incombe donc au fournisseur/moteur de synchronisation de faire la bonne chose.

Exemples

Il s’agit d’un exemple simple où la fonction transmet un InfoBuffer suffisant pour récupérer une seule entrée CF_FILE_RANGE à la fois. Dans la pratique, l’appelant peut passer un InfoBuffer qui peut correspondre à plusieurs entrées CF_FILE_RANGE par appel de l’API. Le code d’erreur HRESULT_FROM_WIN32( ERROR_MORE_DATA ) peut être utilisé pour passer une mémoire tampon plus grande si nécessaire.

#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;
}

Configuration requise

Condition requise Valeur
En-tête cfapi.h

Voir aussi

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey