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_EOF
pour 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 |