title: Windows 10 File Cloud / Sync Provider API - TransferData problem
body: <p>I am building upon the <a href="https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/CloudMirror" rel="nofollow noreferrer">Cloud Mirror Sample</a> and having a similar issue to <a href="https://stackoverflow.com/questions/60733034/cfapi-cloud-operation-is-invalid?r=SearchResults&amp;s=3%7C7.1670">this one</a></p>
  <p>Here is the test code involved:</p>
  <pre><code>        // When the client needs to fetch data from the cloud, this method will be called.
      // The FakeMirrorDataMover class does the actual work of copying files from
      // the &quot;cloud&quot; to the &quot;client&quot; and updating the transfer status along the way.
      void CALLBACK FakeCloudProvider::OnFetchData(
          _In_ CONST CF_CALLBACK_INFO* callbackInfo,
          _In_ CONST CF_CALLBACK_PARAMETERS* callbackParameters)
      {
          //FileCopierWithProgress::CopyFromServerToClient(callbackInfo, callbackParameters, ProviderFolderLocations::GetServerFolder());
      
              const UINT CHUNKSIZE = 48 * 1024 * 1024;
              UINT len;
              LONG64 offset = callbackParameters-&gt;FetchData.RequiredFileOffset.QuadPart;
              LONG64 requiredLength = callbackParameters-&gt;FetchData.RequiredLength.QuadPart;
              byte *buffer = new byte[CHUNKSIZE];
              FillMemory(buffer, CHUNKSIZE, (byte)0xA5);
      
              while (0 &lt; requiredLength)
              {
                  len = requiredLength &lt; CHUNKSIZE ? requiredLength : CHUNKSIZE;
                  if (0 != len % 4096)
                      len = 4096 * (len / 4096 + 1);
      
                  Placeholders::TransferData(callbackInfo-&gt;TransferKey.QuadPart, buffer, offset, len, 0);
      
                  requiredLength -= len;
                  offset += len;
              }
      
              delete[] buffer;
      }
  
  HRESULT Placeholders::TransferData(
      //_In_ CF_CONNECTION_KEY connectionKey,
      _In_ LONG64 transferKey,
      _In_reads_bytes_opt_(length.QuadPart) LPCVOID transferData,
      _In_ LONG64 startingOffset,
      _In_ LONG64 length,
      _In_ NTSTATUS completionStatus)
  {
      CF_OPERATION_INFO opInfo = { 0 };
      CF_OPERATION_PARAMETERS opParams = { 0 };
  
      opInfo.StructSize = sizeof(opInfo);
      opInfo.Type = CF_OPERATION_TYPE_TRANSFER_DATA;
      opInfo.ConnectionKey = FakeCloudProvider::GetConnectionKey();
      opInfo.TransferKey.QuadPart = transferKey;
      opParams.ParamSize = CF_SIZE_OF_OP_PARAM(TransferData);
      opParams.TransferData.CompletionStatus = completionStatus;
      opParams.TransferData.Buffer = transferData;
      opParams.TransferData.Offset.QuadPart = startingOffset;
      opParams.TransferData.Length.QuadPart = length;
  
      winrt::check_hresult(CfExecute(&amp;opInfo, &amp;opParams));     
      return S_OK;
  }
  </code></pre>
  <p>There is only one placeholder file created inside the sync root folder of ~ 9.3 GB size. After I create this I either double click it or right click and &quot;always keep on this device&quot; - same result.</p>
  <p>The result being that after the last call to <code>TransferData</code> the Windows Explorer file progress gets stuck. It will eventually time out, I click on &quot;try again&quot;, my breakpoints inside <code>OnFetchData()</code> get hit and file progress remains stuck. If I cancel the transfer then <code>onCancelFetchData()</code> gets called once as it should. Subsequent attempts to download the rest of the file <em>will no longer call <code>onFetchData()</code></em></p>
  <p>If I comment out the <code>if (0 != len % 4096)      len = 4096 * (len / 4096 + 1);</code> part then I am getting the dreaded <code>0x8007017c the cloud operation is invalid</code> with the rest of the symptoms as above.</p>
  <p>I have tried with a smaller ~ 9.3 MB file and it went fine... what else to try?</p>
  <p><strong>edit</strong></p>
  <p>The ~100MB and ~1GB sizes also working fine</p>
  <p>Result of <code>CfExecute</code> calls:</p>
  <pre><code>//[...] same output for all previous offsets except for the last call
  TransferData method - offset: 1298137088, length: 50331648, syncStatBeforeCall: null, syncStatAfterCall: null, hresult: 0
  TransferData method - offset: 1348468736, length: 50331648, syncStatBeforeCall: null, syncStatAfterCall: null, hresult: 0
  TransferData method - offset: 1398800384, length: 11265024, syncStatBeforeCall: null, syncStatAfterCall: null, hresult: 8007017c
  </code></pre>
  <p>As far as I can tell null is fine for <code>SyncStatus</code>:</p>
  <blockquote>
  <p>SyncStatus</p>
  <p>Note  This member is new for Windows 10, version 1803.</p>
  <p>The current sync status of the platform.</p>
  <p>The platform queries this information upon any failed operations on a
  cloud file placeholder. If a structure is available, the platform will
  use the information provided to construct a more meaningful and
  actionable message to the user. The platform will keep this
  information on the file until the last handle on it goes away. If
  null, the platform will clear the previously set sync status, if there
  is one.</p>
  </blockquote>
  <p><strong>--edit--</strong></p>
  <pre><code>HRESULT Placeholders::Create(_In_ PCWSTR destPath,
                            _In_ PCWSTR fileName,
                            _In_ CF_PLACEHOLDER_CREATE_FLAGS flags,
                            _In_ LONG64 fileSize,
                            _In_ DWORD fileAttributes,
                            _In_ LONG64  ftCreationTime,
                            _In_ LONG64  ftLastWriteTime,
                            _In_ LONG64  ftLastAccessTime,
                            _In_ LONG64  ftChangeTime)
  {
      CF_PLACEHOLDER_CREATE_INFO cloudEntry;
          
      cloudEntry.FileIdentity = fileName;
      cloudEntry.FileIdentityLength = (DWORD)((wcslen(fileName)+1) * sizeof(WCHAR));
      cloudEntry.RelativeFileName = fileName;
      cloudEntry.Flags = flags;
      cloudEntry.FsMetadata.FileSize.QuadPart = fileSize;
      cloudEntry.FsMetadata.BasicInfo.FileAttributes = fileAttributes;
      cloudEntry.FsMetadata.BasicInfo.CreationTime.QuadPart = ftCreationTime;
      cloudEntry.FsMetadata.BasicInfo.LastWriteTime.QuadPart = ftLastWriteTime;
      cloudEntry.FsMetadata.BasicInfo.LastAccessTime.QuadPart = ftLastAccessTime;
      cloudEntry.FsMetadata.BasicInfo.ChangeTime.QuadPart = ftChangeTime;
  
      if ((fileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY) != 0)
      {
          cloudEntry.Flags |= CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION;
          cloudEntry.FsMetadata.FileSize.QuadPart = 0;
          cloudEntry.FileIdentity = nullptr;
      }
  
      try
      {
          wprintf(L&quot;Creating placeholder for %s\n&quot;, fileName);
          winrt::check_hresult(CfCreatePlaceholders(destPath, &amp;cloudEntry, 1, CF_CREATE_FLAG_NONE, NULL));
      }
      catch (...)
      {
          // winrt::to_hresult() will eat the exception if it is a result of winrt::check_hresult,
          // otherwise the exception will get rethrown and this method will crash out as it should
          wprintf(L&quot;Failed to create placeholder for %s with %08x\n&quot;, fileName, static_cast&lt;HRESULT&gt;(winrt::to_hresult()));
          // Eating it here lets other files still get a chance. Not worth crashing the sample, but
          // certainly noteworthy for production code
          return static_cast&lt;HRESULT&gt;(winrt::to_hresult());
      }
  
      return S_OK;
  }
  
  Create(_T(&quot;C:\\SyncRootDT&quot;), _T(&quot;file1&quot;), CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC,
              10000000000, FILE_ATTRIBUTE_NORMAL, 532657415, 532657415, 532657415, 532657415));
  </code></pre>