Index: src/libchcore/IFeedbackHandler.h =================================================================== diff -u -r671f4b1792a20d98b186f4e0a9cc6a620dede019 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/IFeedbackHandler.h (.../IFeedbackHandler.h) (revision 671f4b1792a20d98b186f4e0a9cc6a620dede019) +++ src/libchcore/IFeedbackHandler.h (.../IFeedbackHandler.h) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -35,6 +35,7 @@ eResizeError, ///< Problem occurred when tried to change size of the fs object eReadError, ///< Problem occurred when tried to read data from file eWriteError, ///< Problem occurred when tried to write data to a file + eFinalizeError, ///< Problem occurred when tried to finalize file eFastMoveError, ///< Problem occurred when tried to perform fast move operation (that does not involve copying contents) eCreateError ///< Problem occurred when tried to create the fs object }; Index: src/libchcore/TLocalFilesystem.cpp =================================================================== diff -u -rea7d62521e78371cff90579749d136cb928c9e88 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/TLocalFilesystem.cpp (.../TLocalFilesystem.cpp) (revision ea7d62521e78371cff90579749d136cb928c9e88) +++ src/libchcore/TLocalFilesystem.cpp (.../TLocalFilesystem.cpp) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -390,7 +390,7 @@ DWORD TLocalFilesystemFile::GetFlagsAndAttributes(bool bNoBuffering) const { - return FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0); + return FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING /*| FILE_FLAG_WRITE_THROUGH*/ : 0); } bool TLocalFilesystemFile::OpenExistingForReading(const TSmartPath& pathFile, bool bNoBuffering) @@ -469,7 +469,8 @@ case ERROR_HANDLE_EOF: { rBuffer.SetBytesTransferred(0); - rBuffer.SetStatusCode(ERROR_SUCCESS); + rBuffer.SetStatusCode(0); + rBuffer.SetErrorCode(ERROR_SUCCESS); rBuffer.SetLastPart(true); rBuffer.RequeueAsFull(); // basically the same as OverlappedReadCompleted @@ -489,30 +490,45 @@ THROW_CORE_EXCEPTION(eErr_InternalProblem); DWORD dwToWrite = boost::numeric_cast(rBuffer.GetBytesTransferred()); - unsigned long long ullNewFileSize = 0; if (m_bNoBuffering && rBuffer.IsLastPart()) - { dwToWrite = RoundUp(dwToWrite, MaxSectorSize); - if(dwToWrite != boost::numeric_cast(rBuffer.GetBytesTransferred())) - ullNewFileSize = rBuffer.GetFilePosition() + dwToWrite; // new size - } if (!::WriteFileEx(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rBuffer, OverlappedWriteCompleted)) + { + if (GetLastError() == ERROR_IO_PENDING) + return true; return false; + } - if(ullNewFileSize != 0) + return true; +} + +bool TLocalFilesystemFile::FinalizeFile(TOverlappedDataBuffer& rBuffer) +{ + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + + if (m_bNoBuffering && rBuffer.IsLastPart()) { - if(!OpenExistingForWriting(m_pathFile, false)) - return false; + DWORD dwToWrite = boost::numeric_cast(rBuffer.GetBytesTransferred()); + DWORD dwReallyWritten = RoundUp(dwToWrite, MaxSectorSize); - //seek - if(!SetFilePointer(ullNewFileSize, FILE_BEGIN)) - return false; + if (dwToWrite != dwReallyWritten) + { + unsigned long long ullNewFileSize = rBuffer.GetFilePosition() + dwToWrite; // new size - //set eof - if(!SetEndOfFile()) - return false; + if (!OpenExistingForWriting(m_pathFile, false)) + return false; + + //seek + if (!SetFilePointer(ullNewFileSize, FILE_BEGIN)) + return false; + + //set eof + if (!SetEndOfFile()) + return false; + } } return true; Index: src/libchcore/TLocalFilesystem.h =================================================================== diff -u -rea7d62521e78371cff90579749d136cb928c9e88 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/TLocalFilesystem.h (.../TLocalFilesystem.h) (revision ea7d62521e78371cff90579749d136cb928c9e88) +++ src/libchcore/TLocalFilesystem.h (.../TLocalFilesystem.h) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -123,6 +123,7 @@ bool ReadFile(TOverlappedDataBuffer& rBuffer); bool WriteFile(TOverlappedDataBuffer& rBuffer); + bool FinalizeFile(TOverlappedDataBuffer& rBuffer); bool IsOpen() const { return m_hFile != INVALID_HANDLE_VALUE; } unsigned long long GetFileSize() const; Index: src/libchcore/TOverlappedDataBuffer.cpp =================================================================== diff -u -r11b0a299be97bc3afaa633d6522c17b214ba3b79 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/TOverlappedDataBuffer.cpp (.../TOverlappedDataBuffer.cpp) (revision 11b0a299be97bc3afaa633d6522c17b214ba3b79) +++ src/libchcore/TOverlappedDataBuffer.cpp (.../TOverlappedDataBuffer.cpp) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -27,24 +27,38 @@ #include "ErrorCodes.h" #include "IOverlappedDataBufferQueue.h" #include "RoundingFunctions.h" +#include +#define STATUS_END_OF_FILE 0xc0000011 + BEGIN_CHCORE_NAMESPACE /////////////////////////////////////////////////////////////////////////////////// // class TOverlappedDataBuffer VOID CALLBACK OverlappedReadCompleted(DWORD dwErrorCode, DWORD /*dwNumberOfBytesTransfered*/, LPOVERLAPPED lpOverlapped) { TOverlappedDataBuffer* pBuffer = (TOverlappedDataBuffer*) lpOverlapped; + bool bEof = (dwErrorCode == ERROR_HANDLE_EOF || + pBuffer->GetStatusCode() == STATUS_END_OF_FILE || (dwErrorCode == ERROR_SUCCESS && pBuffer->GetBytesTransferred() != pBuffer->GetRequestedDataSize())); + if (pBuffer->GetStatusCode() == STATUS_END_OF_FILE) + pBuffer->SetStatusCode(0); + pBuffer->SetErrorCode(dwErrorCode == ERROR_HANDLE_EOF ? ERROR_SUCCESS : dwErrorCode); + + if (dwErrorCode != ERROR_SUCCESS) + ATLTRACE(_T("OverlappedReadCompleted error: %lu, status code: %I64u\n"), dwErrorCode, pBuffer->GetStatusCode()); + pBuffer->SetLastPart(bEof); pBuffer->RequeueAsFull(); } -VOID CALLBACK OverlappedWriteCompleted(DWORD /*dwErrorCode*/, DWORD /*dwNumberOfBytesTransfered*/, LPOVERLAPPED lpOverlapped) +VOID CALLBACK OverlappedWriteCompleted(DWORD dwErrorCode, DWORD /*dwNumberOfBytesTransfered*/, LPOVERLAPPED lpOverlapped) { TOverlappedDataBuffer* pBuffer = (TOverlappedDataBuffer*) lpOverlapped; + if (dwErrorCode != ERROR_SUCCESS) + ATLTRACE(_T("OverlappedWriteCompleted error: %lu, status code: %I64u\n"), dwErrorCode, pBuffer->GetStatusCode()); pBuffer->RequeueAsFinished(); } Index: src/libchcore/TOverlappedDataBuffer.h =================================================================== diff -u -r6103ac74583f2136b821dc67515ed8469abd8155 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/TOverlappedDataBuffer.h (.../TOverlappedDataBuffer.h) (revision 6103ac74583f2136b821dc67515ed8469abd8155) +++ src/libchcore/TOverlappedDataBuffer.h (.../TOverlappedDataBuffer.h) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -66,6 +66,9 @@ ULONG_PTR GetStatusCode() const { return Internal; } void SetStatusCode(ULONG_PTR ulStatusCode) { Internal = ulStatusCode; } + DWORD GetErrorCode() const { return m_dwErrorCode; } + void SetErrorCode(DWORD dwErrorCode) { m_dwErrorCode = dwErrorCode; } + void SetBytesTransferred(ULONG_PTR ulBytes) { InternalHigh = ulBytes; } ULONG_PTR GetBytesTransferred() const { return InternalHigh; } @@ -82,8 +85,11 @@ LPVOID m_pBuffer; // pointer to the allocated buffer size_t m_stBufferSize; // total buffer size DWORD m_dwRequestedDataSize; // part of the buffer that is to be used for data transfer (<= m_stBufferSize) + + DWORD m_dwErrorCode; // win32 error code bool m_bLastPart; // marks the last part of the file unsigned long long m_ullBufferOrder; // marks the order of this buffer + IOverlappedDataBufferQueue* m_pQueue; // pointer to the queue where this object resides }; Index: src/libchcore/TSubTaskCopyMove.cpp =================================================================== diff -u -r73d92717b7ba780c7aea1489a5eaa87404afa408 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 73d92717b7ba780c7aea1489a5eaa87404afa408) +++ src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -363,7 +363,7 @@ THROW_CORE_EXCEPTION(eErr_InternalProblem); // was there an error reported? - if(pBuffer->GetStatusCode() != ERROR_SUCCESS) + if(pBuffer->GetErrorCode() != ERROR_SUCCESS) { // read error encountered - handle it eResult = HandleReadError(spFeedbackHandler, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); @@ -421,7 +421,7 @@ if (!pBuffer) THROW_CORE_EXCEPTION(eErr_InternalProblem); - if(pBuffer->GetStatusCode() != ERROR_SUCCESS) + if(pBuffer->GetErrorCode() != ERROR_SUCCESS) { eResult = HandleWriteError(spFeedbackHandler, *pBuffer, pData->spSrcFile->GetFullFilePath(), bSkip); if(eResult == TSubTaskBase::eSubResult_Retry) @@ -453,6 +453,19 @@ } else { + eResult = FinalizeFileFB(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()); + + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + unsigned long long ullCITotalSize = m_tSubTaskStats.GetCurrentItemTotalSize(); unsigned long long ullCIProcessedSize = m_tSubTaskStats.GetCurrentItemProcessedSize(); @@ -1094,7 +1107,7 @@ bool& bSkip) { icpf::log_file& rLog = GetContext().GetLog(); - DWORD dwLastError = boost::numeric_cast(rBuffer.GetStatusCode()); + DWORD dwLastError = rBuffer.GetErrorCode(); bSkip = false; @@ -1142,8 +1155,6 @@ { // 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()); @@ -1185,13 +1196,13 @@ bool& bSkip) { icpf::log_file& rLog = GetContext().GetLog(); - DWORD dwLastError = boost::numeric_cast(rBuffer.GetStatusCode()); + DWORD dwLastError = rBuffer.GetErrorCode(); bSkip = false; // 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("%errno"), boost::lexical_cast(rBuffer.GetErrorCode()).c_str()); strFormat.Replace(_t("%count"), boost::lexical_cast(rBuffer.GetBytesTransferred()).c_str()); strFormat.Replace(_t("%path"), pathFile.ToString()); rLog.loge(strFormat.c_str()); @@ -1218,6 +1229,55 @@ } } +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::FinalizeFileFB(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.FinalizeFile(rBuffer)) + { + // log + DWORD dwLastError = GetLastError(); + + TString strFormat = _T("Error %errno while trying to finalize file %path (CustomCopyFileFB)"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + rLog.loge(strFormat.c_str()); + + EFeedbackResult frResult = spFeedbackHandler->FileError(pathFile.ToWString(), TString(), EFileError::eFinalizeError, dwLastError); + switch (frResult) + { + case EFeedbackResult::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case EFeedbackResult::eResult_Retry: + bRetry = true; + break; + + 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); + } + } + } + while (bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + TSubTaskBase::ESubOperationResult TSubTaskCopyMove::CreateDirectoryFB(const IFeedbackHandlerPtr& spFeedbackHandler, const TSmartPath& pathDirectory) { icpf::log_file& rLog = GetContext().GetLog(); Index: src/libchcore/TSubTaskCopyMove.h =================================================================== diff -u -r6103ac74583f2136b821dc67515ed8469abd8155 -r3c343f2e7aa0d489706136e78f2f56cdd5d417a9 --- src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 6103ac74583f2136b821dc67515ed8469abd8155) +++ src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 3c343f2e7aa0d489706136e78f2f56cdd5d417a9) @@ -77,6 +77,9 @@ ESubOperationResult WriteFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); ESubOperationResult HandleWriteError(const IFeedbackHandlerPtr& spFeedbackHandler, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); + + ESubOperationResult FinalizeFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, TLocalFilesystemFile& file, TOverlappedDataBuffer& rBuffer, const TSmartPath& pathFile, bool& bSkip); + ESubOperationResult CreateDirectoryFB(const IFeedbackHandlerPtr& spFeedbackHandler, const TSmartPath& pathDirectory); ESubOperationResult CheckForFreeSpaceFB(const IFeedbackHandlerPtr& spFeedbackHandler);