What is FetchData.OptionalFileOffset? (cfapi)

oknick 101 Reputation points
2022-02-23T19:07:20.4+00:00

The FetchData struct of a CF_CALLBACK_PARAMETERS has a OptionalFileOffset and OptionalLength field. The docs say it specifies a "broader piece of data" that is used if a provider wants to work with "larger segments of data," but what does this really mean? Shouldn't the file range always be determined by the hydration type? For example, if partial hydration is specified, shouldn't the file range always be the exact amount of bytes the user wants? So then where do these optional fields actually come into play, and when are they different from the non-optional fields?

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,575 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Junjie Zhu - MSFT 17,226 Reputation points Microsoft Vendor
    2022-02-24T07:38:08.89+00:00

    Hello,
    Welcome to Microsoft Q&A!

    Here is an example for your reference https://github.com/Microsoft/Windows-classic-samples/tree/main/Samples/CloudMirror
    Generally, RequiredFileOffset and RequiredLength are used. If optionalFileOffset and optionalLength are used in the callback, it means that you need to deal with larger modules. This is just to provide you with an option. The specific data read in the callback needs to be set by yourself. Using these two parameters will not have any impact on normal reading. It is only the passed parameters, use or not use, Need to decide for yourself.

    // In a nutshell, it copies a file from the "server" to the  
    // "client" using the overlapped trickery of Windows to  
    // chunkatize the copy. This way you don't have to allocate  
    // a huge buffer.  
    void FileCopierWithProgress::CopyFromServerToClientWorker(  
        _In_ CONST CF_CALLBACK_INFO* callbackInfo,  
        _In_opt_ CONST CF_PROCESS_INFO* processInfo,  
        _In_ LARGE_INTEGER requiredFileOffset,  
        _In_ LARGE_INTEGER requiredLength,  
        _In_ LARGE_INTEGER /*optionalFileOffset*/,  
        _In_ LARGE_INTEGER /*optionalLength*/,  
        _In_ CF_CALLBACK_FETCH_DATA_FLAGS /*fetchFlags*/,  
        _In_ UCHAR priorityHint,  
        _In_ LPCWSTR serverFolder)  
    {  
        HANDLE serverFileHandle;  
      
        std::wstring fullServerPath(serverFolder);  
        fullServerPath.append(L"\\");  
        fullServerPath.append(reinterpret_cast<wchar_t const*>(callbackInfo->FileIdentity));  
      
        std::wstring fullClientPath(callbackInfo->VolumeDosName);  
        fullClientPath.append(callbackInfo->NormalizedPath);  
      
        READ_COMPLETION_CONTEXT* readCompletionContext;  
        DWORD chunkBufferSize;  
      
        wprintf(L"[%04x:%04x] - Received data request from %s for %s%s, priority %d, offset %08x`%08x length %08x`%08x\n",  
            GetCurrentProcessId(),  
            GetCurrentThreadId(),  
            (processInfo && processInfo->ImagePath) ? processInfo->ImagePath : L"UNKNOWN",  
            callbackInfo->VolumeDosName,  
            callbackInfo->NormalizedPath,  
            priorityHint,  
            requiredFileOffset.HighPart,  
            requiredFileOffset.LowPart,  
            requiredLength.HighPart,  
            requiredLength.LowPart);  
      
        serverFileHandle =   
            CreateFile(  
                fullServerPath.c_str(),  
                GENERIC_READ,  
                FILE_SHARE_READ | FILE_SHARE_DELETE,  
                NULL,  
                OPEN_EXISTING,  
                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,  
                NULL);  
      
        if (serverFileHandle == INVALID_HANDLE_VALUE)   
        {  
            HRESULT hr = NTSTATUS_FROM_WIN32(GetLastError());  
      
            wprintf(L"[%04x:%04x] - Failed to open %s for read, hr %x\n",  
                GetCurrentProcessId(),  
                GetCurrentThreadId(),  
                fullServerPath.c_str(),  
                hr);  
      
            winrt::check_hresult(hr);  
        }  
      
        // Allocate the buffer used in the overlapped read.  
        chunkBufferSize = (ULONG)min(requiredLength.QuadPart, CHUNKSIZE);  
      
        readCompletionContext = (READ_COMPLETION_CONTEXT*)  
            HeapAlloc(  
                GetProcessHeap(),  
                0,  
                chunkBufferSize + FIELD_OFFSET(READ_COMPLETION_CONTEXT, Buffer));  
      
        if (readCompletionContext == NULL)   
        {  
            HRESULT hr = E_OUTOFMEMORY;  
      
            wprintf(L"[%04x:%04x] - Failed to allocate read buffer for %s, hr %x\n",  
                GetCurrentProcessId(),  
                GetCurrentThreadId(),  
                fullServerPath.c_str(),  
                hr);  
      
            CloseHandle(serverFileHandle);  
            winrt::check_hresult(hr);  
        }  
      
        // Tell the read completion context where to copy the chunk(s)  
        wcsncpy_s(  
            readCompletionContext->FullPath,  
            fullClientPath.data(),  
            wcslen(fullClientPath.data()));  
      
        // Set up the remainder of the overlapped stuff  
        readCompletionContext->CallbackInfo = *callbackInfo;  
        readCompletionContext->Handle = serverFileHandle;  
        readCompletionContext->PriorityHint = priorityHint;  
        readCompletionContext->Overlapped.Offset = requiredFileOffset.LowPart;  
        readCompletionContext->Overlapped.OffsetHigh = requiredFileOffset.HighPart;  
        readCompletionContext->StartOffset = requiredFileOffset;  
        readCompletionContext->RemainingLength = requiredLength;  
        readCompletionContext->BufferSize = chunkBufferSize;  
      
        wprintf(L"[%04x:%04x] - Downloading data for %s, priority %d, offset %08x`%08x length %08x\n",  
            GetCurrentProcessId(),  
            GetCurrentThreadId(),  
            readCompletionContext->FullPath,  
            priorityHint,  
            requiredFileOffset.HighPart,  
            requiredFileOffset.LowPart,  
            chunkBufferSize);  
      
        // Initiate the read for the first chunk. When this async operation  
        // completes (failure or success), it will call the OverlappedCompletionRoutine  
        // above with that chunk. That OverlappedCompletionRoutine is responsible for  
        // subsequent ReadFileEx calls to read subsequent chunks. This is only for the  
        // first one  
        if (!ReadFileEx(  
            serverFileHandle,  
            readCompletionContext->Buffer,  
            chunkBufferSize,  
            &readCompletionContext->Overlapped,  
            OverlappedCompletionRoutine))   
        {  
            HRESULT hr = NTSTATUS_FROM_WIN32(GetLastError());  
            wprintf(L"[%04x:%04x] - Failed to perform async read for %s, Status %x\n",  
                GetCurrentProcessId(),  
                GetCurrentThreadId(),  
                fullServerPath.c_str(),  
                hr);  
      
            CloseHandle(serverFileHandle);  
            HeapFree(GetProcessHeap(), 0, readCompletionContext);  
      
            winrt::check_hresult(hr);  
        }  
    }  
    

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.