CfGetPlaceholderRangeInfoForHydration 関数 (cfapi.h)
プレースホルダー ファイルまたはフォルダーに関する範囲情報を取得します。 この範囲情報は、 CfGetPlaceholderRangeInfo から返される情報と同じです。 ただし、 fileHandle はパラメーターとして受け取りません。 代わりに、 ConnectionKey、 TransferKey、 および FileId を 使用して、範囲情報が要求されているファイルとストリームを識別します。
プラットフォームは、CfConnectSyncRoot 経由で登録されているすべてのコールバック関数に ConnectionKey、TransferKey、FileId を提供します。プロバイダーは、これらのパラメーターを使用して、ファイルへのハンドルを開く必要なく、CF_CALLBACK_TYPE_FETCH_DATA コールバックからプレースホルダーに関する範囲情報を取得できます。
ファイルがクラウド ファイル プレースホルダーでない場合、API は失敗します。 成功すると、要求された特定の InfoClass に従って範囲情報が返されます。
注意
この API は、CfGetPlatformInfo から取得した PlatformVersion.IntegrationNumber
が 以上の0x600
場合にのみ使用できます。
構文
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 がコールバックから呼び出されていない場合は、 CfGetTransferKey によって取得 することもできますCF_CALLBACK_TYPE_FETCH_DATA 。
[in] FileId
サービス対象のプレースホルダー ファイル/ディレクトリの 64 ビット ファイル システムによって管理されるボリューム全体の一意の ID。 TransferKey と同様に、これは、プロバイダーが再度取得する必要がないように、CF_CALLBACK_TYPE_FETCH_DATAおよびその他のコールバックのCF_CALLBACK_INFOで返されます。
[in] InfoClass
プレースホルダー データの範囲の型。 値は次のいずれかになります。
[値] | 説明 |
---|---|
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 フィルターは、ファイルをハイドレートするために必要なファイル範囲ごとに 1 つのCF_CALLBACK_TYPE_FETCH_DATA コールバックのみを呼び出すように設計されています。 上記のいずれかのケースの結果として、データ スキャンが元のCF_CALLBACK_TYPE_FETCH_DATAの背後でスタックしているか、ブロックされた FSCTL の背後でCF_CALLBACK_TYPE_FETCH_DATAがスタックしています。 これにより、ハイドレーション パスでデッドロックが発生します。
そのため、この API が必要です。 CfGetPlaceholderRangeInfo と同じ機能を実行しますが、中間 IO スタックをバイパスするフィルター メッセージ ポートを使用してフィルターと直接通信します。 そのため、中間ミニ フィルターは 、CreateFile または FSCTL_HSM_CONTROLを妨げる可能性があります。
呼び出し元には、常に CfConnectSyncRoot 経由で取得された ConnectionKey があることに注意してください。 CfGetTransferKey を使用して TransferKey を取得し、GetFileInformationByHandle を使用して FileId を取得できます。 ただし、この方法では、ファイルに対してハンドルを開く必要があるため、 CfGetPlaceholderRangeInfo を使用するのと変わる必要はありません。
要約すると、 CF_CALLBACK_TYPE_FETCH_DATA コールバックのコンテキストから範囲情報が必要な場合は、この API を使用する必要があります。 プロバイダーがフィルターによって要求されずにファイルをハイドレートする場合を含め、他のすべての場合は、 CfGetPlaceholderRangeInfo を使用する必要があります。 プラットフォームでは、特定のコンテキストでどの API が呼び出されているかを認識できないため、正しいことを行うためにプロバイダー/同期エンジン上に onus があります。
例
これは、一度に 1 つの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;
}
要件
要件 | 値 |
---|---|
Header | cfapi.h |