Поделиться через


Функция CfGetPlaceholderRangeInfoForHydration (cfapi.h)

Возвращает сведения о диапазоне сведений о файле заполнителя или папке. Эта информация диапазона идентична возвращаемому значению 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

См. также

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey