CfGetPlaceholderRangeInfoForHydration 函式 (cfapi.h)
取得佔位元檔案或資料夾的範圍資訊。 此範圍資訊與 CfGetPlaceholderRangeInfo 傳回的內容相同。 不過,它不會採用 fileHandle 作為參數。 相反地,它會使用 ConnectionKey、 TransferKey 和 FileId 來識別要求範圍資訊的檔案和數據流。
平臺會將 ConnectionKey、 TransferKey 和 FileId 提供給透過 CfConnectSyncRoot 註冊的所有回呼函式,提供者可以使用這些參數,從 CF_CALLBACK_TYPE_FETCH_DATA 回呼取得佔位符的範圍資訊,而不需要開啟檔案的句柄。
如果檔案不是雲端檔案佔位符,API 將會失敗。 成功時,會根據所要求的特定 InfoClass 傳回範圍資訊。
注意
只有當從 CfGetPlatformInfo 取得的 是0x600
或更新版本時PlatformVersion.IntegrationNumber
,才可使用此 API。
語法
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位檔系統維護全磁碟區唯一標識元。 如同 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
數據範圍的長度。 提供者可以指定 CF_EOF
RangeLength ,以指出要求資訊的範圍是從 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,因此 onus 位於提供者/同步處理引擎上,以執行正確的動作。
範例
這是一個簡單的範例,其中函式會傳遞足以一次只擷取一個CF_FILE_RANGE專案的InfoBuffer。 在實務上,呼叫端可以傳遞 InfoBuffer ,以根據 API 的調用對應至多個 CF_FILE_RANGE 專案。 如有需要 ,可以使用 錯誤碼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 |