Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Возвращает сведения о диапазоне сведений о файле заполнителя или папке. Эта информация диапазона идентична возвращаемому значению CfGetPlaceholderRangeInfo . Однако он не принимает fileHandle в качестве параметра. Вместо этого он использует ConnectionKey, TransferKey и FileId для идентификации файла и потока, для которого запрашиваются сведения о диапазоне.
Платформа предоставляет ConnectionKey, TransferKey и FileId всем функциям обратного вызова, зарегистрированным через CfConnectSyncRoot , и поставщик может использовать эти параметры для получения сведений о диапазоне заполнителей из обратного вызова CF_CALLBACK_TYPE_FETCH_DATA без необходимости открыть дескриптор файла.
Если файл не является заполнителем облачных файлов, API завершится сбоем. При успешном выполнении сведения о диапазоне возвращаются в соответствии с конкретным запрошенным InfoClass .
Замечание
Этот API доступен только в том случае, если полученная PlatformVersion.IntegrationNumber из CfGetPlatformInfo0x600 или выше.
Синтаксис
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
);
Параметры
[in] ConnectionKey
Непрозрачный дескриптор, созданный CfConnectSyncRoot для корневого каталога синхронизации, управляемого поставщиком синхронизации. Он возвращается также в CF_CALLBACK_INFO в обратном вызове CF_CALLBACK_TYPE_FETCH_DATA и других обратных вызовах.
[in] TransferKey
Непрозрачный дескриптор в файл заполнителя, для которого был вызван обратный вызов CF_CALLBACK_TYPE_FETCH_DATA . Он также возвращается в CF_CALLBACK_INFO обратного вызова CF_CALLBACK_TYPE_FETCH_DATA . Это можно также получить с помощью CfGetTransferKey , если API не вызывается из CF_CALLBACK_TYPE_FETCH_DATA обратного вызова.
[in] FileId
Уникальный идентификатор 64-разрядной файловой системы на уровне тома для обслуживания файла-заполнителя или каталога. Как и TransferKey, это возвращается в CF_CALLBACK_INFO в CF_CALLBACK_TYPE_FETCH_DATA и других обратных вызовах, чтобы поставщик не должен получить его снова.
[in] InfoClass
Типы диапазона заполнителей. Может иметь следующие значения:
| Ценность | Description |
|---|---|
| CF_PLACEHOLDER_RANGE_INFO_ONDISK | Данные на диске — это данные, которые физически присутствуют в файле. Это супер набор других типов диапазонов. |
| CF_PLACEHOLDER_RANGE_INFO_VALIDATED | Проверенные данные — это подмножество данных на диске, которые в настоящее время синхронизируются с облаком. |
| CF_PLACEHOLDER_RANGEINFO_MODIFIED | Измененные данные — это подмножество данных на диске, которое в настоящее время не синхронизировано с облаком (т. е. изменено или добавлено).) |
[in] StartingOffset
Смещение начальной точки диапазона данных. ЗапускOffset и RangeLength указывают диапазон в файле заполнителя, сведения о котором запрашивается параметром InfoClass .
[in] RangeLength
Длина диапазона данных. Поставщик может указать для RangeLength, чтобы указать CF_EOF диапазон, для которого запрашиваются сведения, от ЗапускаOffset до конца файла.
[out] InfoBuffer
Указатель на буфер, который получит данные. Буфер представляет собой массив CF_FILE_RANGE структур, которые представляют собой пары смещения и длины, описывающие запрошенные диапазоны.
[in] InfoBufferSize
Длина InfoBuffer в байтах.
[out, optional] InfoBufferWritten
Получает количество байтов, возвращаемых в InfoBuffer.
Возвращаемое значение
Если эта функция выполнена успешно, она возвращается S_OK. В противном случае возвращается код ошибки HRESULT . Некоторые распространенные коды ошибок перечислены в следующей таблице:
| Код ошибки | Meaning |
|---|---|
| HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) | Это означает, что StartingOffset> = позиция конца файла. |
| HRESULT_FROM_WIN32( ERROR_MORE_DATA ) | Это означает, что следующая запись CF_FILE_RANGE не соответствует указанному буферу. Вызывающий объект должен проверить, получена ли любая запись или не используется возвращаемое значение InfoBufferWritten . |
Замечания
Хотя API для запроса гидратированных диапазонов файлов заполнителя уже существует, новый API был необходим для повышения надежности платформы.
Для существующего API CfGetPlaceholderRangeInfo требуется открытый дескриптор файла, а затем активирует FSCTL_HSM_CONTROL с помощью этого дескриптора. Обработчики синхронизации обычно используют этот API для оценки того, какие части файла не гидратируются из контекста обратного вызова CF_CALLBACK_TYPE_FETCH_DATA , вызываемого фильтром для гидратации файла для удовлетворения операций ввода-вывода.
Мини-фильтр в стеке операций ввода-вывода может выдавать сканирование данных в файле, когда обработчик поставщика или синхронизации пытается открыть дескриптор файла, передаваемый в качестве параметра в CfGetPlaceholderRangeInfo. Кроме того, мини-фильтр может блокировать FSCTL_HSM_CONTROL , которые активируются в CfGetPlaceholderRangeInfo .
Фильтр cldflt предназначен для вызова только одного вызова CF_CALLBACK_TYPE_FETCH_DATA обратного вызова на требуемый диапазон файлов для обработки файла. В результате любого из указанных выше случаев сканирование данных зависло за исходной CF_CALLBACK_TYPE_FETCH_DATA или CF_CALLBACK_TYPE_FETCH_DATA за заблокированным FSCTL. Это приводит к взаимоблокировке в пути гидратации.
Поэтому этот API необходим. Он выполняет те же функции, что и CfGetPlaceholderRangeInfo, но взаимодействует с фильтром напрямую с помощью портов сообщений фильтра, обходя промежуточный стек ввода-вывода. Поэтому промежуточный мини-фильтр не может препятствовать созданию файла CreateFile или FSCTL_HSM_CONTROL.
Обратите внимание, что вызывающий объект всегда имеет ConnectionKey , полученный через CfConnectSyncRoot. Он может получить TransferKey через CfGetTransferKey и получить FileId с помощью GetFileInformationByHandle. Но этот подход должен открывать дескриптор для файла и поэтому не отличается от использования CfGetPlaceholderRangeInfo.
Чтобы свести итоги, если необходимо получить сведения о диапазоне из контекста обратного вызова CF_CALLBACK_TYPE_FETCH_DATA , этот API следует использовать. Во всех остальных случаях, включая, когда поставщик хочет гидратировать файл без запроса фильтра, следует использовать CfGetPlaceholderRangeInfo . Платформа не может распознать, какой API вызывается в определенном контексте, поэтому он находится на поставщике или обработчике синхронизации, чтобы сделать правильные действия.
Примеры
Это простой пример, в котором функция передает InfoBuffer достаточно, чтобы получить только одну запись CF_FILE_RANGE за раз. На практике вызывающий объект может передать InfoBuffer , который может соответствовать нескольким записям CF_FILE_RANGE для каждого вызова API. Код ошибки HRESULT_FROM_WIN32(ERROR_MORE_DATA) можно использовать для передачи большего буфера при необходимости.
#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;
}
Требования
| Требование | Ценность |
|---|---|
| Header | cfapi.h |
| Library | cldapi.lib |