Partager via


CfGetPlaceholderRangeInfoForHydratation, fonction (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 renvoie CfGetPlaceholderRangeInfo . Toutefois, il ne prend pas de fichierHandle 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 nécessaire 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 la classe InfoClass spécifique demandée.

Note

Cette API est disponible uniquement si l’objet 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. Elle est également retournée dans CF_CALLBACK_INFO dans le rappel CF_CALLBACK_TYPE_FETCH_DATA et d’autres rappels.

[in] TransferKey

Handle opaque dans le 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 . Cela peut également être obtenu par CfGetTransferKey si l’API n’est pas appelée à partir de CF_CALLBACK_TYPE_FETCH_DATA rappel.

[in] FileId

ID unique à l’échelle du système de fichiers de 64 bits de l’espace réservé/répertoire à traiter. Comme TransferKey, cela est retourné dans CF_CALLBACK_INFO dans le CF_CALLBACK_TYPE_FETCH_DATA et d’autres rappels afin que le fournisseur n’ait pas à le 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 Descriptif
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 (par exemple, 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 afin d’indiquer que la plage pour laquelle les informations demandées sont 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 Meaning
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 de 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

Alors qu’une API pour interroger des plages de fichiers hydratées d’un espace réservé existe déjà, une nouvelle API a été 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 une 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 pour satisfaire un E/S.

Un mini filtre dans la pile d’E/S peut émettre une analyse des données sur le fichier lorsque le moteur fournisseur/synchronisation tente d’ouvrir un handle au fichier à transmettre en tant que paramètre à CfGetPlaceholderRangeInfo. Vous pouvez également bloquer le 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 l’hydratage du fichier. En raison de l’un des cas ci-dessus, l’analyse des données est bloquée derrière la CF_CALLBACK_TYPE_FETCH_DATA d’origine ou la CF_CALLBACK_TYPE_FETCH_DATA est bloquée derrière le FSCTL bloqué. Cela provoque un interblocage dans le chemin d’hydratation.

Par conséquent, cette API est nécessaire. Il effectue la même fonctionnalité que CfGetPlaceholderRangeInfo, mais communique directement avec le filtre à l’aide de ports de message de filtre qui contournent la pile d’E/S intermédiaire. Par conséquent, aucun mini filtre intermédiaire ne peut obstruer createFile ou le FSCTL_HSM_CONTROL.

Notez que l’appelant a toujours la connectionKey obtenue 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 dans le 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, notamment 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, par conséquent, le fournisseur/moteur de synchronisation doit faire la bonne chose.

Examples

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

Spécifications

Requirement Valeur
Header cfapi.h
Library cldapi.lib

Voir aussi

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey