Index: src/libchcore/TSubTaskCopyMove.cpp =================================================================== diff -u -N -r671f4b1792a20d98b186f4e0a9cc6a620dede019 -r6103ac74583f2136b821dc67515ed8469abd8155 --- src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 671f4b1792a20d98b186f4e0a9cc6a620dede019) +++ src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 6103ac74583f2136b821dc67515ed8469abd8155) @@ -36,25 +36,25 @@ #include #include "TFileInfo.h" #include "TFileInfoArray.h" -#include "TDataBuffer.h" #include "ErrorCodes.h" #include "TCoreException.h" #include "TPathContainer.h" #include "TScopedRunningTimeTracker.h" #include "TFeedbackHandlerWrapper.h" +#include "TOverlappedDataBufferQueue.h" +#include "TOverlappedDataBuffer.h" +#include "RoundingFunctions.h" +#include BEGIN_CHCORE_NAMESPACE -// assume max sectors of 4kB (for rounding) -#define MAXSECTORSIZE 4096 - struct CUSTOM_COPY_PARAMS { TFileInfoPtr spSrcFile; // CFileInfo - src file TSmartPath pathDstFile; // dest path with filename TBufferSizes tBufferSizes; - TDataBufferManager dbBuffer; // buffer handling + TOverlappedDataBufferQueue dbBuffer; // buffer handling bool bOnlyCreate; // flag from configuration - skips real copying - only create bool bProcessed; // has the element been processed ? (false if skipped) }; @@ -121,7 +121,7 @@ // remove changes in buffer sizes to avoid re-creation later rCfgTracker.RemoveModificationSet(TOptionsSet() % eTO_DefaultBufferSize % eTO_OneDiskBufferSize % eTO_TwoDisksBufferSize % eTO_CDBufferSize % eTO_LANBufferSize % eTO_UseOnlyDefaultBuffer); - AdjustBufferIfNeeded(ccp.dbBuffer, ccp.tBufferSizes); + AdjustBufferIfNeeded(ccp.dbBuffer, ccp.tBufferSizes, true); // log TString strFormat; @@ -269,7 +269,7 @@ TWorkerThreadController& rThreadController = GetContext().GetThreadController(); icpf::log_file& rLog = GetContext().GetLog(); const TConfig& rConfig = GetContext().GetConfig(); - + TLocalFilesystemFile fileSrc = TLocalFilesystem::CreateFileObject(); TLocalFilesystemFile fileDst = TLocalFilesystem::CreateFileObject(); @@ -291,121 +291,201 @@ return TSubTaskBase::eSubResult_Continue; // copying - std::list listDataBuffers; - std::list listEmptyBuffers; - - size_t stToRead = 0; - unsigned long ulRead = 0; - unsigned long ulWritten = 0; TBufferSizes::EBufferType eBufferIndex = TBufferSizes::eBuffer_Default; - bool bLastPart = false; - do - { - // kill flag checks - if(rThreadController.KillRequested()) - { - // log - strFormat = _T("Kill request while main copying file %srcpath -> %dstpath"); - strFormat.Replace(_T("%srcpath"), pData->spSrcFile->GetFullFilePath().ToString()); - strFormat.Replace(_T("%dstpath"), pData->pathDstFile.ToString()); - rLog.logi(strFormat.c_str()); - return TSubTaskBase::eSubResult_KillRequest; - } + // recreate buffer if needed + AdjustBufferIfNeeded(pData->dbBuffer, pData->tBufferSizes); + pData->dbBuffer.DataSourceChanged(); - // recreate buffer if needed - AdjustBufferIfNeeded(pData->dbBuffer, pData->tBufferSizes); + // establish count of data to read + eBufferIndex = GetBufferIndex(pData->tBufferSizes, pData->spSrcFile); + m_tSubTaskStats.SetCurrentBufferIndex(eBufferIndex); - // establish count of data to read - eBufferIndex = GetBufferIndex(pData->tBufferSizes, pData->spSrcFile); - m_tSubTaskStats.SetCurrentBufferIndex(eBufferIndex); + DWORD dwToRead = RoundUp(pData->tBufferSizes.GetSizeByType(eBufferIndex), TLocalFilesystemFile::MaxSectorSize); - stToRead = RoundUp((size_t)pData->tBufferSizes.GetSizeByType(eBufferIndex), pData->dbBuffer.GetSimpleBufferSize()); - size_t stBuffersToRead = stToRead / pData->dbBuffer.GetSimpleBufferSize(); + // read data from file to buffer + enum + { + eKillThread = 0, eWriteFinished, eWritePossible, eReadPossible, eHandleCount + }; + std::array arrHandles = { + rThreadController.GetKillThreadHandle(), + pData->dbBuffer.GetEventWriteFinishedHandle(), + pData->dbBuffer.GetEventWritePossibleHandle(), + pData->dbBuffer.GetEventReadPossibleHandle() + }; - // read data from file to buffer - for(size_t stIndex = 0; stIndex < stBuffersToRead; ++stIndex) + unsigned long long ullNextReadPos = 0; + bool bStopProcessing = false; + while(!bStopProcessing) + { + DWORD dwResult = WaitForMultipleObjectsEx(eHandleCount, arrHandles.data(), false, INFINITE, true); + switch(dwResult) { - // get new simple buffer - TSimpleDataBufferPtr spBuffer; - if(listEmptyBuffers.empty()) + case STATUS_USER_APC: + break; + + case WAIT_OBJECT_0 + eKillThread: { - spBuffer.reset(new TSimpleDataBuffer); - if(pData->dbBuffer.GetFreeBuffer(*spBuffer.get())) - listEmptyBuffers.push_back(spBuffer); - else - { - if(listDataBuffers.empty()) - THROW_CORE_EXCEPTION(eErr_InternalProblem); - break; - } + // log + strFormat = _T("Kill request while main copying file %srcpath -> %dstpath"); + strFormat.Replace(_T("%srcpath"), pData->spSrcFile->GetFullFilePath().ToString()); + strFormat.Replace(_T("%dstpath"), pData->pathDstFile.ToString()); + rLog.logi(strFormat.c_str()); + return TSubTaskBase::eSubResult_KillRequest; } - spBuffer = listEmptyBuffers.back(); - listEmptyBuffers.pop_back(); - - eResult = ReadFileFB(spFeedbackHandler, fileSrc, *spBuffer.get(), boost::numeric_cast(pData->dbBuffer.GetSimpleBufferSize()), ulRead, pData->spSrcFile->GetFullFilePath(), bSkip); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - else if(bSkip) + case WAIT_OBJECT_0 + eReadPossible: { - // new stats - m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + ATLTRACE(_T("Read possible\n")); + TOverlappedDataBuffer* pBuffer = pData->dbBuffer.GetEmptyBuffer(); + if(!pBuffer) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - pData->bProcessed = false; - return TSubTaskBase::eSubResult_Continue; + pBuffer->SetFilePosition(ullNextReadPos); + pBuffer->SetRequestedDataSize(dwToRead); + ullNextReadPos += dwToRead; + + eResult = ReadFileFB(spFeedbackHandler, fileSrc, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // new stats + m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + break; } + case WAIT_OBJECT_0 + eWritePossible: + { + ATLTRACE(_T("Write possible\n")); + TOverlappedDataBuffer* pBuffer = pData->dbBuffer.GetFullBuffer(); + if(!pBuffer) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - spBuffer->SetDataSize(ulRead); + // was there an error reported? + if(pBuffer->GetStatusCode() != ERROR_SUCCESS) + { + // read error encountered - handle it + eResult = HandleReadError(spFeedbackHandler, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); + if(eResult == TSubTaskBase::eSubResult_Retry) + { + // re-request read of the same data + eResult = ReadFileFB(spFeedbackHandler, fileSrc, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // new stats + m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - if(ulRead > 0) - listDataBuffers.push_back(spBuffer); - else - listEmptyBuffers.push_back(spBuffer); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + else if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // new stats + m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - bLastPart = (pData->dbBuffer.GetSimpleBufferSize() != ulRead); - if(bLastPart) - break; - } + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + else + { + eResult = WriteFileFB(spFeedbackHandler, fileDst, *pBuffer, pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // new stats + m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - while(!listDataBuffers.empty()) - { - TSimpleDataBufferPtr spBuffer = listDataBuffers.front(); - listDataBuffers.pop_front(); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } - eResult = WriteFileExFB(spFeedbackHandler, fileDst, *spBuffer.get(), boost::numeric_cast(spBuffer->GetDataSize()), ulWritten, pData->pathDstFile, bSkip, bNoBuffer); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - else if(bSkip) + break; + } + + case WAIT_OBJECT_0 + eWriteFinished: { - // new stats - m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + ATLTRACE(_T("Write finished\n")); + TOverlappedDataBuffer* pBuffer = pData->dbBuffer.GetFinishedBuffer(); + if(!pBuffer) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - pData->bProcessed = false; - return TSubTaskBase::eSubResult_Continue; - } + if(pBuffer->GetStatusCode() != ERROR_SUCCESS) + { + eResult = HandleWriteError(spFeedbackHandler, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); + if(eResult == TSubTaskBase::eSubResult_Retry) + { + eResult = WriteFileFB(spFeedbackHandler, fileDst, *pBuffer, pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // new stats + m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - listEmptyBuffers.push_back(spBuffer); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + else if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // new stats + m_tSubTaskStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(pData->spSrcFile->GetLength64() - m_tSubTaskStats.GetCurrentItemProcessedSize()); - unsigned long long ullCITotalSize = m_tSubTaskStats.GetCurrentItemTotalSize(); - unsigned long long ullCIProcessedSize = m_tSubTaskStats.GetCurrentItemProcessedSize(); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + else + { + unsigned long long ullCITotalSize = m_tSubTaskStats.GetCurrentItemTotalSize(); + unsigned long long ullCIProcessedSize = m_tSubTaskStats.GetCurrentItemProcessedSize(); - if(ullCIProcessedSize + ulWritten > ullCITotalSize) - { - // total size changed - pData->spSrcFile->SetLength64(ullCIProcessedSize + ulWritten); - m_tSubTaskStats.IncreaseCurrentItemTotalSize(ullCIProcessedSize + ulWritten - ullCITotalSize); - m_tSubTaskStats.IncreaseTotalSize(ullCIProcessedSize + ulWritten - ullCITotalSize); + unsigned long long ullWritten = pBuffer->GetBytesTransferred(); + if(ullCIProcessedSize + ullWritten > ullCITotalSize) + { + // total size changed + pData->spSrcFile->SetLength64(ullCIProcessedSize + ullWritten); + m_tSubTaskStats.IncreaseCurrentItemTotalSize(ullCIProcessedSize + ullWritten - ullCITotalSize); + m_tSubTaskStats.IncreaseTotalSize(ullCIProcessedSize + ullWritten - ullCITotalSize); + } + + // new stats + m_tSubTaskStats.IncreaseProcessedSize(ullWritten); + m_tSubTaskStats.IncreaseCurrentItemProcessedSize(ullWritten); + + // stop iterating through file + bStopProcessing = pBuffer->IsLastPart(); + pBuffer->RequeueAsEmpty(); + } + + break; } - // new stats - m_tSubTaskStats.IncreaseProcessedSize(ulWritten); - m_tSubTaskStats.IncreaseCurrentItemProcessedSize(ulWritten); + default: + THROW_CORE_EXCEPTION(eErr_UnhandledCase); } } - while(!bLastPart); // fix the stats for files shorter than expected unsigned long long ullCITotalSize = m_tSubTaskStats.GetCurrentItemTotalSize(); @@ -533,7 +613,7 @@ if(ullSeekTo != 0) // src and dst files exists, requested resume at the specified index { // try to move file pointers to the end - ULONGLONG ullMove = (bNoBuffer ? ROUNDDOWN(ullSeekTo, MAXSECTORSIZE) : ullSeekTo); + ULONGLONG ullMove = (bNoBuffer ? ROUNDDOWN(ullSeekTo, TLocalFilesystemFile::MaxSectorSize) : ullSeekTo); eResult = SetFilePointerFB(spFeedbackHandler, fileSrc, ullMove, pData->spSrcFile->GetFullFilePath(), bSkip); if(eResult != TSubTaskBase::eSubResult_Continue) @@ -600,13 +680,13 @@ return eResult; } -bool TSubTaskCopyMove::AdjustBufferIfNeeded(chcore::TDataBufferManager& rBuffer, TBufferSizes& rBufferSizes) +bool TSubTaskCopyMove::AdjustBufferIfNeeded(TOverlappedDataBufferQueue& rBuffer, TBufferSizes& rBufferSizes, bool bForce) { const TConfig& rConfig = GetContext().GetConfig(); TTaskConfigTracker& rCfgTracker = GetContext().GetCfgTracker(); icpf::log_file& rLog = GetContext().GetLog(); - if(!rBuffer.IsInitialized() || (rCfgTracker.IsModified() && rCfgTracker.IsModified(TOptionsSet() % eTO_DefaultBufferSize % eTO_OneDiskBufferSize % eTO_TwoDisksBufferSize % eTO_CDBufferSize % eTO_LANBufferSize % eTO_UseOnlyDefaultBuffer, true))) + if(bForce || (rCfgTracker.IsModified() && rCfgTracker.IsModified(TOptionsSet() % eTO_DefaultBufferSize % eTO_OneDiskBufferSize % eTO_TwoDisksBufferSize % eTO_CDBufferSize % eTO_LANBufferSize % eTO_UseOnlyDefaultBuffer, true))) { rBufferSizes.SetOnlyDefault(GetTaskPropValue(rConfig)); rBufferSizes.SetDefaultSize(GetTaskPropValue(rConfig)); @@ -627,28 +707,12 @@ rLog.logi(strFormat.c_str()); - if(!rBuffer.IsInitialized()) - { - size_t stMaxSize = rBufferSizes.GetMaxSize(); - size_t stPageSize = GetTaskPropValue(rConfig); - size_t stChunkSize = GetTaskPropValue(rConfig); + rBuffer.ReinitializeBuffers(2, rBufferSizes.GetMaxSize()); - chcore::TDataBufferManager::CheckBufferConfig(stMaxSize, stPageSize, stChunkSize); - - rBuffer.Initialize(stMaxSize, stPageSize, stChunkSize); - } - else - { - size_t stMaxSize = rBufferSizes.GetMaxSize(); - rBuffer.CheckResizeSize(stMaxSize); - - rBuffer.ChangeMaxMemorySize(stMaxSize); - } - - return true; + return true; // buffer adjusted } - else - return false; + + return false; // buffer did not need adjusting } TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenSourceFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& fileSrc, const TSmartPath& spPathToOpen, bool bNoBuffering) @@ -983,7 +1047,7 @@ return TSubTaskBase::eSubResult_Continue; } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::ReadFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, chcore::TSimpleDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const TSmartPath& pathFile, bool& bSkip) +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::ReadFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) { icpf::log_file& rLog = GetContext().GetLog(); @@ -993,18 +1057,15 @@ { bRetry = false; - if(!file.ReadFile(rBuffer, dwToRead, rdwBytesRead)) + if(!file.ReadFile(rBuffer)) { - // log - DWORD dwLastError = GetLastError(); - - TString strFormat = _T("Error %errno while trying to read %count bytes from source file %path (CustomCopyFileFB)"); - strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_t("%count"), boost::lexical_cast(dwToRead).c_str()); + TString strFormat = _T("Error %errno while requesting read of %count bytes from source file %path (CustomCopyFileFB)"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(GetLastError()).c_str()); + strFormat.Replace(_t("%count"), boost::lexical_cast(rBuffer.GetRequestedDataSize()).c_str()); strFormat.Replace(_t("%path"), pathFile.ToString()); rLog.loge(strFormat.c_str()); - EFeedbackResult frResult = spFeedbackHandler->FileError(pathFile.ToWString(), TString(), EFileError::eReadError, dwLastError); + EFeedbackResult frResult = spFeedbackHandler->FileError(pathFile.ToWString(), TString(), EFileError::eReadError, GetLastError()); switch(frResult) { case EFeedbackResult::eResult_Cancel: @@ -1032,25 +1093,66 @@ return TSubTaskBase::eSubResult_Continue; } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::WriteFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, chcore::TSimpleDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const TSmartPath& pathFile, bool& bSkip) +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::HandleReadError(const IFeedbackHandlerPtr& spFeedbackHandler, + TOverlappedDataBuffer& rBuffer, + const TSmartPath& pathFile, + bool& bSkip) { icpf::log_file& rLog = GetContext().GetLog(); + DWORD dwLastError = boost::numeric_cast(rBuffer.GetStatusCode()); bSkip = false; + // log + TString strFormat = _T("Error %errno while requesting read of %count bytes from source file %path (CustomCopyFileFB)"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%count"), boost::lexical_cast(rBuffer.GetRequestedDataSize()).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + rLog.loge(strFormat.c_str()); + + EFeedbackResult frResult = spFeedbackHandler->FileError(pathFile.ToWString(), TString(), EFileError::eReadError, dwLastError); + switch(frResult) + { + case EFeedbackResult::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case EFeedbackResult::eResult_Retry: + return TSubTaskBase::eSubResult_Retry; + + case EFeedbackResult::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case EFeedbackResult::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::WriteFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip) +{ + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + bool bRetry = false; do { bRetry = false; - if(!file.WriteFile(rBuffer, dwToWrite, rdwBytesWritten)) + if(!file.WriteFile(rBuffer)) { // log DWORD dwLastError = GetLastError(); + if (dwLastError == ERROR_IO_PENDING) + break; TString strFormat = _T("Error %errno while trying to write %count bytes to destination file %path (CustomCopyFileFB)"); strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_t("%count"), boost::lexical_cast(dwToWrite).c_str()); + strFormat.Replace(_t("%count"), boost::lexical_cast(rBuffer.GetBytesTransferred()).c_str()); strFormat.Replace(_t("%path"), pathFile.ToString()); rLog.loge(strFormat.c_str()); @@ -1082,69 +1184,43 @@ return TSubTaskBase::eSubResult_Continue; } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::WriteFileExFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, chcore::TSimpleDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const TSmartPath& pathFile, bool& bSkip, bool bNoBuffer) +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::HandleWriteError(const IFeedbackHandlerPtr& spFeedbackHandler, + TOverlappedDataBuffer& rBuffer, + const TSmartPath& pathFile, + bool& bSkip) { - TString strFormat; - TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; + icpf::log_file& rLog = GetContext().GetLog(); + DWORD dwLastError = boost::numeric_cast(rBuffer.GetStatusCode()); - rdwBytesWritten = 0; + bSkip = false; - // copying - unsigned long ulWritten = 0; - bool bNonAlignedSize = (dwToWrite % MAXSECTORSIZE) != 0; + // log + TString strFormat = _T("Error %errno while trying to write %count bytes to destination file %path (CustomCopyFileFB)"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(rBuffer.GetStatusCode()).c_str()); + strFormat.Replace(_t("%count"), boost::lexical_cast(rBuffer.GetBytesTransferred()).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + rLog.loge(strFormat.c_str()); - // handle not aligned part at the end of file when no buffering is enabled - if(bNoBuffer && bNonAlignedSize) + EFeedbackResult frResult = spFeedbackHandler->FileError(pathFile.ToWString(), TString(), EFileError::eWriteError, dwLastError); + switch(frResult) { - // count of data read from the file is less than requested - we're at the end of source file - // and this is the operation with system buffering turned off + case EFeedbackResult::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; - // write as much as possible to the destination file with no buffering - // NOTE: as an alternative, we could write more data to the destination file and then truncate the file - unsigned long ulDataToWrite = ROUNDDOWN(dwToWrite, MAXSECTORSIZE); - if(ulDataToWrite > 0) - { - eResult = WriteFileFB(spFeedbackHandler, file, rBuffer, ulDataToWrite, ulWritten, pathFile, bSkip); - if(eResult != TSubTaskBase::eSubResult_Continue || bSkip) - return eResult; + case EFeedbackResult::eResult_Retry: + return TSubTaskBase::eSubResult_Retry; - // calculate count of bytes left to be written - rdwBytesWritten = ulWritten; - dwToWrite -= ulWritten; + case EFeedbackResult::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; - // now remove part of data from buffer (ulWritten bytes) - rBuffer.CutDataFromBuffer(ulWritten); - } + case EFeedbackResult::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; - // close and re-open the destination file with buffering option for append - file.Close(); - - // are there any more data to be written? - if(dwToWrite != 0) - { - // re-open the destination file, this time with standard buffering to allow writing not aligned part of file data - eResult = OpenExistingDestinationFileFB(spFeedbackHandler, file, pathFile, false); - if(eResult != TSubTaskBase::eSubResult_Continue || !file.IsOpen()) - return eResult; - - // move file pointer to the end of destination file - eResult = SetFilePointerFB(spFeedbackHandler, file, m_tSubTaskStats.GetCurrentItemProcessedSize() + rdwBytesWritten, pathFile, bSkip); - if(eResult != TSubTaskBase::eSubResult_Continue || bSkip) - return eResult; - } + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); } - - // write - if(dwToWrite != 0) - { - eResult = WriteFileFB(spFeedbackHandler, file, rBuffer, dwToWrite, ulWritten, pathFile, bSkip); - if(eResult != TSubTaskBase::eSubResult_Continue || bSkip) - return eResult; - - rdwBytesWritten += ulWritten; - } - - return TSubTaskBase::eSubResult_Continue; } TSubTaskBase::ESubOperationResult TSubTaskCopyMove::CreateDirectoryFB(const IFeedbackHandlerPtr& spFeedbackHandler, const TSmartPath& pathDirectory)