CfGetPlaceholderRangeInfoForHydration 함수(cfapi.h)
자리 표시자 파일 또는 폴더에 대한 범위 정보를 가져옵니다. 이 범위 정보는 CfGetPlaceholderRangeInfo 가 반환하는 것과 동일합니다. 그러나 fileHandle 을 매개 변수로 받아들이지 않습니다. 대신 ConnectionKey, TransferKey 및 FileId 를 사용하여 범위 정보가 요청되는 파일 및 스트림을 식별합니다.
플랫폼은 CfConnectSyncRoot를 통해 등록된 모든 콜백 함수에 ConnectionKey, TransferKey 및 FileId를 제공하며 공급자는 이러한 매개 변수를 사용하여 파일에 대한 핸들을 열지 않고도 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
데이터 범위의 시작점 오프셋입니다. StartingOffset 및 RangeLength 는 InfoClass 매개 변수에 설명된 대로 정보가 요청되는 자리 표시자 파일의 범위를 지정합니다.
[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 |