次の方法で共有


CfGetPlaceholderRangeInfoForHydration 関数 (cfapi.h)

プレースホルダー ファイルまたはフォルダーに関する範囲情報を取得します。 この範囲情報は、 CfGetPlaceholderRangeInfo から返される情報と同じです。 ただし、 fileHandle はパラメーターとして受け取りません。 代わりに、 ConnectionKeyTransferKeyおよび FileId を 使用して、範囲情報が要求されているファイルとストリームを識別します。

プラットフォームは、CfConnectSyncRoot 経由で登録されているすべてのコールバック関数に ConnectionKeyTransferKeyFileId を提供します。プロバイダーは、これらのパラメーターを使用して、ファイルへのハンドルを開く必要なく、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

データ範囲の開始点のオフセット。 StartingOffsetRangeLength は、 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

こちらもご覧ください

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey