다음을 통해 공유


CfGetPlaceholderRangeInfoForHydration 함수(cfapi.h)

자리 표시자 파일 또는 폴더에 대한 범위 정보를 가져옵니다. 이 범위 정보는 CfGetPlaceholderRangeInfo 가 반환하는 것과 동일합니다. 그러나 fileHandle 을 매개 변수로 받아들이지 않습니다. 대신 ConnectionKey, TransferKeyFileId 를 사용하여 범위 정보가 요청되는 파일 및 스트림을 식별합니다.

플랫폼은 CfConnectSyncRoot를 통해 등록된 모든 콜백 함수에 ConnectionKey, TransferKeyFileId를 제공하며 공급자는 이러한 매개 변수를 사용하여 파일에 대한 핸들을 열지 않고도 CF_CALLBACK_TYPE_FETCH_DATA 콜백에서 자리 표시자에 대한 범위 정보를 가져올 수 있습니다.

파일이 클라우드 파일 자리 표시자가 아니면 API가 실패합니다. 성공하면 요청된 특정 InfoClass 에 따라 범위 정보가 반환됩니다.

참고

이 API는 CfGetPlatformInfo에서 가져온 이 이상인 0x600 경우에만 PlatformVersion.IntegrationNumber 사용할 수 있습니다.

구문

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_TYPE_FETCH_DATA 콜백 및 기타 콜백의 CF_CALLBACK_INFO 반환됩니다.

[in] TransferKey

CF_CALLBACK_TYPE_FETCH_DATA 콜백이 호출된 자리 표시자 파일에 대한 불투명 핸들입니다. 또한 CF_CALLBACK_TYPE_FETCH_DATA 콜백의 CF_CALLBACK_INFO 반환됩니다. 또는 API가 CF_CALLBACK_TYPE_FETCH_DATA 콜백에서 호출되지 않는 경우 CfGetTransferKey에서 가져올 수 있습니다.

[in] FileId

서비스할 자리 표시자 파일/디렉터리의 64비트 파일 시스템 유지 관리 볼륨 전체 고유 ID입니다. TransferKey와 마찬가지로 공급자가 다시 검색할 필요가 없도록 CF_CALLBACK_TYPE_FETCH_DATA 및 기타 콜백의 CF_CALLBACK_INFO 반환됩니다.

[in] InfoClass

자리 표시자 데이터 범위의 형식입니다. 값은 다음 중 하나일 수 있습니다.

Description
CF_PLACEHOLDER_RANGE_INFO_ONDISK 디스크 내 데이터는 파일에 실제로 존재하는 데이터입니다. 이것은 다른 유형의 범위의 슈퍼 집합입니다.
CF_PLACEHOLDER_RANGE_INFO_VALIDATED 유효성이 검사된 데이터는 현재 클라우드와 동기화 중인 디스크 내 데이터의 하위 집합입니다.
CF_PLACEHOLDER_RANGEINFO_MODIFIED 수정된 데이터는 현재 클라우드와 동기화되지 않은 디스크 내 데이터의 하위 집합입니다(즉, 수정되거나 추가됨).

[in] StartingOffset

데이터 범위의 시작점 오프셋입니다. StartingOffsetRangeLengthInfoClass 매개 변수에 설명된 대로 정보가 요청되는 자리 표시자 파일의 범위를 지정합니다.

[in] RangeLength

데이터 범위의 길이입니다. 공급자는 RangeLength에 대해 를 지정 CF_EOF 하여 정보가 요청되는 범위가 StartingOffset에서 파일 끝까지임을 나타낼 수 있습니다.

[out] InfoBuffer

데이터를 수신할 버퍼에 대한 포인터입니다. 버퍼는 요청된 범위를 설명하는 오프셋/길이 쌍인 CF_FILE_RANGE 구조체의 배열입니다.

[in] InfoBufferSize

InfoBuffer의 길이(바이트)입니다.

[out, optional] InfoBufferWritten

InfoBuffer에서 반환된 바이트 수를 받습니다.

반환 값

이 함수가 성공하면 를 반환합니다 S_OK. 그러지 않으면 HRESULT 오류 코드를 반환합니다. 몇 가지 일반적인 오류 코드는 다음 표에 나와 있습니다.

오류 코드 의미
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 콜백의 컨텍스트에서 수화되지 않는 파일 부분을 평가하여 파일을 수화하여 IO를 충족합니다.

공급자/동기화 엔진이 CfGetPlaceholderRangeInfo에 매개 변수로 전달될 파일에 대한 핸들을 열려고 할 때 IO 스택의 미니 필터가 파일에 대한 데이터 검사를 실행할 수 있습니다. 또는 미니 필터는 CfGetPlaceholderRangeInfo가 내부적으로 트리거하는 FSCTL_HSM_CONTROL 차단할 수 있습니다.

cldflt 필터는 파일을 하이드레이션하는 데 필요한 파일 범위당 하나의 CF_CALLBACK_TYPE_FETCH_DATA 콜백만 호출하도록 설계되었습니다. 위의 경우 중 하나로 인해 데이터 검색이 원래 CF_CALLBACK_TYPE_FETCH_DATA 뒤에 붙어 있거나 CF_CALLBACK_TYPE_FETCH_DATA 차단된 FSCTL 뒤에 중단됩니다. 이로 인해 하이드레이션 경로에 교착 상태가 발생합니다.

따라서 이 API가 필요합니다. CfGetPlaceholderRangeInfo와 동일한 기능을 수행하지만 중간 IO 스택을 우회하는 필터 메시지 포트를 사용하여 필터와 직접 통신합니다. 따라서 중간 미니 필터가 CreateFile 또는 FSCTL_HSM_CONTROL 방해할 수 없습니다.

호출자에게는 항상 CfConnectSyncRoot를 통해 가져온 ConnectionKey가 있습니다. CfGetTransferKey를 통해 TransferKey를 가져오고 GetFileInformationByHandle을 사용하여 FileId를 가져올 수 있습니다. 그러나 이 방법은 파일에 대한 핸들을 열어야 하므로 CfGetPlaceholderRangeInfo를 사용하는 것과 다르지 않습니다.

요약하자면, CF_CALLBACK_TYPE_FETCH_DATA 콜백의 컨텍스트에서 범위 정보가 필요한 경우 이 API를 사용해야 합니다. 공급자가 필터에서 요청하지 않고 파일을 수화하려는 경우를 포함하여 다른 모든 경우에서 CfGetPlaceholderRangeInfo 를 사용해야 합니다. 플랫폼은 특정 컨텍스트에서 호출되는 API를 인식할 수 없으므로 올바른 작업을 수행하려면 공급자/동기화 엔진에 있습니다.

예제

이는 함수가 한 번에 하나의 CF_FILE_RANGE 항목만 검색하기에 충분한 InfoBuffer를 전달하는 간단한 예제입니다. 실제로 호출자는 API 호출당 여러 CF_FILE_RANGE 항목에 해당할 수 있는 InfoBuffer를 전달할 수 있습니다. 필요한 경우 오류 코드 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;
}

요구 사항

요구 사항
헤더 cfapi.h

추가 정보

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey