Index: src/libchcore/TOverlappedReaderFB.cpp =================================================================== diff -u -ra1f5b3d99f2f175b102d81379698ea1f08e42cce -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TOverlappedReaderFB.cpp (.../TOverlappedReaderFB.cpp) (revision a1f5b3d99f2f175b102d81379698ea1f08e42cce) +++ src/libchcore/TOverlappedReaderFB.cpp (.../TOverlappedReaderFB.cpp) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -19,6 +19,7 @@ #include "stdafx.h" #include "TOverlappedReaderFB.h" #include "TCoreException.h" +#include "TFileInfo.h" namespace chcore { @@ -43,6 +44,29 @@ { } + TSubTaskBase::ESubOperationResult TOverlappedReaderFB::Start() + { + // update the source file size (it might differ from the time this file was originally scanned). + // NOTE: this kind of update could be also done when copying chunks of data beyond the original end-of-file, + // but it would require frequent total size updates and thus - serializations). + // NOTE2: the by-chunk corrections of stats are still applied when copying to ensure even further size + // matching; this update however still allows for better serialization management. + file_size_t fsOldSize = m_spSrcFileInfo->GetLength64(); + file_size_t fsNewSize = 0; + + TSubTaskBase::ESubOperationResult eResult = m_spSrcFile->GetFileSize(fsNewSize); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + if(fsNewSize != fsOldSize) + { + m_spStats->AdjustTotalSize(fsOldSize, fsNewSize); + m_spSrcFileInfo->SetLength64(fsNewSize); + } + + return eResult; + } + void TOverlappedReaderFB::SetReleaseMode() { m_spReader->ReleaseBuffers(); Index: src/libchcore/TOverlappedReaderFB.h =================================================================== diff -u -rc0d9a798f9fbbeda239b84721ed864f9727e1ddc -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TOverlappedReaderFB.h (.../TOverlappedReaderFB.h) (revision c0d9a798f9fbbeda239b84721ed864f9727e1ddc) +++ src/libchcore/TOverlappedReaderFB.h (.../TOverlappedReaderFB.h) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -35,6 +35,8 @@ unsigned long long ullFilePos, DWORD dwChunkSize); ~TOverlappedReaderFB(); + TSubTaskBase::ESubOperationResult Start(); + TOverlappedReaderPtr GetReader() const { return m_spReader; } void SetReleaseMode(); Index: src/libchcore/TOverlappedReaderWriterFB.cpp =================================================================== diff -u -ra1f5b3d99f2f175b102d81379698ea1f08e42cce -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TOverlappedReaderWriterFB.cpp (.../TOverlappedReaderWriterFB.cpp) (revision a1f5b3d99f2f175b102d81379698ea1f08e42cce) +++ src/libchcore/TOverlappedReaderWriterFB.cpp (.../TOverlappedReaderWriterFB.cpp) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -104,8 +104,16 @@ return eResult; } - TSubTaskBase::ESubOperationResult TOverlappedReaderWriterFB::Start(HANDLE hKill) + TSubTaskBase::ESubOperationResult TOverlappedReaderWriterFB::Start(HANDLE hKill, bool bCreateOnly) { + TSubTaskBase::ESubOperationResult eResult = m_spReader->Start(); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + eResult = m_spWriter->Start(bCreateOnly); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + // read data from file to buffer // NOTE: order is critical here: // - write finished is first, so that all the data that were already queued to be written, will be written and accounted for (in stats) @@ -127,7 +135,6 @@ m_spReader->GetReader()->GetEventReadPossibleHandle() }; - TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; bool bStopProcessing = false; while(!bStopProcessing && eResult == TSubTaskBase::eSubResult_Continue) { Index: src/libchcore/TOverlappedReaderWriterFB.h =================================================================== diff -u -rc0d9a798f9fbbeda239b84721ed864f9727e1ddc -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TOverlappedReaderWriterFB.h (.../TOverlappedReaderWriterFB.h) (revision c0d9a798f9fbbeda239b84721ed864f9727e1ddc) +++ src/libchcore/TOverlappedReaderWriterFB.h (.../TOverlappedReaderWriterFB.h) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -40,7 +40,7 @@ TOverlappedReaderWriterFB& operator=(const TOverlappedReaderWriterFB&) = delete; - TSubTaskBase::ESubOperationResult Start(HANDLE hKill); + TSubTaskBase::ESubOperationResult Start(HANDLE hKill, bool bCreateOnly); // reader/writer TOverlappedReaderFBPtr GetReader() const { return m_spReader; } Index: src/libchcore/TOverlappedWriterFB.cpp =================================================================== diff -u -ra1f5b3d99f2f175b102d81379698ea1f08e42cce -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TOverlappedWriterFB.cpp (.../TOverlappedWriterFB.cpp) (revision a1f5b3d99f2f175b102d81379698ea1f08e42cce) +++ src/libchcore/TOverlappedWriterFB.cpp (.../TOverlappedWriterFB.cpp) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -199,4 +199,87 @@ return eResult; } + + TSubTaskBase::ESubOperationResult TOverlappedWriterFB::Start(bool bOnlyCreate) + { + // open destination file, handle the failures and possibly existence of the destination file + unsigned long long ullProcessedSize = m_spStats->GetCurrentItemProcessedSize(); + unsigned long long ullSeekTo = ullProcessedSize; + + bool bDstFileFreshlyCreated = false; + TSubTaskBase::ESubOperationResult eResult = m_spDstFile->IsFreshlyCreated(bDstFileFreshlyCreated); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + file_size_t fsDstFileSize = 0; + eResult = m_spDstFile->GetFileSize(fsDstFileSize); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + // try to resume if possible + bool bCanSilentResume = false; + if(m_spStats->CanCurrentItemSilentResume()) + { + if(fsDstFileSize == ullProcessedSize && fsDstFileSize <= m_spSrcFileInfo->GetLength64()) + { + ullSeekTo = fsDstFileSize; + bCanSilentResume = true; + } + } + + if(!bCanSilentResume && !bDstFileFreshlyCreated && fsDstFileSize > 0) + { + bool bShouldAppend = false; + eResult = m_spDstFile->HandleFileAlreadyExistsFB(m_spSrcFileInfo, bShouldAppend); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + if(bShouldAppend) + ullSeekTo = std::min(fsDstFileSize, m_spSrcFileInfo->GetLength64()); + else + ullSeekTo = 0; + } + + if(bOnlyCreate) + { + // we don't copy contents, but need to increase processed size + m_spStats->AdjustProcessedSize(m_spStats->GetCurrentItemProcessedSize(), m_spSrcFileInfo->GetLength64()); + + return TSubTaskBase::eSubResult_Continue; + } + + // ullSeekTo contains the seek position in destination file; in case the destination is already + // larger than source file all we can do is to perform truncation of destination file to the size of + // source file. + // NOTE: the truncation that will be the result of the following assignment might cause the end of destination file + // to be overwritten by the end of source file. + ullSeekTo = std::min(ullSeekTo, m_spSrcFileInfo->GetLength64()); + + // seek to the position where copying will start + file_size_t fsMoveTo = m_spDstFile->GetSeekPositionForResume(ullSeekTo); + + // sanity check + if(bDstFileFreshlyCreated && ullSeekTo != 0) + throw TCoreException(eErr_InternalProblem, L"Destination file was freshly created, but seek position is not 0", LOCATION); + if(fsMoveTo > ullSeekTo) + throw TCoreException(eErr_InternalProblem, L"File position to move to is placed after the end of file", LOCATION); + + // adjust the stats for the difference between what was already processed and what will now be considered processed + m_spStats->AdjustProcessedSize(ullProcessedSize, fsMoveTo); + + // if the destination file already exists - truncate it to the current file position + if(!bDstFileFreshlyCreated) + { + // if destination file was opened (as opposed to newly created) + eResult = m_spDstFile->TruncateFileFB(fsMoveTo); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + } + + // at this point user already decided that he want to write data into destination file; + // so if we're to resume copying after this point, we don't have to ask user for overwriting existing file + m_spStats->SetCurrentItemSilentResume(true); + + return eResult; + } } Index: src/libchcore/TOverlappedWriterFB.h =================================================================== diff -u -ra1f5b3d99f2f175b102d81379698ea1f08e42cce -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TOverlappedWriterFB.h (.../TOverlappedWriterFB.h) (revision a1f5b3d99f2f175b102d81379698ea1f08e42cce) +++ src/libchcore/TOverlappedWriterFB.h (.../TOverlappedWriterFB.h) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -33,6 +33,8 @@ unsigned long long ullFilePos, const TBufferListPtr& spEmptyBuffers); ~TOverlappedWriterFB(); + TSubTaskBase::ESubOperationResult Start(bool bOnlyCreate); + TOverlappedWriterPtr GetWriter() const { return m_spWriter; } void SetReleaseMode() { m_bReleaseMode = true; } Index: src/libchcore/TSubTaskCopyMove.cpp =================================================================== diff -u -ra1f5b3d99f2f175b102d81379698ea1f08e42cce -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision a1f5b3d99f2f175b102d81379698ea1f08e42cce) +++ src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -358,15 +358,9 @@ TFilesystemFileFeedbackWrapperPtr spSrcFileWrapper(std::make_shared(fileSrc, spFeedbackHandler, GetContext().GetLogFileData(), rThreadController, spFilesystem)); TFilesystemFileFeedbackWrapperPtr spDstFileWrapper(std::make_shared(fileDst, spFeedbackHandler, GetContext().GetLogFileData(), rThreadController, spFilesystem)); - TSubTaskBase::ESubOperationResult eResult = OpenSrcAndDstFilesFB(*spSrcFileWrapper, *spDstFileWrapper, pData); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - // recreate buffer if needed AdjustBufferIfNeeded(pData->spMemoryPool, pData->tBufferSizes); - //ATLTRACE(_T("CustomCopyFile: %s\n"), pData->spSrcFile->GetFullFilePath().ToString()); - // establish count of data to read TBufferSizes::EBufferType eBufferIndex = GetBufferIndex(pData->tBufferSizes, pData->spSrcFile); m_spSubTaskStats->SetCurrentBufferIndex(eBufferIndex); @@ -381,7 +375,7 @@ TOverlappedReaderWriterFB tReaderWriter(spSrcFileWrapper, pData->spSrcFile, spDstFileWrapper, m_spSubTaskStats, m_spLog->GetLogFileData(), pData->spMemoryPool, ullNextReadPos, dwCurrentBufferSize); - eResult = tReaderWriter.Start(rThreadController.GetKillThreadHandle()); + ESubOperationResult eResult = tReaderWriter.Start(rThreadController.GetKillThreadHandle(), pData->bOnlyCreate); return eResult; } @@ -391,110 +385,6 @@ m_spSubTaskStats->AdjustProcessedSize(m_spSubTaskStats->GetCurrentItemProcessedSize(), spSrcFileInfo->GetLength64()); } - TSubTaskCopyMove::ESubOperationResult TSubTaskCopyMove::OpenSrcAndDstFilesFB(TFilesystemFileFeedbackWrapper& rSrcFile, TFilesystemFileFeedbackWrapper& rDstFile, - CUSTOM_COPY_PARAMS* pData) - { - IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem(); - - // update the source file size (it might differ from the time this file was originally scanned). - // NOTE: this kind of update could be also done when copying chunks of data beyond the original end-of-file, - // but it would require frequent total size updates and thus - serializations). - // NOTE2: the by-chunk corrections of stats are still applied when copying to ensure even further size - // matching; this update however still allows for better serialization management. - file_size_t fsOldSize = pData->spSrcFile->GetLength64(); - file_size_t fsNewSize = 0; - - ESubOperationResult eResult = rSrcFile.GetFileSize(fsNewSize); - if(eResult != eSubResult_Continue) - return eResult; - - if(fsNewSize != fsOldSize) - { - m_spSubTaskStats->AdjustTotalSize(fsOldSize, fsNewSize); - pData->spSrcFile->SetLength64(fsNewSize); - } - - // open destination file, handle the failures and possibly existence of the destination file - unsigned long long ullProcessedSize = m_spSubTaskStats->GetCurrentItemProcessedSize(); - unsigned long long ullSeekTo = ullProcessedSize; - - bool bDstFileFreshlyCreated = false; - eResult = rDstFile.IsFreshlyCreated(bDstFileFreshlyCreated); - if(eResult != eSubResult_Continue) - return eResult; - - file_size_t fsDstFileSize = 0; - eResult = rDstFile.GetFileSize(fsDstFileSize); - if(eResult != eSubResult_Continue) - return eResult; - - // try to resume if possible - bool bCanSilentResume = false; - if (m_spSubTaskStats->CanCurrentItemSilentResume()) - { - if(fsDstFileSize == ullProcessedSize && fsDstFileSize <= fsNewSize) - { - ullSeekTo = fsDstFileSize; - bCanSilentResume = true; - } - } - - if(!bCanSilentResume && !bDstFileFreshlyCreated && fsDstFileSize > 0) - { - bool bShouldAppend = false; - eResult = rDstFile.HandleFileAlreadyExistsFB(pData->spSrcFile, bShouldAppend); - if(eResult != eSubResult_Continue) - return eResult; - - if(bShouldAppend) - ullSeekTo = std::min(fsDstFileSize, fsNewSize); - else - ullSeekTo = 0; - } - - if(pData->bOnlyCreate) - { - // we don't copy contents, but need to increase processed size - AdjustProcessedSizeForSkip(pData->spSrcFile); - - return eSubResult_Continue; - } - - // ullSeekTo contains the seek position in destination file; in case the destination is already - // larger than source file all we can do is to perform truncation of destination file to the size of - // source file. - // NOTE: the truncation that will be the result of the following assignment might cause the end of destination file - // to be overwritten by the end of source file. - ullSeekTo = std::min(ullSeekTo, fsNewSize); - - // seek to the position where copying will start - file_size_t fsMoveTo = rDstFile.GetSeekPositionForResume(ullSeekTo); - - // sanity check - if (bDstFileFreshlyCreated && ullSeekTo != 0) - throw TCoreException(eErr_InternalProblem, L"Destination file was freshly created, but seek position is not 0", LOCATION); - if(fsMoveTo > ullSeekTo) - throw TCoreException(eErr_InternalProblem, L"File position to move to is placed after the end of file", LOCATION); - - // adjust the stats for the difference between what was already processed and what will now be considered processed - m_spSubTaskStats->AdjustProcessedSize(ullProcessedSize, fsMoveTo); - - // if the destination file already exists - truncate it to the current file position - if(!bDstFileFreshlyCreated) - { - // if destination file was opened (as opposed to newly created) - eResult = rDstFile.TruncateFileFB(fsMoveTo); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - } - - // at this point user already decided that he want to write data into destination file; - // so if we're to resume copying after this point, we don't have to ask user for overwriting existing file - m_spSubTaskStats->SetCurrentItemSilentResume(true); - - return eResult; - } - bool TSubTaskCopyMove::AdjustBufferIfNeeded(const TOverlappedMemoryPoolPtr& spBuffer, TBufferSizes& rBufferSizes, bool bForce) { const TConfig& rConfig = GetContext().GetConfig(); Index: src/libchcore/TSubTaskCopyMove.h =================================================================== diff -u -rc0d9a798f9fbbeda239b84721ed864f9727e1ddc -r8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e --- src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision c0d9a798f9fbbeda239b84721ed864f9727e1ddc) +++ src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 8aa9ecb7ccb06d721b9717a4bb664651b0b8b10e) @@ -26,7 +26,6 @@ #include "libchcore.h" #include "TSubTaskBase.h" #include "TBufferSizes.h" -#include "IFilesystemFile.h" #include "../liblogger/TLogger.h" #include "TOverlappedMemoryPool.h" @@ -64,9 +63,6 @@ ESubOperationResult CustomCopyFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, CUSTOM_COPY_PARAMS* pData); - ESubOperationResult OpenSrcAndDstFilesFB(TFilesystemFileFeedbackWrapper& rSrcFile, TFilesystemFileFeedbackWrapper& rDstFile, - CUSTOM_COPY_PARAMS* pData); - void AdjustProcessedSizeForSkip(const TFileInfoPtr& spSrcFileInfo); private: