Index: src/ch/TBasicProgressInfo.cpp =================================================================== diff -u --- src/ch/TBasicProgressInfo.cpp (revision 0) +++ src/ch/TBasicProgressInfo.cpp (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,92 @@ +// ============================================================================ +// Copyright (C) 2001-2011 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TBasicProgressInfo.cpp +/// @date 2011/03/28 +/// @brief Contains implementation of class recording progress info. +// ============================================================================ +#include "stdafx.h" +#include "TBasicProgressInfo.h" + + +TTaskBasicProgressInfo::TTaskBasicProgressInfo() : +m_stCurrentIndex(0), +m_ullCurrentFileProcessedSize(0), +m_stSubOperationIndex(0) +{ +} + +TTaskBasicProgressInfo::~TTaskBasicProgressInfo() +{ +} + +void TTaskBasicProgressInfo::SetCurrentIndex(size_t stIndex) +{ + boost::unique_lock lock(m_lock); + m_stCurrentIndex = stIndex; + m_ullCurrentFileProcessedSize = 0; +} + +void TTaskBasicProgressInfo::IncreaseCurrentIndex() +{ + boost::unique_lock lock(m_lock); + ++m_stCurrentIndex; + m_ullCurrentFileProcessedSize = 0; +} + +size_t TTaskBasicProgressInfo::GetCurrentIndex() const +{ + boost::shared_lock lock(m_lock); + return m_stCurrentIndex; +} + +void TTaskBasicProgressInfo::SetCurrentFileProcessedSize(unsigned long long ullSize) +{ + boost::unique_lock lock(m_lock); + m_ullCurrentFileProcessedSize = ullSize; +} + +unsigned long long TTaskBasicProgressInfo::GetCurrentFileProcessedSize() const +{ + boost::shared_lock lock(m_lock); + return m_ullCurrentFileProcessedSize; +} + +void TTaskBasicProgressInfo::IncreaseCurrentFileProcessedSize(unsigned long long ullSizeToAdd) +{ + boost::unique_lock lock(m_lock); + m_ullCurrentFileProcessedSize += ullSizeToAdd; +} + +void TTaskBasicProgressInfo::SetSubOperationIndex(size_t stSubOperationIndex) +{ + boost::unique_lock lock(m_lock); + m_stSubOperationIndex = stSubOperationIndex; +} + +size_t TTaskBasicProgressInfo::GetSubOperationIndex() const +{ + boost::shared_lock lock(m_lock); + return m_stSubOperationIndex; +} + +void TTaskBasicProgressInfo::IncreaseSubOperationIndex() +{ + boost::unique_lock lock(m_lock); + ++m_stSubOperationIndex; +} Index: src/ch/TBasicProgressInfo.h =================================================================== diff -u --- src/ch/TBasicProgressInfo.h (revision 0) +++ src/ch/TBasicProgressInfo.h (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,93 @@ +// ============================================================================ +// Copyright (C) 2001-2011 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TBasicProgressInfo.h +/// @date 2011/03/28 +/// @brief Contains class with progress tracking. +// ============================================================================ +#ifndef __TBASICPROGRESSINFO_H__ +#define __TBASICPROGRESSINFO_H__ + + +/////////////////////////////////////////////////////////////////////////// +// TTaskBasicProgressInfo + +class TTaskBasicProgressInfo +{ +public: + TTaskBasicProgressInfo(); + ~TTaskBasicProgressInfo(); + + void SetCurrentIndex(size_t stIndex); // might be unneeded when serialization is implemented + void IncreaseCurrentIndex(); + size_t GetCurrentIndex() const; + + void SetCurrentFileProcessedSize(unsigned long long ullSize); + unsigned long long GetCurrentFileProcessedSize() const; + void IncreaseCurrentFileProcessedSize(unsigned long long ullSizeToAdd); + + void SetSubOperationIndex(size_t stSubOperationIndex); + size_t GetSubOperationIndex() const; + void IncreaseSubOperationIndex(); + + template + void load(Archive& ar, unsigned int /*uiVersion*/) + { + size_t stCurrentIndex = 0; + ar >> stCurrentIndex; + + unsigned long long ullCurrentFileProcessedSize = 0; + ar >> ullCurrentFileProcessedSize; + + size_t stSubOperationIndex = 0; + ar >> stSubOperationIndex; + + boost::unique_lock lock(m_lock); + + m_stCurrentIndex = stCurrentIndex; + m_ullCurrentFileProcessedSize = ullCurrentFileProcessedSize; + m_stSubOperationIndex = stSubOperationIndex; + } + + template + void save(Archive& ar, unsigned int /*uiVersion*/) const + { + m_lock.lock_shared(); + + size_t stCurrentIndex = m_stCurrentIndex; + unsigned long long ullCurrentFileProcessedSize = m_ullCurrentFileProcessedSize; + size_t stSubOperationIndex = m_stSubOperationIndex; + + m_lock.unlock_shared(); + + ar << stCurrentIndex; + ar << ullCurrentFileProcessedSize; + ar << stSubOperationIndex; + } + + BOOST_SERIALIZATION_SPLIT_MEMBER(); + +private: + volatile size_t m_stSubOperationIndex; // index of sub-operation from TOperationDescription + volatile size_t m_stCurrentIndex; // index to the m_files array stating currently processed item + volatile unsigned long long m_ullCurrentFileProcessedSize; // count of bytes processed for current file + + mutable boost::shared_mutex m_lock; +}; + +#endif Index: src/ch/TLocalFilesystem.cpp =================================================================== diff -u --- src/ch/TLocalFilesystem.cpp (revision 0) +++ src/ch/TLocalFilesystem.cpp (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,102 @@ +// ============================================================================ +// Copyright (C) 2001-2010 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TLocalFilesystem.cpp +/// @date 2011/03/24 +/// @brief +// ============================================================================ +#include "stdafx.h" +#include "TLocalFilesystem.h" +#include "TAutoHandles.h" + +void TLocalFilesystem::GetDriveData(const chcore::TSmartPath& spPath, int* piDrvNum, UINT* puiDrvType) +{ + TCHAR drv[_MAX_DRIVE + 1]; + + _tsplitpath(spPath.ToString(), drv, NULL, NULL, NULL); + if(lstrlen(drv) != 0) + { + // add '\\' + lstrcat(drv, _T("\\")); + _tcsupr(drv); + + // disk number + if(piDrvNum) + *piDrvNum=drv[0]-_T('A'); + + // disk type + if(puiDrvType) + { + *puiDrvType=GetDriveType(drv); + if(*puiDrvType == DRIVE_NO_ROOT_DIR) + *puiDrvType=DRIVE_UNKNOWN; + } + } + else + { + // there's no disk in a path + if(piDrvNum) + *piDrvNum=-1; + + if(puiDrvType) + { + // check for unc path + if(_tcsncmp(spPath.ToString(), _T("\\\\"), 2) == 0) + *puiDrvType=DRIVE_REMOTE; + else + *puiDrvType=DRIVE_UNKNOWN; + } + } +} + +bool TLocalFilesystem::PathExist(chcore::TSmartPath pathToCheck) +{ + WIN32_FIND_DATA fd; + + // search by exact name + HANDLE hFind = FindFirstFile(pathToCheck.ToString(), &fd); + if(hFind != INVALID_HANDLE_VALUE) + return true; + + // another try (add '\\' if needed and '*' for marking that we look for ie. c:\* + // instead of c:\, which would never be found prev. way) + pathToCheck.AppendIfNotExists(_T("*"), false); + + hFind = FindFirstFile(pathToCheck.ToString(), &fd); + if(hFind != INVALID_HANDLE_VALUE) + { + ::FindClose(hFind); + return true; + } + else + return false; +} + +bool TLocalFilesystem::SetFileDirectoryTime(LPCTSTR lpszName, const FILETIME& ftCreationTime, const FILETIME& ftLastAccessTime, const FILETIME& ftLastWriteTime) +{ + TAutoFileHandle hFile = CreateFile(lpszName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); + if(hFile == INVALID_HANDLE_VALUE) + return false; + + BOOL bResult = (!SetFileTime(hFile, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime)); + + if(!hFile.Close()) + return false; + + return bResult != 0; +} Index: src/ch/TLocalFilesystem.h =================================================================== diff -u --- src/ch/TLocalFilesystem.h (revision 0) +++ src/ch/TLocalFilesystem.h (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,38 @@ +// ============================================================================ +// Copyright (C) 2001-2010 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TLocalFilesystem.h +/// @date 2011/03/24 +/// @brief Contains class responsible for accessing local filesystem. +// ============================================================================ +#ifndef __TLOCALFILESYSTEM_H__ +#define __TLOCALFILESYSTEM_H__ + +#include "../libchcore/TPath.h" + +class TLocalFilesystem +{ +public: + static void GetDriveData(const chcore::TSmartPath& spPath, int *piDrvNum, UINT *puiDrvType); + static bool PathExist(chcore::TSmartPath strPath); // check for file or folder existence + static bool SetFileDirectoryTime(LPCTSTR lpszName, const FILETIME& ftCreationTime, const FILETIME& ftLastAccessTime, const FILETIME& ftLastWriteTime); + +}; + +#endif + Index: src/ch/TSubTaskBase.cpp =================================================================== diff -u -rb7709acbab26fdb108b77d3e08d3872f54248af2 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskBase.cpp (.../TSubTaskBase.cpp) (revision b7709acbab26fdb108b77d3e08d3872f54248af2) +++ src/ch/TSubTaskBase.cpp (.../TSubTaskBase.cpp) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -22,16 +22,116 @@ // ============================================================================ #include "stdafx.h" #include "TSubTaskBase.h" +#include "TBasePathData.h" +#include "TLocalFilesystem.h" +#include "TSubTaskContext.h" +#include "TTaskDefinition.h" +#include "TTaskConfiguration.h" /////////////////////////////////////////////////////////////////////////// // TSubTaskBase -TSubTaskBase::TSubTaskBase(TSubTaskContext& rContext, TSubTaskProgressInfo& rProgressInfo) : - m_rContext(rContext), - m_rProgressInfo(rProgressInfo) +TSubTaskBase::TSubTaskBase(TSubTaskContext& rContext) : + m_rContext(rContext) { } TSubTaskBase::~TSubTaskBase() { } + + +int TSubTaskBase::GetDriveNumber(const CFileInfoPtr& spFileInfo) +{ + if(!spFileInfo) + THROW(_T("Invalid pointer"), 0, 0, 0); + if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) + THROW(_T("Received non-relative (standalone) path info"), 0, 0, 0); + + // check if this information has already been stored + size_t stBaseIndex = spFileInfo->GetSrcIndex(); + if(stBaseIndex >= GetContext().GetBasePathDataContainer().GetCount()) + THROW(_T("Index out of bounds"), 0, 0, 0); + + TBasePathDataPtr spPathData = GetContext().GetBasePathDataContainer().GetAt(stBaseIndex); + if(spPathData->IsDriveNumberSet()) + return spPathData->GetDriveNumber(); + + // drive number wasn't cached previously - read it now + int iDriveNumber = 0; + TLocalFilesystem::GetDriveData(GetContext().GetTaskDefinition().GetSourcePathAt(stBaseIndex), &iDriveNumber, NULL); + + spPathData->SetDriveNumber(iDriveNumber); + + return iDriveNumber; +} + + +chcore::TSmartPath TSubTaskBase::CalculateDestinationPath(const CFileInfoPtr& spFileInfo, chcore::TSmartPath pathDst, int iFlags) const +{ + const TBasePathDataContainer& rSourcePathsInfo = GetContext().GetBasePathDataContainer(); + + if(!spFileInfo) + THROW(_T("Invalid pointer"), 0, 0, 0); + + // iFlags: bit 0-ignore folders; bit 1-force creating directories + if (iFlags & 0x02) + { + // force create directories + chcore::TSmartPath pathCombined = pathDst + spFileInfo->GetFullFilePath().GetFileDir(); + + // force create directory + SHCreateDirectoryEx(NULL, pathCombined.ToString(), NULL); + + return pathCombined + spFileInfo->GetFullFilePath().GetFileName(); + } + else + { + size_t stSrcIndex = spFileInfo->GetSrcIndex(); + + if (!(iFlags & 0x01) && stSrcIndex != std::numeric_limits::max()) + { + // generate new dest name + if(!rSourcePathsInfo.GetAt(stSrcIndex)->IsDestinationPathSet()) + { + chcore::TSmartPath pathSubst = FindFreeSubstituteName(spFileInfo->GetFullFilePath(), pathDst); + rSourcePathsInfo.GetAt(stSrcIndex)->SetDestinationPath(pathSubst); + } + + return pathDst + rSourcePathsInfo.GetAt(stSrcIndex)->GetDestinationPath() + spFileInfo->GetFilePath(); + } + else + return pathDst + spFileInfo->GetFullFilePath().GetFileName(); + } +} + + +// finds another name for a copy of src file(folder) in dest location +chcore::TSmartPath TSubTaskBase::FindFreeSubstituteName(chcore::TSmartPath pathSrcPath, chcore::TSmartPath pathDstPath) const +{ + const TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + + // get the name from srcpath + pathSrcPath.StripSeparatorAtEnd(); + + chcore::TSmartPath pathFilename = pathSrcPath.GetFileName(); + + // set the dest path + CString strCheckPath; + ictranslate::CFormat fmt(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + fmt.SetParam(_t("%name"), pathFilename.ToString()); + chcore::TSmartPath pathCheckPath(chcore::PathFromString((PCTSTR)fmt)); + + // when adding to strDstPath check if the path already exists - if so - try again + int iCounter=1; + CString strFmt = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + while(TLocalFilesystem::PathExist(pathDstPath + pathCheckPath)) + { + fmt.SetFormat(strFmt); + fmt.SetParam(_t("%name"), pathFilename.ToString()); + fmt.SetParam(_t("%count"), ++iCounter); + pathCheckPath.FromString((PCTSTR)fmt); + } + + return pathCheckPath; +} Index: src/ch/TSubTaskBase.h =================================================================== diff -u -rb7709acbab26fdb108b77d3e08d3872f54248af2 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskBase.h (.../TSubTaskBase.h) (revision b7709acbab26fdb108b77d3e08d3872f54248af2) +++ src/ch/TSubTaskBase.h (.../TSubTaskBase.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -23,23 +23,43 @@ #ifndef __TSUBTASKBASE_H__ #define __TSUBTASKBASE_H__ +#include "FileInfo.h" + class TSubTaskContext; -class TSubTaskProgressInfo; +class TBasePathDataContainer; /////////////////////////////////////////////////////////////////////////// // TSubTaskBase class TSubTaskBase { public: - TSubTaskBase(TSubTaskContext& rContext, TSubTaskProgressInfo& rProgressInfo); + enum ESubOperationResult + { + eSubResult_Continue, + eSubResult_KillRequest, + eSubResult_Error, + eSubResult_CancelRequest, + eSubResult_PauseRequest + }; + +public: + TSubTaskBase(TSubTaskContext& rContext); virtual ~TSubTaskBase(); - virtual void Exec() = 0; + virtual ESubOperationResult Exec() = 0; + TSubTaskContext& GetContext() { return m_rContext; } + const TSubTaskContext& GetContext() const { return m_rContext; } + +protected: + // some common operations + int GetDriveNumber(const CFileInfoPtr& spFileInfo); + chcore::TSmartPath CalculateDestinationPath(const CFileInfoPtr& spFileInfo, chcore::TSmartPath strPath, int iFlags) const; + chcore::TSmartPath FindFreeSubstituteName(chcore::TSmartPath pathSrcPath, chcore::TSmartPath pathDstPath) const; + private: TSubTaskContext& m_rContext; - TSubTaskProgressInfo& m_rProgressInfo; }; #endif Index: src/ch/TSubTaskContext.cpp =================================================================== diff -u -r3f72015a9db19bd1b0a5e20e0f1aa0ec00bda529 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskContext.cpp (.../TSubTaskContext.cpp) (revision 3f72015a9db19bd1b0a5e20e0f1aa0ec00bda529) +++ src/ch/TSubTaskContext.cpp (.../TSubTaskContext.cpp) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -23,9 +23,17 @@ #include "stdafx.h" #include "TSubTaskContext.h" -TSubTaskContext::TSubTaskContext(TTaskDefinition& rTaskDefinition, CFileInfoArray& rFilesCache) : +TSubTaskContext::TSubTaskContext(TTaskDefinition& rTaskDefinition, TBasePathDataContainer& rBasePathDataContainer, CFileInfoArray& rFilesCache, TTaskLocalStats& rTaskLocalStats, + TTaskBasicProgressInfo& rTaskBasicProgressInfo, TTaskConfigTracker& rCfgTracker, icpf::log_file& rLog, chcore::IFeedbackHandler* piFeedbackHandler, TWorkerThreadController& rThreadController) : m_rTaskDefinition(rTaskDefinition), - m_rFilesCache(rFilesCache) + m_rBasePathDataContainer(rBasePathDataContainer), + m_rFilesCache(rFilesCache), + m_rTaskLocalStats(rTaskLocalStats), + m_rTaskBasicProgressInfo(rTaskBasicProgressInfo), + m_rCfgTracker(rCfgTracker), + m_rLog(rLog), + m_piFeedbackHandler(piFeedbackHandler), + m_rThreadController(rThreadController) { } Index: src/ch/TSubTaskContext.h =================================================================== diff -u -r3f72015a9db19bd1b0a5e20e0f1aa0ec00bda529 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskContext.h (.../TSubTaskContext.h) (revision 3f72015a9db19bd1b0a5e20e0f1aa0ec00bda529) +++ src/ch/TSubTaskContext.h (.../TSubTaskContext.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -26,21 +26,75 @@ #include "FileInfo.h" class TTaskDefinition; +namespace chcore { class IFeedbackHandler; } +class TWorkerThreadController; +class TBasePathDataContainer; +class TTaskLocalStats; +class TTaskConfigTracker; +class TTaskBasicProgressInfo; /////////////////////////////////////////////////////////////////////////// // TSubTaskContext class TSubTaskContext { public: - TSubTaskContext(TTaskDefinition& rTaskDefinition, CFileInfoArray& rFilesCache); + TSubTaskContext(TTaskDefinition& rTaskDefinition, TBasePathDataContainer& rBasePathDataContainer, CFileInfoArray& rFilesCache, TTaskLocalStats& rTaskLocalStats, + TTaskBasicProgressInfo& rTaskBasicProgressInfo, TTaskConfigTracker& rCfgTracker, icpf::log_file& rLog, + chcore::IFeedbackHandler* piFeedbackHandler, TWorkerThreadController& rThreadController); ~TSubTaskContext(); + TTaskDefinition& GetTaskDefinition() { return m_rTaskDefinition; } + const TTaskDefinition& GetTaskDefinition() const { return m_rTaskDefinition; } + + TBasePathDataContainer& GetBasePathDataContainer() { return m_rBasePathDataContainer; } + const TBasePathDataContainer& GetBasePathDataContainer() const { return m_rBasePathDataContainer; } + + CFileInfoArray& GetFilesCache() { return m_rFilesCache; } + const CFileInfoArray& GetFilesCache() const { return m_rFilesCache; } + + TTaskLocalStats& GetTaskLocalStats() { return m_rTaskLocalStats; } + const TTaskLocalStats& GetTaskLocalStats() const { return m_rTaskLocalStats; } + + TTaskBasicProgressInfo& GetTaskBasicProgressInfo() { return m_rTaskBasicProgressInfo; } + const TTaskBasicProgressInfo& GetTaskBasicProgressInfo() const { return m_rTaskBasicProgressInfo; } + + TTaskConfigTracker& GetCfgTracker() { return m_rCfgTracker; } + const TTaskConfigTracker& GetCfgTracker() const { return m_rCfgTracker; } + + icpf::log_file& GetLog() { return m_rLog; } + const icpf::log_file& GetLog() const { return m_rLog; } + + chcore::IFeedbackHandler* GetFeedbackHandler() { return m_piFeedbackHandler; } + const chcore::IFeedbackHandler* GetFeedbackHandler() const { return m_piFeedbackHandler; } + + TWorkerThreadController& GetThreadController() { return m_rThreadController; } + const TWorkerThreadController& GetThreadController() const { return m_rThreadController; } + private: TTaskDefinition& m_rTaskDefinition; + // information about input paths + TBasePathDataContainer& m_rBasePathDataContainer; + // data on which to operate CFileInfoArray& m_rFilesCache; + + // local stats for task + TTaskLocalStats& m_rTaskLocalStats; + TTaskBasicProgressInfo& m_rTaskBasicProgressInfo; + + // configuration changes tracking + TTaskConfigTracker& m_rCfgTracker; + + // additional data + icpf::log_file& m_rLog; + + // feedback handling + chcore::IFeedbackHandler* m_piFeedbackHandler; + + // thread control + TWorkerThreadController& m_rThreadController; }; Index: src/ch/TSubTaskCopyMove.cpp =================================================================== diff -u -rb7709acbab26fdb108b77d3e08d3872f54248af2 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision b7709acbab26fdb108b77d3e08d3872f54248af2) +++ src/ch/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -22,3 +22,1072 @@ // ============================================================================ #include "stdafx.h" #include "TSubTaskCopyMove.h" +#include "TSubTaskContext.h" +#include "TTaskConfiguration.h" +#include "TTaskDefinition.h" +#include "task.h" +#include "TLocalFilesystem.h" +#include "FeedbackHandler.h" +#include "..\Common\FileSupport.h" +#include "Device IO.h" + +// assume max sectors of 4kB (for rounding) +#define MAXSECTORSIZE 4096 + +struct CUSTOM_COPY_PARAMS +{ + CFileInfoPtr spSrcFile; // CFileInfo - src file + chcore::TSmartPath pathDstFile; // dest path with filename + + CDataBuffer dbBuffer; // buffer handling + bool bOnlyCreate; // flag from configuration - skips real copying - only create + bool bProcessed; // has the element been processed ? (false if skipped) +}; + +TSubTaskCopyMove::TSubTaskCopyMove(TSubTaskContext& tSubTaskContext) : + TSubTaskBase(tSubTaskContext) +{ +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::Exec() +{ + icpf::log_file& rLog = GetContext().GetLog(); + CFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + TTaskConfigTracker& rCfgTracker = GetContext().GetCfgTracker(); + TTaskBasicProgressInfo& rBasicProgressInfo = GetContext().GetTaskBasicProgressInfo(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + TTaskLocalStats& rLocalStats = GetContext().GetTaskLocalStats(); + + BOOST_ASSERT(piFeedbackHandler != NULL); + if(piFeedbackHandler == NULL) + return eSubResult_Error; + + // log + rLog.logi(_T("Processing files/folders (ProcessFiles)")); + + // count how much has been done (updates also a member in TSubTaskCopyMoveArray) + rLocalStats.SetProcessedSize(rFilesCache.CalculatePartialSize(rBasicProgressInfo.GetCurrentIndex())); + + // begin at index which wasn't processed previously + size_t stSize = rFilesCache.GetSize(); + bool bIgnoreFolders = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bool bForceDirectories = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + + // create a buffer of size m_nBufferSize + CUSTOM_COPY_PARAMS ccp; + ccp.bProcessed = false; + ccp.bOnlyCreate = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + + // 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); + + BUFFERSIZES bs; + bs.m_bOnlyDefault = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiDefaultSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiOneDiskSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiTwoDisksSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiCDSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiLANSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + + ccp.dbBuffer.Create(&bs); + + // helpers + DWORD dwLastError = 0; + + // log + const BUFFERSIZES* pbs = ccp.dbBuffer.GetSizes(); + + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Processing files/folders (ProcessFiles):\r\n\tOnlyCreate: %create\r\n\tBufferSize: [Def:%defsize, One:%onesize, Two:%twosize, CD:%cdsize, LAN:%lansize]\r\n\tFiles/folders count: %filecount\r\n\tIgnore Folders: %ignorefolders\r\n\tDest path: %dstpath\r\n\tCurrent index (0-based): %currindex")); + fmt.SetParam(_t("%create"), ccp.bOnlyCreate); + fmt.SetParam(_t("%defsize"), pbs->m_uiDefaultSize); + fmt.SetParam(_t("%onesize"), pbs->m_uiOneDiskSize); + fmt.SetParam(_t("%twosize"), pbs->m_uiTwoDisksSize); + fmt.SetParam(_t("%cdsize"), pbs->m_uiCDSize); + fmt.SetParam(_t("%lansize"), pbs->m_uiLANSize); + fmt.SetParam(_t("%filecount"), stSize); + fmt.SetParam(_t("%ignorefolders"), bIgnoreFolders); + fmt.SetParam(_t("%dstpath"), rTaskDefinition.GetDestinationPath().ToString()); + fmt.SetParam(_t("%currindex"), rBasicProgressInfo.GetCurrentIndex()); + + rLog.logi(fmt); + + for(size_t stIndex = rBasicProgressInfo.GetCurrentIndex(); stIndex < stSize; stIndex++) + { + // should we kill ? + if(rThreadController.KillRequested()) + { + // log + rLog.logi(_T("Kill request while processing file in ProcessFiles")); + return TSubTaskBase::eSubResult_KillRequest; + } + + // update m_stNextIndex, getting current CFileInfo + CFileInfoPtr spFileInfo = rFilesCache.GetAt(rBasicProgressInfo.GetCurrentIndex()); + + // set dest path with filename + ccp.pathDstFile = CalculateDestinationPath(spFileInfo, rTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1 | (int)bIgnoreFolders); + + // are the files/folders lie on the same partition ? + int iDstDriveNumber = 0; + bool bMove = rTaskDefinition.GetOperationType() == eOperation_Move; + if(bMove) + TLocalFilesystem::GetDriveData(rTaskDefinition.GetDestinationPath(), &iDstDriveNumber, NULL); + if(bMove && iDstDriveNumber != -1 && iDstDriveNumber == GetDriveNumber(spFileInfo) && GetMove(spFileInfo)) + { + bool bRetry = true; + if(bRetry && !MoveFile(spFileInfo->GetFullFilePath().ToString(), ccp.pathDstFile.ToString())) + { + dwLastError=GetLastError(); + //log + fmt.SetFormat(_T("Error %errno while calling MoveFile %srcpath -> %dstpath (ProcessFiles)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%srcpath"), spFileInfo->GetFullFilePath().ToString()); + fmt.SetParam(_t("%dstpath"), ccp.pathDstFile.ToString()); + rLog.loge(fmt); + + FEEDBACK_FILEERROR ferr = { spFileInfo->GetFullFilePath().ToString(), ccp.pathDstFile.ToString(), eFastMoveError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + continue; + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bRetry = false; + break; // just do nothing + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + else + spFileInfo->SetFlags(FIF_PROCESSED, FIF_PROCESSED); + } + else + { + // if folder - create it + if(spFileInfo->IsDirectory()) + { + bool bRetry = true; + if(bRetry && !CreateDirectory(ccp.pathDstFile.ToString(), NULL) && (dwLastError=GetLastError()) != ERROR_ALREADY_EXISTS ) + { + // log + fmt.SetFormat(_T("Error %errno while calling CreateDirectory %path (ProcessFiles)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), ccp.pathDstFile.ToString()); + rLog.loge(fmt); + + FEEDBACK_FILEERROR ferr = { ccp.pathDstFile.ToString(), NULL, eCreateError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + continue; + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bRetry = false; + break; // just do nothing + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + + rLocalStats.IncreaseProcessedSize(spFileInfo->GetLength64()); + spFileInfo->SetFlags(FIF_PROCESSED, FIF_PROCESSED); + } + else + { + // start copying/moving file + ccp.spSrcFile = spFileInfo; + ccp.bProcessed = false; + + // kopiuj dane + TSubTaskBase::ESubOperationResult eResult = CustomCopyFileFB(&ccp); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + spFileInfo->SetFlags(ccp.bProcessed ? FIF_PROCESSED : 0, FIF_PROCESSED); + + // if moving - delete file (only if config flag is set) + if(bMove && spFileInfo->GetFlags() & FIF_PROCESSED && !GetTaskPropValue(rTaskDefinition.GetConfiguration())) + { + if(!GetTaskPropValue(rTaskDefinition.GetConfiguration())) + SetFileAttributes(spFileInfo->GetFullFilePath().ToString(), FILE_ATTRIBUTE_NORMAL); + DeleteFile(spFileInfo->GetFullFilePath().ToString()); // there will be another try later, so I don't check + // if succeeded + } + } + + // set a time + if(GetTaskPropValue(rTaskDefinition.GetConfiguration())) + TLocalFilesystem::SetFileDirectoryTime(ccp.pathDstFile.ToString(), spFileInfo->GetCreationTime(), spFileInfo->GetLastAccessTime(), spFileInfo->GetLastWriteTime()); // no error checking (but most probably it should be checked) + + // attributes + if(GetTaskPropValue(rTaskDefinition.GetConfiguration())) + SetFileAttributes(ccp.pathDstFile.ToString(), spFileInfo->GetAttributes()); // as above + } + + rBasicProgressInfo.SetCurrentIndex(stIndex + 1); + } + + // delete buffer - it's not needed + ccp.dbBuffer.Delete(); + + // to look better (as 100%) - increase current index by 1 + rBasicProgressInfo.SetCurrentIndex(stSize); + + // log + rLog.logi(_T("Finished processing in ProcessFiles")); + + return TSubTaskBase::eSubResult_Continue; +} + +bool TSubTaskCopyMove::GetMove(const CFileInfoPtr& spFileInfo) +{ + if(!spFileInfo) + THROW(_T("Invalid pointer"), 0, 0, 0); + if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) + THROW(_T("Received non-relative (standalone) path info"), 0, 0, 0); + + // check if this information has already been stored + size_t stBaseIndex = spFileInfo->GetSrcIndex(); + if(stBaseIndex >= GetContext().GetBasePathDataContainer().GetCount()) + THROW(_T("Index out of bounds"), 0, 0, 0); + + TBasePathDataPtr spPathData = GetContext().GetBasePathDataContainer().GetAt(stBaseIndex); + return spPathData->GetMove(); +} + +int TSubTaskCopyMove::GetBufferIndex(const CFileInfoPtr& spFileInfo) +{ + TBasePathDataContainer& rSrcPathsInfo = GetContext().GetBasePathDataContainer(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + + if(!spFileInfo) + THROW(_T("Invalid pointer"), 0, 0, 0); + if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) + THROW(_T("Received non-relative (standalone) path info"), 0, 0, 0); + + // check if this information has already been stored + size_t stBaseIndex = spFileInfo->GetSrcIndex(); + if(stBaseIndex >= rSrcPathsInfo.GetCount()) + THROW(_T("Index out of bounds"), 0, 0, 0); + + TBasePathDataPtr spPathData = rSrcPathsInfo.GetAt(stBaseIndex); + if(spPathData->IsBufferIndexSet()) + return spPathData->GetBufferIndex(); + + // buffer index wasn't cached previously - read it now + int iDriveNumber = 0; + UINT uiDriveType = 0; + int iDstDriveNumber = 0; + UINT uiDstDriveType = 0; + TLocalFilesystem::GetDriveData(rTaskDefinition.GetSourcePathAt(stBaseIndex), &iDriveNumber, &uiDriveType); + TLocalFilesystem::GetDriveData(rTaskDefinition.GetDestinationPath(), &iDstDriveNumber, &uiDstDriveType); + + // what kind of buffer + int iBufferIndex = BI_DEFAULT; + if(uiDriveType == DRIVE_REMOTE || uiDstDriveType == DRIVE_REMOTE) + iBufferIndex = BI_LAN; + else if(uiDriveType == DRIVE_CDROM || uiDstDriveType == DRIVE_CDROM) + iBufferIndex = BI_CD; + else if(uiDriveType == DRIVE_FIXED && uiDstDriveType == DRIVE_FIXED) + { + // two hdd's - is this the same physical disk ? + if(iDriveNumber == iDstDriveNumber || IsSamePhysicalDisk(iDriveNumber, iDstDriveNumber)) + iBufferIndex = BI_ONEDISK; + else + iBufferIndex = BI_TWODISKS; + } + else + iBufferIndex = BI_DEFAULT; + + spPathData->SetBufferIndex(iBufferIndex); + + return iBufferIndex; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::CustomCopyFileFB(CUSTOM_COPY_PARAMS* pData) +{ + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + TTaskBasicProgressInfo& rBasicProgressInfo = GetContext().GetTaskBasicProgressInfo(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + TTaskLocalStats& rLocalStats = GetContext().GetTaskLocalStats(); + icpf::log_file& rLog = GetContext().GetLog(); + TTaskConfigTracker& rCfgTracker = GetContext().GetCfgTracker(); + + TAutoFileHandle hSrc = INVALID_HANDLE_VALUE, + hDst = INVALID_HANDLE_VALUE; + ictranslate::CFormat fmt; + TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; + bool bSkip = false; + + // calculate if we want to disable buffering for file transfer + // NOTE: we are using here the file size read when scanning directories for files; it might be + // outdated at this point, but at present we don't want to re-read file size since it + // will cost additional disk access + bool bNoBuffer = (GetTaskPropValue(rTaskDefinition.GetConfiguration()) && + pData->spSrcFile->GetLength64() >= GetTaskPropValue(rTaskDefinition.GetConfiguration())); + + // first open the source file and handle any failures + eResult = OpenSourceFileFB(hSrc, pData->spSrcFile, bNoBuffer); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(hSrc == INVALID_HANDLE_VALUE) + { + // invalid handle = operation skipped by user + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + // change attributes of a dest file + // NOTE: probably should be removed from here and report problems with read-only files + // directly to the user (as feedback request) + if(!GetTaskPropValue(rTaskDefinition.GetConfiguration())) + SetFileAttributes(pData->pathDstFile.ToString(), FILE_ATTRIBUTE_NORMAL); + + // open destination file, handle the failures and possibly existence of the destination file + unsigned long long ullSeekTo = 0; + bool bDstFileFreshlyCreated = false; + + if(rBasicProgressInfo.GetCurrentFileProcessedSize() == 0) + { + // open destination file for case, when we start operation on this file (i.e. it is not resume of the + // old operation) + eResult = OpenDestinationFileFB(hDst, pData->pathDstFile, bNoBuffer, pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(hDst == INVALID_HANDLE_VALUE) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + else + { + // we are resuming previous operation + eResult = OpenExistingDestinationFileFB(hDst, pData->pathDstFile, bNoBuffer); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(hDst == INVALID_HANDLE_VALUE) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + ullSeekTo = rBasicProgressInfo.GetCurrentFileProcessedSize(); + } + + if(!pData->bOnlyCreate) + { + // seek to the position where copying will start + 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); + + eResult = SetFilePointerFB(hSrc, ullMove, pData->spSrcFile->GetFullFilePath(), bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + eResult = SetFilePointerFB(hDst, ullMove, pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // with either first or second seek we got 'skip' answer... + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + rBasicProgressInfo.IncreaseCurrentFileProcessedSize(ullMove); + rLocalStats.IncreaseProcessedSize(ullMove); + } + + // 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 = SetEndOfFileFB(hDst, pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + + // copying + unsigned long ulToRead = 0; + unsigned long ulRead = 0; + unsigned long ulWritten = 0; + int iBufferIndex = 0; + bool bLastPart = false; + + do + { + // kill flag checks + if(rThreadController.KillRequested()) + { + // log + fmt.SetFormat(_T("Kill request while main copying file %srcpath -> %dstpath")); + fmt.SetParam(_t("%srcpath"), pData->spSrcFile->GetFullFilePath().ToString()); + fmt.SetParam(_t("%dstpath"), pData->pathDstFile.ToString()); + rLog.logi(fmt); + return TSubTaskBase::eSubResult_KillRequest; + } + + // recreate buffer if needed + if(rCfgTracker.IsModified() && rCfgTracker.IsModified(TOptionsSet() % eTO_DefaultBufferSize % eTO_OneDiskBufferSize % eTO_TwoDisksBufferSize % eTO_CDBufferSize % eTO_LANBufferSize % eTO_UseOnlyDefaultBuffer, true)) + { + BUFFERSIZES bs; + bs.m_bOnlyDefault = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiDefaultSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiOneDiskSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiTwoDisksSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiCDSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bs.m_uiLANSize = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + + // log + const BUFFERSIZES* pbs1 = pData->dbBuffer.GetSizes(); + + fmt.SetFormat(_T("Changing buffer size from [Def:%defsize, One:%onesize, Two:%twosize, CD:%cdsize, LAN:%lansize] to [Def:%defsize2, One:%onesize2, Two:%twosize2, CD:%cdsize2, LAN:%lansize2] wile copying %srcfile -> %dstfile (CustomCopyFileFB)")); + + fmt.SetParam(_t("%defsize"), pbs1->m_uiDefaultSize); + fmt.SetParam(_t("%onesize"), pbs1->m_uiOneDiskSize); + fmt.SetParam(_t("%twosize"), pbs1->m_uiTwoDisksSize); + fmt.SetParam(_t("%cdsize"), pbs1->m_uiCDSize); + fmt.SetParam(_t("%lansize"), pbs1->m_uiLANSize); + fmt.SetParam(_t("%defsize2"), bs.m_uiDefaultSize); + fmt.SetParam(_t("%onesize2"), bs.m_uiOneDiskSize); + fmt.SetParam(_t("%twosize2"), bs.m_uiTwoDisksSize); + fmt.SetParam(_t("%cdsize2"), bs.m_uiCDSize); + fmt.SetParam(_t("%lansize2"), bs.m_uiLANSize); + fmt.SetParam(_t("%srcfile"), pData->spSrcFile->GetFullFilePath().ToString()); + fmt.SetParam(_t("%dstfile"), pData->pathDstFile.ToString()); + + rLog.logi(fmt); + pData->dbBuffer.Create(&bs); + } + + // establish count of data to read + if(GetTaskPropValue(rTaskDefinition.GetConfiguration())) + iBufferIndex = BI_DEFAULT; + else + iBufferIndex = GetBufferIndex(pData->spSrcFile); + rLocalStats.SetCurrentBufferIndex(iBufferIndex); + + ulToRead = bNoBuffer ? ROUNDUP(pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex], MAXSECTORSIZE) : pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex]; + + // read data from file to buffer + eResult = ReadFileFB(hSrc, pData->dbBuffer, ulToRead, ulRead, pData->spSrcFile->GetFullFilePath(), bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + if(ulRead > 0) + { + // determine if this is the last chunk of data we could get from the source file (EOF condition) + bLastPart = (ulToRead != ulRead); + + // handle not aligned part at the end of file when no buffering is enabled + if(bNoBuffer && bLastPart) + { + // 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 + + // 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(ulRead, MAXSECTORSIZE); + if(ulDataToWrite > 0) + { + eResult = WriteFileFB(hDst, pData->dbBuffer, ulDataToWrite, ulWritten, pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + // increase count of processed data + rBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulWritten); + rLocalStats.IncreaseProcessedSize(ulWritten); + + // calculate count of bytes left to be written + ulRead -= ulWritten; + + // now remove part of data from buffer (ulWritten bytes) + pData->dbBuffer.CutDataFromBuffer(ulWritten); + } + + // close and re-open the destination file with buffering option for append + hDst.Close(); + + // are there any more data to be written? + if(ulRead != 0) + { + // re-open the destination file, this time with standard buffering to allow writing not aligned part of file data + eResult = OpenExistingDestinationFileFB(hDst, pData->pathDstFile, false); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(hDst == INVALID_HANDLE_VALUE) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + // move file pointer to the end of destination file + eResult = SetFilePointerFB(hDst, rBasicProgressInfo.GetCurrentFileProcessedSize(), pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + // with either first or second seek we got 'skip' answer... + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + } + + // write + if(ulRead != 0) + { + eResult = WriteFileFB(hDst, pData->dbBuffer, ulRead, ulWritten, pData->pathDstFile, bSkip); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(bSkip) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + + // increase count of processed data + rBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulRead); + rLocalStats.IncreaseProcessedSize(ulRead); + } + } + } + while(ulRead != 0 && !bLastPart); + } + else + { + // we don't copy contents, but need to increase processed size + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + } + + pData->bProcessed = true; + rBasicProgressInfo.SetCurrentFileProcessedSize(0); + + return TSubTaskBase::eSubResult_Continue; +} + + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenSourceFileFB(TAutoFileHandle& hOutFile, const CFileInfoPtr& spSrcFileInfo, bool bNoBuffering) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + BOOST_ASSERT(spSrcFileInfo); + if(!spSrcFileInfo) + THROW(_T("Invalid argument"), 0, 0, 0); + + bool bRetry = false; + CString strPath = spSrcFileInfo->GetFullFilePath().ToString(); + + hOutFile = INVALID_HANDLE_VALUE; + + TAutoFileHandle hFile; + do + { + bRetry = false; + + hFile = CreateFile(strPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + if(hFile == INVALID_HANDLE_VALUE) + { + DWORD dwLastError = GetLastError(); + + FEEDBACK_FILEERROR feedStruct = { (PCTSTR)strPath, NULL, eCreateError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); + + switch(frResult) + { + case CFeedbackHandler::eResult_Skip: + break; // will return INVALID_HANDLE_VALUE + + case CFeedbackHandler::eResult_Cancel: + { + // log + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Cancel request [error %errno] while opening source file %path (OpenSourceFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), strPath); + rLog.loge(fmt); + + return TSubTaskBase::eSubResult_CancelRequest; + } + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Retry: + { + // log + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Retrying [error %errno] to open source file %path (OpenSourceFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), strPath); + rLog.loge(fmt); + + bRetry = true; + break; + } + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + hOutFile = hFile.Detach(); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenDestinationFileFB(TAutoFileHandle& hOutFile, const chcore::TSmartPath& pathDstFile, bool bNoBuffering, const CFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bool bRetry = false; + TAutoFileHandle hFile; + + ullSeekTo = 0; + bFreshlyCreated = true; + hOutFile = INVALID_HANDLE_VALUE; + + do + { + bRetry = false; + + hFile = ::CreateFile(pathDstFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + if(hFile == INVALID_HANDLE_VALUE) + { + DWORD dwLastError = GetLastError(); + if(dwLastError == ERROR_FILE_EXISTS) + { + bFreshlyCreated = false; + + // pass it to the specialized method + TSubTaskBase::ESubOperationResult eResult = OpenExistingDestinationFileFB(hFile, pathDstFile, bNoBuffering); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(hFile == INVALID_HANDLE_VALUE) + return TSubTaskBase::eSubResult_Continue; + + // read info about the existing destination file, + // NOTE: it is not known which one would be faster - reading file parameters + // by using spDstFileInfo->Create() (which uses FindFirstFile()) or by + // reading parameters using opened handle; need to be tested in the future + CFileInfoPtr spDstFileInfo(boost::make_shared()); + if(!spDstFileInfo->Create(pathDstFile, std::numeric_limits::max())) + THROW(_T("Cannot get information about file which has already been opened!"), 0, GetLastError(), 0); + + // src and dst files are the same + FEEDBACK_ALREADYEXISTS feedStruct = { spSrcFileInfo, spDstFileInfo }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileAlreadyExists, &feedStruct); + // check for dialog result + switch(frResult) + { + case CFeedbackHandler::eResult_Overwrite: + ullSeekTo = 0; + break; + + case CFeedbackHandler::eResult_CopyRest: + ullSeekTo = spDstFileInfo->GetLength64(); + break; + + case CFeedbackHandler::eResult_Skip: + return TSubTaskBase::eSubResult_Continue; + + case CFeedbackHandler::eResult_Cancel: + { + // log + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Cancel request while checking result of dialog before opening source file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%path"), pathDstFile.ToString()); + rLog.logi(fmt); + + return TSubTaskBase::eSubResult_CancelRequest; + } + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + else + { + FEEDBACK_FILEERROR feedStruct = { pathDstFile.ToString(), NULL, eCreateError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); + switch (frResult) + { + case CFeedbackHandler::eResult_Retry: + { + // log + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pathDstFile.ToString()); + rLog.loge(fmt); + + bRetry = true; + + break; + } + case CFeedbackHandler::eResult_Cancel: + { + // log + ictranslate::CFormat fmt; + + fmt.SetFormat(_T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pathDstFile.ToString()); + rLog.loge(fmt); + + return TSubTaskBase::eSubResult_CancelRequest; + } + + case CFeedbackHandler::eResult_Skip: + break; // will return invalid handle value + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + } + while(bRetry); + + hOutFile = hFile.Detach(); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenExistingDestinationFileFB(TAutoFileHandle& hOutFile, const chcore::TSmartPath& pathDstFile, bool bNoBuffering) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bool bRetry = false; + TAutoFileHandle hFile; + + hOutFile = INVALID_HANDLE_VALUE; + + do + { + bRetry = false; + + hFile = CreateFile(pathDstFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + if(hFile == INVALID_HANDLE_VALUE) + { + DWORD dwLastError = GetLastError(); + FEEDBACK_FILEERROR feedStruct = { pathDstFile.ToString(), NULL, eCreateError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); + switch (frResult) + { + case CFeedbackHandler::eResult_Retry: + { + // log + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pathDstFile.ToString()); + rLog.loge(fmt); + + bRetry = true; + + break; + } + case CFeedbackHandler::eResult_Cancel: + { + // log + ictranslate::CFormat fmt; + + fmt.SetFormat(_T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pathDstFile.ToString()); + rLog.loge(fmt); + + return TSubTaskBase::eSubResult_CancelRequest; + } + + case CFeedbackHandler::eResult_Skip: + break; // will return invalid handle value + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + hOutFile = hFile.Detach(); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::SetFilePointerFB(HANDLE hFile, long long llDistance, const chcore::TSmartPath& pathFile, bool& bSkip) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + bool bRetry = false; + do + { + bRetry = false; + + if(SetFilePointer64(hFile, llDistance, FILE_BEGIN) == -1) + { + DWORD dwLastError = GetLastError(); + + // log + ictranslate::CFormat fmt; + + fmt.SetFormat(_T("Error %errno while moving file pointer of %path to %pos")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pathFile.ToString()); + fmt.SetParam(_t("%pos"), llDistance); + rLog.loge(fmt); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eSeekError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::SetEndOfFileFB(HANDLE hFile, const chcore::TSmartPath& pathFile, bool& bSkip) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + + bool bRetry = false; + do + { + if(!SetEndOfFile(hFile)) + { + // log + DWORD dwLastError = GetLastError(); + + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Error %errno while setting size of file %path to 0")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pathFile.ToString()); + rLog.loge(fmt); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eResizeError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + bRetry = true; + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::ReadFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const chcore::TSmartPath& pathFile, bool& bSkip) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + bool bRetry = false; + do + { + bRetry = false; + + if(!ReadFile(hFile, rBuffer, dwToRead, &rdwBytesRead, NULL)) + { + // log + DWORD dwLastError = GetLastError(); + + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Error %errno while trying to read %count bytes from source file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%count"), dwToRead); + fmt.SetParam(_t("%path"), pathFile.ToString()); + rLog.loge(fmt); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eReadError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::WriteFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const chcore::TSmartPath& pathFile, bool& bSkip) +{ + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + + bool bRetry = false; + do + { + bRetry = false; + + if(!WriteFile(hFile, rBuffer, dwToWrite, &rdwBytesWritten, NULL) || dwToWrite != rdwBytesWritten) + { + // log + DWORD dwLastError = GetLastError(); + + ictranslate::CFormat fmt; + fmt.SetFormat(_T("Error %errno while trying to write %count bytes to destination file %path (CustomCopyFileFB)")); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%count"), dwToWrite); + fmt.SetParam(_t("%path"), pathFile.ToString()); + rLog.loge(fmt); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eWriteError, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case CFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} Index: src/ch/TSubTaskCopyMove.h =================================================================== diff -u -rb7709acbab26fdb108b77d3e08d3872f54248af2 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision b7709acbab26fdb108b77d3e08d3872f54248af2) +++ src/ch/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -23,4 +23,34 @@ #ifndef __TSUBTASKCOPYMOVE_H__ #define __TSUBTASKCOPYMOVE_H__ +#include "TSubTaskBase.h" + +struct CUSTOM_COPY_PARAMS; +class TAutoFileHandle; +class CDataBuffer; + +class TSubTaskCopyMove : public TSubTaskBase +{ +public: + TSubTaskCopyMove(TSubTaskContext& tSubTaskContext); + + ESubOperationResult Exec(); + +private: + bool GetMove(const CFileInfoPtr& spFileInfo); + int GetBufferIndex(const CFileInfoPtr& spFileInfo); + + TSubTaskBase::ESubOperationResult CustomCopyFileFB(CUSTOM_COPY_PARAMS* pData); + + TSubTaskBase::ESubOperationResult OpenSourceFileFB(TAutoFileHandle& hFile, const CFileInfoPtr& spSrcFileInfo, bool bNoBuffering); + TSubTaskBase::ESubOperationResult OpenDestinationFileFB(TAutoFileHandle& hFile, const chcore::TSmartPath& pathDstFile, bool bNoBuffering, const CFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated); + TSubTaskBase::ESubOperationResult OpenExistingDestinationFileFB(TAutoFileHandle& hFile, const chcore::TSmartPath& pathDstFilePath, bool bNoBuffering); + + TSubTaskBase::ESubOperationResult SetFilePointerFB(HANDLE hFile, long long llDistance, const chcore::TSmartPath& pathFile, bool& bSkip); + TSubTaskBase::ESubOperationResult SetEndOfFileFB(HANDLE hFile, const chcore::TSmartPath& pathFile, bool& bSkip); + + TSubTaskBase::ESubOperationResult ReadFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const chcore::TSmartPath& pathFile, bool& bSkip); + TSubTaskBase::ESubOperationResult WriteFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const chcore::TSmartPath& pathFile, bool& bSkip); +}; + #endif Index: src/ch/TSubTaskProgressInfo.cpp =================================================================== diff -u -rae09c8430aad5eaa8225df84878b7d9050bdccd6 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskProgressInfo.cpp (.../TSubTaskProgressInfo.cpp) (revision ae09c8430aad5eaa8225df84878b7d9050bdccd6) +++ src/ch/TSubTaskProgressInfo.cpp (.../TSubTaskProgressInfo.cpp) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -22,6 +22,7 @@ // ============================================================================ #include "stdafx.h" #include "TSubTaskProgressInfo.h" +/* /////////////////////////////////////////////////////////////////////////// // TSubTaskProgressInfo @@ -250,3 +251,4 @@ m_timeLast = timeCurrent; } } +*/ Index: src/ch/TSubTaskProgressInfo.h =================================================================== diff -u -rae09c8430aad5eaa8225df84878b7d9050bdccd6 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskProgressInfo.h (.../TSubTaskProgressInfo.h) (revision ae09c8430aad5eaa8225df84878b7d9050bdccd6) +++ src/ch/TSubTaskProgressInfo.h (.../TSubTaskProgressInfo.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -23,6 +23,7 @@ #ifndef __TSUBTASKPROGRESSINFO_H__ #define __TSUBTASKPROGRESSINFO_H__ +/* /////////////////////////////////////////////////////////////////////////// // TSubTaskProgressInfo @@ -93,5 +94,6 @@ }; typedef boost::shared_ptr TSubTaskProgressInfoPtr; +*/ #endif // __TSUBTASKPROGRESSINFO_H__ \ No newline at end of file Index: src/ch/TSubTaskScanDirectory.cpp =================================================================== diff -u -rb7709acbab26fdb108b77d3e08d3872f54248af2 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskScanDirectory.cpp (.../TSubTaskScanDirectory.cpp) (revision b7709acbab26fdb108b77d3e08d3872f54248af2) +++ src/ch/TSubTaskScanDirectory.cpp (.../TSubTaskScanDirectory.cpp) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -22,4 +22,249 @@ // ============================================================================ #include "stdafx.h" #include "TSubTaskScanDirectory.h" +#include "TSubTaskContext.h" +#include "TTaskConfiguration.h" +#include "TTaskDefinition.h" +#include "FeedbackHandler.h" +#include "TLocalFilesystem.h" +#include "..\libchcore\FeedbackHandlerBase.h" +#include "TBasePathData.h" +#include "TWorkerThreadController.h" +#include "TTaskLocalStats.h" +TSubTaskScanDirectories::TSubTaskScanDirectories(TSubTaskContext& rContext) : + TSubTaskBase(rContext) +{ +} + +TSubTaskScanDirectories::~TSubTaskScanDirectories() +{ +} + +TSubTaskScanDirectories::ESubOperationResult TSubTaskScanDirectories::Exec() +{ + // log + icpf::log_file& rLog = GetContext().GetLog(); + CFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + chcore::IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + const TBasePathDataContainer& rarrSourcePathsInfo = GetContext().GetTaskDefinition().GetSourcePaths(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + + rLog.logi(_T("Searching for files...")); + + // delete the content of rFilesCache + rFilesCache.Clear(); + + // read filtering options + CFiltersArray afFilters; + GetTaskPropValue(rTaskDefinition.GetConfiguration(), afFilters); + + // enter some data to rFilesCache + int iDestDrvNumber = 0; + TLocalFilesystem::GetDriveData(rTaskDefinition.GetDestinationPath(), &iDestDrvNumber, NULL); + + bool bIgnoreDirs = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bool bForceDirectories = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bool bMove = rTaskDefinition.GetOperationType() == eOperation_Move; + + // add everything + ictranslate::CFormat fmt; + bool bRetry = true; + bool bSkipInputPath = false; + + size_t stSize = rTaskDefinition.GetSourcePathCount(); + for(size_t stIndex = 0; stIndex < stSize ; stIndex++) + { + CFileInfoPtr spFileInfo; + + bSkipInputPath = false; + + spFileInfo.reset(new CFileInfo()); + spFileInfo->SetClipboard(&rTaskDefinition.GetSourcePaths()); + + // try to get some info about the input path; let user know if the path does not exist. + do + { + bRetry = false; + + // read attributes of src file/folder + bool bExists = spFileInfo->Create(rTaskDefinition.GetSourcePathAt(stIndex), stIndex); + if(!bExists) + { + FEEDBACK_FILEERROR ferr = { rTaskDefinition.GetSourcePathAt(stIndex).ToString(), NULL, eFastMoveError, ERROR_FILE_NOT_FOUND }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case CFeedbackHandler::eResult_Cancel: + rFilesCache.Clear(); + return eSubResult_CancelRequest; + + case CFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case CFeedbackHandler::eResult_Pause: + rFilesCache.Clear(); + return eSubResult_PauseRequest; + + case CFeedbackHandler::eResult_Skip: + bSkipInputPath = true; + break; // just do nothing + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW(_T("Unhandled case"), 0, 0, 0); + } + } + } + while(bRetry); + + // if we have chosen to skip the input path then there's nothing to do + if(bSkipInputPath) + continue; + + // log + fmt.SetFormat(_T("Adding file/folder (clipboard) : %path ...")); + fmt.SetParam(_t("%path"), rTaskDefinition.GetSourcePathAt(stIndex).ToString()); + rLog.logi(fmt); + + // found file/folder - check if the dest name has been generated + if(!rarrSourcePathsInfo.GetAt(stIndex)->IsDestinationPathSet()) + { + // generate something - if dest folder == src folder - search for copy + if(rTaskDefinition.GetDestinationPath() == spFileInfo->GetFullFilePath().GetFileRoot()) + { + chcore::TSmartPath pathSubst = FindFreeSubstituteName(spFileInfo->GetFullFilePath(), rTaskDefinition.GetDestinationPath()); + rarrSourcePathsInfo.GetAt(stIndex)->SetDestinationPath(pathSubst); + } + else + rarrSourcePathsInfo.GetAt(stIndex)->SetDestinationPath(spFileInfo->GetFullFilePath().GetFileName()); + } + + // add if needed + if(spFileInfo->IsDirectory()) + { + // add if folder's aren't ignored + if(!bIgnoreDirs && !bForceDirectories) + { + // add directory info; it is not to be filtered with afFilters + rFilesCache.AddFileInfo(spFileInfo); + + // log + fmt.SetFormat(_T("Added folder %path")); + fmt.SetParam(_t("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.logi(fmt); + } + + // don't add folder contents when moving inside one disk boundary + if(bIgnoreDirs || !bMove || iDestDrvNumber == -1 || iDestDrvNumber != GetDriveNumber(spFileInfo) || + TLocalFilesystem::PathExist(CalculateDestinationPath(spFileInfo, rTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1)) ) + { + // log + fmt.SetFormat(_T("Recursing folder %path")); + fmt.SetParam(_t("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.logi(fmt); + + // no movefile possibility - use CustomCopyFileFB + rarrSourcePathsInfo.GetAt(stIndex)->SetMove(false); + + ScanDirectory(spFileInfo->GetFullFilePath(), stIndex, true, !bIgnoreDirs || bForceDirectories, afFilters); + } + + // check for kill need + if(rThreadController.KillRequested()) + { + // log + rLog.logi(_T("Kill request while adding data to files array (RecurseDirectories)")); + rFilesCache.Clear(); + return eSubResult_KillRequest; + } + } + else + { + if(bMove && iDestDrvNumber != -1 && iDestDrvNumber == GetDriveNumber(spFileInfo) && + !TLocalFilesystem::PathExist(CalculateDestinationPath(spFileInfo, rTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1)) ) + { + // if moving within one partition boundary set the file size to 0 so the overall size will + // be ok + spFileInfo->SetLength64(0); + } + else + rarrSourcePathsInfo.GetAt(stIndex)->SetMove(false); // no MoveFile + + // add file info if passes filters + if(afFilters.Match(spFileInfo)) + rFilesCache.AddFileInfo(spFileInfo); + + // log + fmt.SetFormat(_T("Added file %path")); + fmt.SetParam(_t("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.logi(fmt); + } + } + + // calc size of all files + GetContext().GetTaskLocalStats().SetTotalSize(rFilesCache.CalculateTotalSize()); + + // log + rLog.logi(_T("Searching for files finished")); + + return eSubResult_Continue; +} + +int TSubTaskScanDirectories::ScanDirectory(chcore::TSmartPath pathDirName, size_t stSrcIndex, bool bRecurse, bool bIncludeDirs, CFiltersArray& afFilters) +{ + CFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + + WIN32_FIND_DATA wfd; + chcore::TSmartPath pathCurrent; + + pathCurrent = pathDirName + chcore::PathFromString(_T("*")); + + // Iterate through dirs & files + HANDLE hFind = FindFirstFile(pathCurrent.ToString(), &wfd); + if(hFind != INVALID_HANDLE_VALUE) + { + do + { + if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + CFileInfoPtr spFileInfo(boost::make_shared()); + spFileInfo->SetClipboard(&rTaskDefinition.GetSourcePaths()); // this is the link table (CClipboardArray) + + spFileInfo->Create(&wfd, pathDirName, stSrcIndex); + if(afFilters.Match(spFileInfo)) + rFilesCache.AddFileInfo(spFileInfo); + } + else if(wfd.cFileName[0] != _T('.') || (wfd.cFileName[1] != _T('\0') && (wfd.cFileName[1] != _T('.') || wfd.cFileName[2] != _T('\0')))) + { + if(bIncludeDirs) + { + CFileInfoPtr spFileInfo(boost::make_shared()); + spFileInfo->SetClipboard(&rTaskDefinition.GetSourcePaths()); // this is the link table (CClipboardArray) + + // Add directory itself + spFileInfo->Create(&wfd, pathDirName, stSrcIndex); + rFilesCache.AddFileInfo(spFileInfo); + } + if(bRecurse) + { + pathCurrent = pathDirName + chcore::PathFromString(wfd.cFileName) + chcore::PathFromString(_T("\\")); + // Recurse Dirs + ScanDirectory(pathCurrent, stSrcIndex, bRecurse, bIncludeDirs, afFilters); + } + } + + if(rThreadController.KillRequested()) + break; + } + while(FindNextFile(hFind, &wfd)); + + FindClose(hFind); + } + + return 0; +} Index: src/ch/TSubTaskScanDirectory.h =================================================================== diff -u -rb7709acbab26fdb108b77d3e08d3872f54248af2 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TSubTaskScanDirectory.h (.../TSubTaskScanDirectory.h) (revision b7709acbab26fdb108b77d3e08d3872f54248af2) +++ src/ch/TSubTaskScanDirectory.h (.../TSubTaskScanDirectory.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -24,17 +24,22 @@ #define __TSUBTASKSCANDIRECTORY_H__ #include "TSubTaskBase.h" +#include "../libchcore/TPath.h" +#include "FileFilter.h" /////////////////////////////////////////////////////////////////////////// // TSubTaskScanDirectories class TSubTaskScanDirectories : public TSubTaskBase { public: - TSubTaskScanDirectories(); + TSubTaskScanDirectories(TSubTaskContext& rContext); virtual ~TSubTaskScanDirectories(); - virtual void Exec(); + virtual ESubOperationResult Exec(); + +private: + int ScanDirectory(chcore::TSmartPath pathDirName, size_t stSrcIndex, bool bRecurse, bool bIncludeDirs, CFiltersArray& afFilters); }; #endif Index: src/ch/TTaskGlobalStats.cpp =================================================================== diff -u --- src/ch/TTaskGlobalStats.cpp (revision 0) +++ src/ch/TTaskGlobalStats.cpp (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,118 @@ +// ============================================================================ +// Copyright (C) 2001-2009 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TTaskGlobalStats.cpp +/// @date 2011/03/28 +/// @brief Contains declarations of classes responsible for maintaining task global stats. +// ============================================================================ +#include "stdafx.h" +#include "TTaskGlobalStats.h" + +//////////////////////////////////////////////////////////////////////////////// +// TTasksGlobalStats members + +TTasksGlobalStats::TTasksGlobalStats() : + m_ullGlobalTotalSize(0), + m_ullGlobalProcessedSize(0), + m_stRunningTasks(0) +{ +} + +TTasksGlobalStats::~TTasksGlobalStats() +{ +} + +void TTasksGlobalStats::IncreaseGlobalTotalSize(unsigned long long ullModify) +{ + boost::unique_lock lock(m_lock); + m_ullGlobalTotalSize += ullModify; +} + +void TTasksGlobalStats::DecreaseGlobalTotalSize(unsigned long long ullModify) +{ + boost::unique_lock lock(m_lock); + m_ullGlobalTotalSize -= ullModify; +} + +unsigned long long TTasksGlobalStats::GetGlobalTotalSize() const +{ + boost::shared_lock lock(m_lock); + return m_ullGlobalTotalSize; +} + +void TTasksGlobalStats::IncreaseGlobalProcessedSize(unsigned long long ullModify) +{ + boost::unique_lock lock(m_lock); + m_ullGlobalProcessedSize += ullModify; +} + +void TTasksGlobalStats::DecreaseGlobalProcessedSize(unsigned long long ullModify) +{ + boost::unique_lock lock(m_lock); + m_ullGlobalProcessedSize -= ullModify; +} + +unsigned long long TTasksGlobalStats::GetGlobalProcessedSize() const +{ + boost::shared_lock lock(m_lock); + return m_ullGlobalProcessedSize; +} + +void TTasksGlobalStats::IncreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize) +{ + boost::unique_lock lock(m_lock); + m_ullGlobalTotalSize += ullTasksSize; + m_ullGlobalProcessedSize += ullTasksPosition; +} + +void TTasksGlobalStats::DecreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize) +{ + boost::unique_lock lock(m_lock); + m_ullGlobalTotalSize -= ullTasksSize; + m_ullGlobalProcessedSize -= ullTasksPosition; +} + +int TTasksGlobalStats::GetProgressPercents() const +{ + unsigned long long llPercent = 0; + + boost::shared_lock lock(m_lock); + + if(m_ullGlobalTotalSize != 0) + llPercent = m_ullGlobalProcessedSize * 100 / m_ullGlobalTotalSize; + + return boost::numeric_cast(llPercent); +} + +void TTasksGlobalStats::IncreaseRunningTasks() +{ + boost::unique_lock lock(m_lock); + ++m_stRunningTasks; +} + +void TTasksGlobalStats::DecreaseRunningTasks() +{ + boost::unique_lock lock(m_lock); + --m_stRunningTasks; +} + +size_t TTasksGlobalStats::GetRunningTasksCount() const +{ + boost::shared_lock lock(m_lock); + return m_stRunningTasks; +} Index: src/ch/TTaskGlobalStats.h =================================================================== diff -u --- src/ch/TTaskGlobalStats.h (revision 0) +++ src/ch/TTaskGlobalStats.h (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,59 @@ +// ============================================================================ +// Copyright (C) 2001-2009 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TTaskGlobalStats.h +/// @date 2011/03/28 +/// @brief Contains declarations of classes responsible for maintaining task global stats. +// ============================================================================ +#ifndef __TTASKGLOBALSTATS_H__ +#define __TTASKGLOBALSTATS_H__ + +/////////////////////////////////////////////////////////////////////////// +// TTasksGlobalStats +class TTasksGlobalStats +{ +public: + TTasksGlobalStats(); + ~TTasksGlobalStats(); + + void IncreaseGlobalTotalSize(unsigned long long ullModify); + void DecreaseGlobalTotalSize(unsigned long long ullModify); + unsigned long long GetGlobalTotalSize() const; + + void IncreaseGlobalProcessedSize(unsigned long long ullModify); + void DecreaseGlobalProcessedSize(unsigned long long ullModify); + unsigned long long GetGlobalProcessedSize() const; + + void IncreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize); + void DecreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize); + + int GetProgressPercents() const; + + void IncreaseRunningTasks(); + void DecreaseRunningTasks(); + size_t GetRunningTasksCount() const; + +private: + volatile unsigned long long m_ullGlobalTotalSize; + volatile unsigned long long m_ullGlobalProcessedSize; + + volatile size_t m_stRunningTasks; // count of current operations + mutable boost::shared_mutex m_lock; +}; + +#endif Index: src/ch/TTaskLocalStats.cpp =================================================================== diff -u --- src/ch/TTaskLocalStats.cpp (revision 0) +++ src/ch/TTaskLocalStats.cpp (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,257 @@ +// ============================================================================ +// Copyright (C) 2001-2011 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TTaskLocalStats.cpp +/// @date 2011/03/28 +/// @brief Contains implementation of classes responsible for maintaining local task stats. +// ============================================================================ +#include "stdafx.h" +#include "TTaskLocalStats.h" +#include "TTaskGlobalStats.h" + +//////////////////////////////////////////////////////////////////////////////// +// TTasksGlobalStats members +TTaskLocalStats::TTaskLocalStats() : + m_prtGlobalStats(NULL), + m_ullProcessedSize(0), + m_ullTotalSize(0), + m_bTaskIsRunning(false), + m_timeElapsed(0), + m_timeLast(-1), + m_iCurrentBufferIndex(0) +{ +} + +TTaskLocalStats::~TTaskLocalStats() +{ + DisconnectGlobalStats(); +} + +void TTaskLocalStats::ConnectGlobalStats(TTasksGlobalStats& rtGlobalStats) +{ + DisconnectGlobalStats(); + + boost::unique_lock lock(m_lock); + + m_prtGlobalStats = &rtGlobalStats; + m_prtGlobalStats->IncreaseGlobalProgressData(m_ullProcessedSize, m_ullTotalSize); + if(m_bTaskIsRunning) + m_prtGlobalStats->IncreaseRunningTasks(); +} + +void TTaskLocalStats::DisconnectGlobalStats() +{ + boost::unique_lock lock(m_lock); + + if(m_prtGlobalStats) + { + m_prtGlobalStats->DecreaseGlobalProgressData(m_ullProcessedSize, m_ullTotalSize); + if(m_bTaskIsRunning) + m_prtGlobalStats->DecreaseRunningTasks(); + m_prtGlobalStats = NULL; + } +} + +void TTaskLocalStats::IncreaseProcessedSize(unsigned long long ullAdd) +{ + boost::unique_lock lock(m_lock); + + if(m_prtGlobalStats) + m_prtGlobalStats->IncreaseGlobalProcessedSize(ullAdd); + + m_ullProcessedSize += ullAdd; +} + +void TTaskLocalStats::DecreaseProcessedSize(unsigned long long ullSub) +{ + boost::unique_lock lock(m_lock); + if(m_prtGlobalStats) + m_prtGlobalStats->DecreaseGlobalProcessedSize(ullSub); + + m_ullProcessedSize -= ullSub; +} + +void TTaskLocalStats::SetProcessedSize(unsigned long long ullSet) +{ + boost::unique_lock lock(m_lock); + + if(m_prtGlobalStats) + { + if(ullSet < m_ullProcessedSize) + m_prtGlobalStats->DecreaseGlobalProcessedSize(m_ullProcessedSize - ullSet); + else + m_prtGlobalStats->IncreaseGlobalProcessedSize(ullSet - m_ullProcessedSize); + } + + m_ullProcessedSize = ullSet; +} + +unsigned long long TTaskLocalStats::GetProcessedSize() const +{ + boost::shared_lock lock(m_lock); + return m_ullProcessedSize; +} + +unsigned long long TTaskLocalStats::GetUnProcessedSize() const +{ + boost::shared_lock lock(m_lock); + return m_ullTotalSize - m_ullProcessedSize; +} + +void TTaskLocalStats::IncreaseTotalSize(unsigned long long ullAdd) +{ + boost::unique_lock lock(m_lock); + + if(m_prtGlobalStats) + m_prtGlobalStats->IncreaseGlobalTotalSize(ullAdd); + m_ullTotalSize += ullAdd; +} + +void TTaskLocalStats::DecreaseTotalSize(unsigned long long ullSub) +{ + boost::unique_lock lock(m_lock); + + if(m_prtGlobalStats) + m_prtGlobalStats->DecreaseGlobalTotalSize(ullSub); + + m_ullTotalSize -= ullSub; +} + +void TTaskLocalStats::SetTotalSize(unsigned long long ullSet) +{ + boost::unique_lock lock(m_lock); + + if(m_prtGlobalStats) + { + if(ullSet < m_ullTotalSize) + m_prtGlobalStats->DecreaseGlobalTotalSize(m_ullTotalSize - ullSet); + else + m_prtGlobalStats->IncreaseGlobalTotalSize(ullSet - m_ullTotalSize); + } + + m_ullTotalSize = ullSet; +} + +unsigned long long TTaskLocalStats::GetTotalSize() const +{ + boost::shared_lock lock(m_lock); + return m_ullTotalSize; +} + +int TTaskLocalStats::GetProgressInPercent() const +{ + boost::shared_lock lock(m_lock); + + unsigned long long ullPercent = 0; + + if(m_ullTotalSize != 0) + ullPercent = m_ullProcessedSize * 100 / m_ullTotalSize; + + return boost::numeric_cast(ullPercent); +} + +void TTaskLocalStats::MarkTaskAsRunning() +{ + boost::unique_lock lock(m_lock); + if(!m_bTaskIsRunning) + { + if(m_prtGlobalStats) + m_prtGlobalStats->IncreaseRunningTasks(); + m_bTaskIsRunning = true; + } +} + +void TTaskLocalStats::MarkTaskAsNotRunning() +{ + boost::unique_lock lock(m_lock); + if(m_bTaskIsRunning) + { + if(m_prtGlobalStats) + m_prtGlobalStats->DecreaseRunningTasks(); + m_bTaskIsRunning = false; + } +} + +bool TTaskLocalStats::IsRunning() const +{ + boost::shared_lock lock(m_lock); + return m_bTaskIsRunning; +} + +void TTaskLocalStats::SetTimeElapsed(time_t timeElapsed) +{ + boost::unique_lock lock(m_lock); + m_timeElapsed = timeElapsed; +} + +time_t TTaskLocalStats::GetTimeElapsed() +{ + UpdateTime(); + + boost::shared_lock lock(m_lock); + return m_timeElapsed; +} + +void TTaskLocalStats::EnableTimeTracking() +{ + boost::upgrade_lock lock(m_lock); + if(m_timeLast == -1) + { + boost::upgrade_to_unique_lock lock_upgraded(lock); + m_timeLast = time(NULL); + } +} + +void TTaskLocalStats::DisableTimeTracking() +{ + UpdateTime(); + + boost::upgrade_lock lock(m_lock); + if(m_timeLast != -1) + { + boost::upgrade_to_unique_lock lock_upgraded(lock); + m_timeLast = -1; + } +} + +void TTaskLocalStats::UpdateTime() +{ + boost::upgrade_lock lock(m_lock); + if(m_timeLast != -1) + { + time_t timeCurrent = time(NULL); + + boost::upgrade_to_unique_lock lock_upgraded(lock); + m_timeElapsed += timeCurrent - m_timeLast; + m_timeLast = timeCurrent; + } +} + +void TTaskLocalStats::SetCurrentBufferIndex(int iCurrentIndex) +{ + boost::unique_lock lock(m_lock); + m_iCurrentBufferIndex = iCurrentIndex; +} + +int TTaskLocalStats::GetCurrentBufferIndex() const +{ + // locking possibly not needed, not entirely sure now + boost::shared_lock lock(m_lock); + int iResult = m_iCurrentBufferIndex; + return iResult; +} Index: src/ch/TTaskLocalStats.h =================================================================== diff -u --- src/ch/TTaskLocalStats.h (revision 0) +++ src/ch/TTaskLocalStats.h (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -0,0 +1,80 @@ +// ============================================================================ +// Copyright (C) 2001-2011 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +/// @file TTaskLocalStats.h +/// @date 2011/03/28 +/// @brief Contains classes responsible for maintaining local task stats. +// ============================================================================ +#ifndef __TTASKLOCALSTATS_H__ +#define __TTASKLOCALSTATS_H__ + +class TTasksGlobalStats; + +class TTaskLocalStats +{ +public: + TTaskLocalStats(); + ~TTaskLocalStats(); + + void ConnectGlobalStats(TTasksGlobalStats& rtGlobalStats); + void DisconnectGlobalStats(); + + void IncreaseProcessedSize(unsigned long long ullAdd); + void DecreaseProcessedSize(unsigned long long ullSub); + void SetProcessedSize(unsigned long long ullSet); + unsigned long long GetProcessedSize() const; + unsigned long long GetUnProcessedSize() const; + + void IncreaseTotalSize(unsigned long long ullAdd); + void DecreaseTotalSize(unsigned long long ullSub); + void SetTotalSize(unsigned long long ullSet); + unsigned long long GetTotalSize() const; + + int GetProgressInPercent() const; + + void MarkTaskAsRunning(); + void MarkTaskAsNotRunning(); + bool IsRunning() const; + + void SetTimeElapsed(time_t timeElapsed); + time_t GetTimeElapsed(); + + void EnableTimeTracking(); + void DisableTimeTracking(); + void UpdateTime(); + + void SetCurrentBufferIndex(int iCurrentIndex); + int GetCurrentBufferIndex() const; + +private: + volatile unsigned long long m_ullProcessedSize; + volatile unsigned long long m_ullTotalSize; + + volatile bool m_bTaskIsRunning; + + // time + volatile time_t m_timeElapsed; + volatile time_t m_timeLast; + + volatile int m_iCurrentBufferIndex; + + mutable boost::shared_mutex m_lock; + TTasksGlobalStats* m_prtGlobalStats; +}; + +#endif Index: src/ch/TTaskProgressInfo.cpp =================================================================== diff -u -rae09c8430aad5eaa8225df84878b7d9050bdccd6 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TTaskProgressInfo.cpp (.../TTaskProgressInfo.cpp) (revision ae09c8430aad5eaa8225df84878b7d9050bdccd6) +++ src/ch/TTaskProgressInfo.cpp (.../TTaskProgressInfo.cpp) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -22,6 +22,7 @@ // ============================================================================ #include "stdafx.h" #include "TTaskProgressInfo.h" +/* /////////////////////////////////////////////////////////////////////////// // TProgressSnapshot @@ -123,3 +124,4 @@ ++m_stSubOperationIndex; } +*/ Index: src/ch/TTaskProgressInfo.h =================================================================== diff -u -rae09c8430aad5eaa8225df84878b7d9050bdccd6 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/TTaskProgressInfo.h (.../TTaskProgressInfo.h) (revision ae09c8430aad5eaa8225df84878b7d9050bdccd6) +++ src/ch/TTaskProgressInfo.h (.../TTaskProgressInfo.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -22,6 +22,7 @@ // ============================================================================ #ifndef __TTASKPROGRESSINFO_H__ #define __TTASKPROGRESSINFO_H__ +/* #include "TTaskOperationPlan.h" #include "TSubTaskProgressInfo.h" @@ -83,10 +84,10 @@ // serialization template - void load(Archive& ar, unsigned int /*uiVersion*/); + void load(Archive& ar, unsigned int / *uiVersion* /); template - void save(Archive& ar, unsigned int /*uiVersion*/) const; + void save(Archive& ar, unsigned int / *uiVersion* /) const; BOOST_SERIALIZATION_SPLIT_MEMBER(); @@ -99,7 +100,7 @@ }; template -void TTaskProgressInfo::load(Archive& ar, unsigned int /*uiVersion*/) +void TTaskProgressInfo::load(Archive& ar, unsigned int / *uiVersion* /) { boost::unique_lock lock(m_lock); @@ -113,12 +114,12 @@ } template -void TTaskProgressInfo::save(Archive& ar, unsigned int /*uiVersion*/) const +void TTaskProgressInfo::save(Archive& ar, unsigned int / *uiVersion* /) const { boost::shared_lock lock(m_lock); ar << m_vProgressInfo; ar << m_stSubOperationIndex; -} +}*/ #endif // __TTASKPROGRESSINFO_H__ \ No newline at end of file Index: src/ch/ch.vc90.vcproj =================================================================== diff -u -r3cd8d4a64a63e4fb32d7dc96e46789c713698435 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 3cd8d4a64a63e4fb32d7dc96e46789c713698435) +++ src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -479,54 +479,30 @@ > - - - - - - - - - - - - @@ -555,21 +531,89 @@ > - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lock(m_lock); - m_ullGlobalTotalSize += ullModify; -} - -void TTasksGlobalStats::DecreaseGlobalTotalSize(unsigned long long ullModify) -{ - boost::unique_lock lock(m_lock); - m_ullGlobalTotalSize -= ullModify; -} - -unsigned long long TTasksGlobalStats::GetGlobalTotalSize() const -{ - boost::shared_lock lock(m_lock); - return m_ullGlobalTotalSize; -} - -void TTasksGlobalStats::IncreaseGlobalProcessedSize(unsigned long long ullModify) -{ - boost::unique_lock lock(m_lock); - m_ullGlobalProcessedSize += ullModify; -} - -void TTasksGlobalStats::DecreaseGlobalProcessedSize(unsigned long long ullModify) -{ - boost::unique_lock lock(m_lock); - m_ullGlobalProcessedSize -= ullModify; -} - -unsigned long long TTasksGlobalStats::GetGlobalProcessedSize() const -{ - boost::shared_lock lock(m_lock); - return m_ullGlobalProcessedSize; -} - -void TTasksGlobalStats::IncreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize) -{ - boost::unique_lock lock(m_lock); - m_ullGlobalTotalSize += ullTasksSize; - m_ullGlobalProcessedSize += ullTasksPosition; -} - -void TTasksGlobalStats::DecreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize) -{ - boost::unique_lock lock(m_lock); - m_ullGlobalTotalSize -= ullTasksSize; - m_ullGlobalProcessedSize -= ullTasksPosition; -} - -int TTasksGlobalStats::GetProgressPercents() const -{ - unsigned long long llPercent = 0; - - boost::shared_lock lock(m_lock); - - if(m_ullGlobalTotalSize != 0) - llPercent = m_ullGlobalProcessedSize * 100 / m_ullGlobalTotalSize; - - return boost::numeric_cast(llPercent); -} - -void TTasksGlobalStats::IncreaseRunningTasks() -{ - boost::unique_lock lock(m_lock); - ++m_stRunningTasks; -} - -void TTasksGlobalStats::DecreaseRunningTasks() -{ - boost::unique_lock lock(m_lock); - --m_stRunningTasks; -} - -size_t TTasksGlobalStats::GetRunningTasksCount() const -{ - boost::shared_lock lock(m_lock); - return m_stRunningTasks; -} - -//////////////////////////////////////////////////////////////////////////////// -// TTasksGlobalStats members -TTaskLocalStats::TTaskLocalStats() : - m_prtGlobalStats(NULL), - m_ullProcessedSize(0), - m_ullTotalSize(0), - m_bTaskIsRunning(false), - m_timeElapsed(0), - m_timeLast(-1) -{ -} - -TTaskLocalStats::~TTaskLocalStats() -{ - DisconnectGlobalStats(); -} - -void TTaskLocalStats::ConnectGlobalStats(TTasksGlobalStats& rtGlobalStats) -{ - DisconnectGlobalStats(); - - boost::unique_lock lock(m_lock); - - m_prtGlobalStats = &rtGlobalStats; - m_prtGlobalStats->IncreaseGlobalProgressData(m_ullProcessedSize, m_ullTotalSize); - if(m_bTaskIsRunning) - m_prtGlobalStats->IncreaseRunningTasks(); -} - -void TTaskLocalStats::DisconnectGlobalStats() -{ - boost::unique_lock lock(m_lock); - - if(m_prtGlobalStats) - { - m_prtGlobalStats->DecreaseGlobalProgressData(m_ullProcessedSize, m_ullTotalSize); - if(m_bTaskIsRunning) - m_prtGlobalStats->DecreaseRunningTasks(); - m_prtGlobalStats = NULL; - } -} - -void TTaskLocalStats::IncreaseProcessedSize(unsigned long long ullAdd) -{ - boost::unique_lock lock(m_lock); - - if(m_prtGlobalStats) - m_prtGlobalStats->IncreaseGlobalProcessedSize(ullAdd); - - m_ullProcessedSize += ullAdd; -} - -void TTaskLocalStats::DecreaseProcessedSize(unsigned long long ullSub) -{ - boost::unique_lock lock(m_lock); - if(m_prtGlobalStats) - m_prtGlobalStats->DecreaseGlobalProcessedSize(ullSub); - - m_ullProcessedSize -= ullSub; -} - -void TTaskLocalStats::SetProcessedSize(unsigned long long ullSet) -{ - boost::unique_lock lock(m_lock); - - if(m_prtGlobalStats) - { - if(ullSet < m_ullProcessedSize) - m_prtGlobalStats->DecreaseGlobalProcessedSize(m_ullProcessedSize - ullSet); - else - m_prtGlobalStats->IncreaseGlobalProcessedSize(ullSet - m_ullProcessedSize); - } - - m_ullProcessedSize = ullSet; -} - -unsigned long long TTaskLocalStats::GetProcessedSize() const -{ - boost::shared_lock lock(m_lock); - return m_ullProcessedSize; -} - -unsigned long long TTaskLocalStats::GetUnProcessedSize() const -{ - boost::shared_lock lock(m_lock); - return m_ullTotalSize - m_ullProcessedSize; -} - -void TTaskLocalStats::IncreaseTotalSize(unsigned long long ullAdd) -{ - boost::unique_lock lock(m_lock); - - if(m_prtGlobalStats) - m_prtGlobalStats->IncreaseGlobalTotalSize(ullAdd); - m_ullTotalSize += ullAdd; -} - -void TTaskLocalStats::DecreaseTotalSize(unsigned long long ullSub) -{ - boost::unique_lock lock(m_lock); - - if(m_prtGlobalStats) - m_prtGlobalStats->DecreaseGlobalTotalSize(ullSub); - - m_ullTotalSize -= ullSub; -} - -void TTaskLocalStats::SetTotalSize(unsigned long long ullSet) -{ - boost::unique_lock lock(m_lock); - - if(m_prtGlobalStats) - { - if(ullSet < m_ullTotalSize) - m_prtGlobalStats->DecreaseGlobalTotalSize(m_ullTotalSize - ullSet); - else - m_prtGlobalStats->IncreaseGlobalTotalSize(ullSet - m_ullTotalSize); - } - - m_ullTotalSize = ullSet; -} - -unsigned long long TTaskLocalStats::GetTotalSize() const -{ - boost::shared_lock lock(m_lock); - return m_ullTotalSize; -} - -int TTaskLocalStats::GetProgressInPercent() const -{ - boost::shared_lock lock(m_lock); - - unsigned long long ullPercent = 0; - - if(m_ullTotalSize != 0) - ullPercent = m_ullProcessedSize * 100 / m_ullTotalSize; - - return boost::numeric_cast(ullPercent); -} - -void TTaskLocalStats::MarkTaskAsRunning() -{ - boost::unique_lock lock(m_lock); - if(!m_bTaskIsRunning) - { - if(m_prtGlobalStats) - m_prtGlobalStats->IncreaseRunningTasks(); - m_bTaskIsRunning = true; - } -} - -void TTaskLocalStats::MarkTaskAsNotRunning() -{ - boost::unique_lock lock(m_lock); - if(m_bTaskIsRunning) - { - if(m_prtGlobalStats) - m_prtGlobalStats->DecreaseRunningTasks(); - m_bTaskIsRunning = false; - } -} - -bool TTaskLocalStats::IsRunning() const -{ - boost::shared_lock lock(m_lock); - return m_bTaskIsRunning; -} - -void TTaskLocalStats::SetTimeElapsed(time_t timeElapsed) -{ - boost::unique_lock lock(m_lock); - m_timeElapsed = timeElapsed; -} - -time_t TTaskLocalStats::GetTimeElapsed() -{ - UpdateTime(); - - boost::shared_lock lock(m_lock); - return m_timeElapsed; -} - -void TTaskLocalStats::EnableTimeTracking() -{ - boost::upgrade_lock lock(m_lock); - if(m_timeLast == -1) - { - boost::upgrade_to_unique_lock lock_upgraded(lock); - m_timeLast = time(NULL); - } -} - -void TTaskLocalStats::DisableTimeTracking() -{ - UpdateTime(); - - boost::upgrade_lock lock(m_lock); - if(m_timeLast != -1) - { - boost::upgrade_to_unique_lock lock_upgraded(lock); - m_timeLast = -1; - } -} - -void TTaskLocalStats::UpdateTime() -{ - boost::upgrade_lock lock(m_lock); - if(m_timeLast != -1) - { - time_t timeCurrent = time(NULL); - - boost::upgrade_to_unique_lock lock_upgraded(lock); - m_timeElapsed += timeCurrent - m_timeLast; - m_timeLast = timeCurrent; - } -} - -TTaskBasicProgressInfo::TTaskBasicProgressInfo() : - m_stCurrentIndex(0), - m_ullCurrentFileProcessedSize(0), - m_stSubOperationIndex(0) -{ -} - -TTaskBasicProgressInfo::~TTaskBasicProgressInfo() -{ -} - -void TTaskBasicProgressInfo::SetCurrentIndex(size_t stIndex) -{ - boost::unique_lock lock(m_lock); - m_stCurrentIndex = stIndex; - m_ullCurrentFileProcessedSize = 0; -} - -void TTaskBasicProgressInfo::IncreaseCurrentIndex() -{ - boost::unique_lock lock(m_lock); - ++m_stCurrentIndex; - m_ullCurrentFileProcessedSize = 0; -} - -size_t TTaskBasicProgressInfo::GetCurrentIndex() const -{ - boost::shared_lock lock(m_lock); - return m_stCurrentIndex; -} - -void TTaskBasicProgressInfo::SetCurrentFileProcessedSize(unsigned long long ullSize) -{ - boost::unique_lock lock(m_lock); - m_ullCurrentFileProcessedSize = ullSize; -} - -unsigned long long TTaskBasicProgressInfo::GetCurrentFileProcessedSize() const -{ - boost::shared_lock lock(m_lock); - return m_ullCurrentFileProcessedSize; -} - -void TTaskBasicProgressInfo::IncreaseCurrentFileProcessedSize(unsigned long long ullSizeToAdd) -{ - boost::unique_lock lock(m_lock); - m_ullCurrentFileProcessedSize += ullSizeToAdd; -} - -void TTaskBasicProgressInfo::SetSubOperationIndex(size_t stSubOperationIndex) -{ - boost::unique_lock lock(m_lock); - m_stSubOperationIndex = stSubOperationIndex; -} - -size_t TTaskBasicProgressInfo::GetSubOperationIndex() const -{ - boost::shared_lock lock(m_lock); - return m_stSubOperationIndex; -} - -void TTaskBasicProgressInfo::IncreaseSubOperationIndex() -{ - boost::unique_lock lock(m_lock); - ++m_stSubOperationIndex; -} - //////////////////////////////////////////////////////////////////////////// // CTask members CTask::CTask(chcore::IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID) : @@ -457,59 +79,6 @@ m_localStats.DisconnectGlobalStats(); } -// m_files -int CTask::ScanDirectory(chcore::TSmartPath pathDirName, size_t stSrcIndex, bool bRecurse, bool bIncludeDirs) -{ - WIN32_FIND_DATA wfd; - chcore::TSmartPath pathCurrent; - - pathCurrent = pathDirName + chcore::PathFromString(_T("*")); - - // Iterate through dirs & files - HANDLE hFind = FindFirstFile(pathCurrent.ToString(), &wfd); - if(hFind != INVALID_HANDLE_VALUE) - { - do - { - if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - CFileInfoPtr spFileInfo(boost::make_shared()); - spFileInfo->SetClipboard(&m_tTaskDefinition.GetSourcePaths()); // this is the link table (CClipboardArray) - - spFileInfo->Create(&wfd, pathDirName, stSrcIndex); - if(m_afFilters.Match(spFileInfo)) - m_files.AddFileInfo(spFileInfo); - } - else if(wfd.cFileName[0] != _T('.') || (wfd.cFileName[1] != _T('\0') && (wfd.cFileName[1] != _T('.') || wfd.cFileName[2] != _T('\0')))) - { - if(bIncludeDirs) - { - CFileInfoPtr spFileInfo(boost::make_shared()); - spFileInfo->SetClipboard(&m_tTaskDefinition.GetSourcePaths()); // this is the link table (CClipboardArray) - - // Add directory itself - spFileInfo->Create(&wfd, pathDirName, stSrcIndex); - m_files.AddFileInfo(spFileInfo); - } - if(bRecurse) - { - pathCurrent = pathDirName + chcore::PathFromString(wfd.cFileName) + chcore::PathFromString(_T("\\")); - // Recurse Dirs - ScanDirectory(pathCurrent, stSrcIndex, bRecurse, bIncludeDirs); - } - } - - if(m_workerThread.KillRequested()) - break; - } - while(FindNextFile(hFind, &wfd)); - - FindClose(hFind); - } - - return 0; -} - void CTask::SetTaskState(ETaskCurrentState eTaskState) { // NOTE: we could check some transition rules here @@ -547,7 +116,7 @@ int CTask::GetCurrentBufferIndex() { - return GetBufferIndex(m_files.GetAt(m_tTaskBasicProgressInfo.GetCurrentIndex())); + return m_localStats.GetCurrentBufferIndex(); } // thread @@ -556,20 +125,6 @@ SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), nPriority); } -void CTask::CalculateTotalSize() -{ - unsigned long long ullTotalSize = 0; - - boost::shared_lock lock(m_lock); - size_t nSize = m_files.GetSize(); - for(size_t i = 0; i < nSize; i++) - { - ullTotalSize += m_files.GetAt(i)->GetLength64(); - } - - m_localStats.SetTotalSize(ullTotalSize); -} - void CTask::CalculateProcessedSize() { boost::shared_lock lock(m_lock); @@ -841,7 +396,7 @@ pData->m_bCreateEmptyFiles = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); if(m_files.GetSize() > 0) - pData->m_iCurrentBufferIndex = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()) ? BI_DEFAULT : GetBufferIndex(m_files.GetAt((stCurrentIndex < m_files.GetSize()) ? stCurrentIndex : 0)); + pData->m_iCurrentBufferIndex = m_localStats.GetCurrentBufferIndex(); else pData->m_iCurrentBufferIndex = BI_DEFAULT; @@ -977,31 +532,10 @@ } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool CTask::SetFileDirectoryTime(LPCTSTR lpszName, const CFileInfoPtr& spFileInfo) -{ - TAutoFileHandle hFile = CreateFile(lpszName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | (spFileInfo->IsDirectory() ? FILE_FLAG_BACKUP_SEMANTICS : 0), NULL); - if(hFile == INVALID_HANDLE_VALUE) - return false; - BOOL bResult = (!SetFileTime(hFile, &spFileInfo->GetCreationTime(), &spFileInfo->GetLastAccessTime(), &spFileInfo->GetLastWriteTime())); - - if(!hFile.Close()) - return false; - - return bResult != 0; -} - void CTask::CalculateTotalSizeNL() { - unsigned long long ullTotalSize = 0; - - size_t nSize = m_files.GetSize(); - for(size_t stIndex = 0; stIndex < nSize; stIndex++) - { - ullTotalSize += m_files.GetAt(stIndex)->GetLength64(); - } - - m_localStats.SetTotalSize(ullTotalSize); + m_localStats.SetTotalSize(m_files.CalculateTotalSize()); } void CTask::SetForceFlagNL(bool bFlag) @@ -1024,176 +558,8 @@ return m_bContinue; } -// searching for files -CTask::ESubOperationResult CTask::RecurseDirectories() -{ - // log - m_log.logi(_T("Searching for files...")); - - // delete the content of m_files - m_files.Clear(); - - // read filtering options - GetTaskPropValue(m_tTaskDefinition.GetConfiguration(), m_afFilters); - - // enter some data to m_files - int iDestDrvNumber = 0; - GetDriveData(m_tTaskDefinition.GetDestinationPath(), &iDestDrvNumber, NULL); - - bool bIgnoreDirs = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bool bForceDirectories = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bool bMove = m_tTaskDefinition.GetOperationType() == eOperation_Move; - - // add everything - ictranslate::CFormat fmt; - bool bRetry = true; - bool bSkipInputPath = false; - - size_t stSize = m_tTaskDefinition.GetSourcePathCount(); - for(size_t stIndex = 0; stIndex < stSize ; stIndex++) - { - CFileInfoPtr spFileInfo; - - bSkipInputPath = false; - - spFileInfo.reset(new CFileInfo()); - spFileInfo->SetClipboard(&m_tTaskDefinition.GetSourcePaths()); - - // try to get some info about the input path; let user know if the path does not exist. - do - { - bRetry = false; - - // read attributes of src file/folder - bool bExists = spFileInfo->Create(m_tTaskDefinition.GetSourcePathAt(stIndex), stIndex); - if(!bExists) - { - FEEDBACK_FILEERROR ferr = { m_tTaskDefinition.GetSourcePathAt(stIndex).ToString(), NULL, eFastMoveError, ERROR_FILE_NOT_FOUND }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - m_files.Clear(); - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - bRetry = true; - break; - - case CFeedbackHandler::eResult_Pause: - m_files.Clear(); - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bSkipInputPath = true; - break; // just do nothing - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - // if we have chosen to skip the input path then there's nothing to do - if(bSkipInputPath) - continue; - - // log - fmt.SetFormat(_T("Adding file/folder (clipboard) : %path ...")); - fmt.SetParam(_t("%path"), m_tTaskDefinition.GetSourcePathAt(stIndex).ToString()); - m_log.logi(fmt); - - // found file/folder - check if the dest name has been generated - if(!m_arrSourcePathsInfo.GetAt(stIndex)->IsDestinationPathSet()) - { - // generate something - if dest folder == src folder - search for copy - if(m_tTaskDefinition.GetDestinationPath() == spFileInfo->GetFullFilePath().GetFileRoot()) - { - chcore::TSmartPath pathSubst = FindFreeSubstituteName(spFileInfo->GetFullFilePath(), m_tTaskDefinition.GetDestinationPath()); - m_arrSourcePathsInfo.GetAt(stIndex)->SetDestinationPath(pathSubst); - } - else - m_arrSourcePathsInfo.GetAt(stIndex)->SetDestinationPath(spFileInfo->GetFullFilePath().GetFileName()); - } - - // add if needed - if(spFileInfo->IsDirectory()) - { - // add if folder's aren't ignored - if(!bIgnoreDirs && !bForceDirectories) - { - // add directory info; it is not to be filtered with m_afFilters - m_files.AddFileInfo(spFileInfo); - - // log - fmt.SetFormat(_T("Added folder %path")); - fmt.SetParam(_t("%path"), spFileInfo->GetFullFilePath().ToString()); - m_log.logi(fmt); - } - - // don't add folder contents when moving inside one disk boundary - if(bIgnoreDirs || !bMove || iDestDrvNumber == -1 || iDestDrvNumber != GetDriveNumber(spFileInfo) || - PathExist(GetDestinationPath(spFileInfo, m_tTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1)) ) - { - // log - fmt.SetFormat(_T("Recursing folder %path")); - fmt.SetParam(_t("%path"), spFileInfo->GetFullFilePath().ToString()); - m_log.logi(fmt); - - // no movefile possibility - use CustomCopyFileFB - m_arrSourcePathsInfo.GetAt(stIndex)->SetMove(false); - - ScanDirectory(spFileInfo->GetFullFilePath(), stIndex, true, !bIgnoreDirs || bForceDirectories); - } - - // check for kill need - if(m_workerThread.KillRequested()) - { - // log - m_log.logi(_T("Kill request while adding data to files array (RecurseDirectories)")); - m_files.Clear(); - return eSubResult_KillRequest; - } - } - else - { - if(bMove && iDestDrvNumber != -1 && iDestDrvNumber == GetDriveNumber(spFileInfo) && - !PathExist(GetDestinationPath(spFileInfo, m_tTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1)) ) - { - // if moving within one partition boundary set the file size to 0 so the overall size will - // be ok - spFileInfo->SetLength64(0); - } - else - m_arrSourcePathsInfo.GetAt(stIndex)->SetMove(false); // no MoveFile - - // add file info if passes filters - if(m_afFilters.Match(spFileInfo)) - m_files.AddFileInfo(spFileInfo); - - // log - fmt.SetFormat(_T("Added file %path")); - fmt.SetParam(_t("%path"), spFileInfo->GetFullFilePath().ToString()); - m_log.logi(fmt); - } - } - - // calc size of all files - CalculateTotalSize(); - - // save task status - Store(); - - // log - m_log.logi(_T("Searching for files finished")); - - return eSubResult_Continue; -} - // delete files - after copying -CTask::ESubOperationResult CTask::DeleteFiles() +TSubTaskBase::ESubOperationResult CTask::DeleteFiles() { // log m_log.logi(_T("Deleting files (DeleteFiles)...")); @@ -1215,7 +581,7 @@ { // log m_log.logi(_T("Kill request while deleting files (Delete Files)")); - return eSubResult_KillRequest; + return TSubTaskBase::eSubResult_KillRequest; } // current processed element @@ -1257,13 +623,13 @@ { case CFeedbackHandler::eResult_Cancel: m_log.logi(_T("Cancel request while deleting file.")); - return eSubResult_CancelRequest; + return TSubTaskBase::eSubResult_CancelRequest; case CFeedbackHandler::eResult_Retry: continue; // no stIndex bump, since we are trying again case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; + return TSubTaskBase::eSubResult_PauseRequest; case CFeedbackHandler::eResult_Skip: break; // just do nothing @@ -1286,947 +652,11 @@ // log m_log.logi(_T("Deleting files finished")); - return eSubResult_Continue; + return TSubTaskBase::eSubResult_Continue; } -CTask::ESubOperationResult CTask::OpenSourceFileFB(TAutoFileHandle& hOutFile, const CFileInfoPtr& spSrcFileInfo, bool bNoBuffering) +TSubTaskBase::ESubOperationResult CTask::CheckForWaitState() { - BOOST_ASSERT(spSrcFileInfo); - if(!spSrcFileInfo) - THROW(_T("Invalid argument"), 0, 0, 0); - - bool bRetry = false; - CString strPath = spSrcFileInfo->GetFullFilePath().ToString(); - - hOutFile = INVALID_HANDLE_VALUE; - - TAutoFileHandle hFile; - do - { - bRetry = false; - - hFile = CreateFile(strPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); - if(hFile == INVALID_HANDLE_VALUE) - { - DWORD dwLastError = GetLastError(); - - FEEDBACK_FILEERROR feedStruct = { (PCTSTR)strPath, NULL, eCreateError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); - - switch(frResult) - { - case CFeedbackHandler::eResult_Skip: - break; // will return INVALID_HANDLE_VALUE - - case CFeedbackHandler::eResult_Cancel: - { - // log - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Cancel request [error %errno] while opening source file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), strPath); - m_log.loge(fmt); - - return eSubResult_CancelRequest; - } - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Retry: - { - // log - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Retrying [error %errno] to open source file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), strPath); - m_log.loge(fmt); - - bRetry = true; - break; - } - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - hOutFile = hFile.Detach(); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::OpenDestinationFileFB(TAutoFileHandle& hOutFile, const chcore::TSmartPath& pathDstFile, bool bNoBuffering, const CFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated) -{ - bool bRetry = false; - TAutoFileHandle hFile; - - ullSeekTo = 0; - bFreshlyCreated = true; - hOutFile = INVALID_HANDLE_VALUE; - - do - { - bRetry = false; - - hFile = ::CreateFile(pathDstFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); - if(hFile == INVALID_HANDLE_VALUE) - { - DWORD dwLastError = GetLastError(); - if(dwLastError == ERROR_FILE_EXISTS) - { - bFreshlyCreated = false; - - // pass it to the specialized method - CTask::ESubOperationResult eResult = OpenExistingDestinationFileFB(hFile, pathDstFile, bNoBuffering); - if(eResult != eSubResult_Continue) - return eResult; - else if(hFile == INVALID_HANDLE_VALUE) - return eSubResult_Continue; - - // read info about the existing destination file, - // NOTE: it is not known which one would be faster - reading file parameters - // by using spDstFileInfo->Create() (which uses FindFirstFile()) or by - // reading parameters using opened handle; need to be tested in the future - CFileInfoPtr spDstFileInfo(boost::make_shared()); - if(!spDstFileInfo->Create(pathDstFile, std::numeric_limits::max())) - THROW(_T("Cannot get information about file which has already been opened!"), 0, GetLastError(), 0); - - // src and dst files are the same - FEEDBACK_ALREADYEXISTS feedStruct = { spSrcFileInfo, spDstFileInfo }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileAlreadyExists, &feedStruct); - // check for dialog result - switch(frResult) - { - case CFeedbackHandler::eResult_Overwrite: - ullSeekTo = 0; - break; - - case CFeedbackHandler::eResult_CopyRest: - ullSeekTo = spDstFileInfo->GetLength64(); - break; - - case CFeedbackHandler::eResult_Skip: - return eSubResult_Continue; - - case CFeedbackHandler::eResult_Cancel: - { - // log - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Cancel request while checking result of dialog before opening source file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%path"), pathDstFile.ToString()); - m_log.logi(fmt); - - return eSubResult_CancelRequest; - } - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - else - { - FEEDBACK_FILEERROR feedStruct = { pathDstFile.ToString(), NULL, eCreateError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); - switch (frResult) - { - case CFeedbackHandler::eResult_Retry: - { - // log - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), pathDstFile.ToString()); - m_log.loge(fmt); - - bRetry = true; - - break; - } - case CFeedbackHandler::eResult_Cancel: - { - // log - ictranslate::CFormat fmt; - - fmt.SetFormat(_T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), pathDstFile.ToString()); - m_log.loge(fmt); - - return eSubResult_CancelRequest; - } - - case CFeedbackHandler::eResult_Skip: - break; // will return invalid handle value - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - } - while(bRetry); - - hOutFile = hFile.Detach(); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::OpenExistingDestinationFileFB(TAutoFileHandle& hOutFile, const chcore::TSmartPath& pathDstFile, bool bNoBuffering) -{ - bool bRetry = false; - TAutoFileHandle hFile; - - hOutFile = INVALID_HANDLE_VALUE; - - do - { - bRetry = false; - - hFile = CreateFile(pathDstFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); - if(hFile == INVALID_HANDLE_VALUE) - { - DWORD dwLastError = GetLastError(); - FEEDBACK_FILEERROR feedStruct = { pathDstFile.ToString(), NULL, eCreateError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); - switch (frResult) - { - case CFeedbackHandler::eResult_Retry: - { - // log - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), pathDstFile.ToString()); - m_log.loge(fmt); - - bRetry = true; - - break; - } - case CFeedbackHandler::eResult_Cancel: - { - // log - ictranslate::CFormat fmt; - - fmt.SetFormat(_T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), pathDstFile.ToString()); - m_log.loge(fmt); - - return eSubResult_CancelRequest; - } - - case CFeedbackHandler::eResult_Skip: - break; // will return invalid handle value - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - hOutFile = hFile.Detach(); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::SetFilePointerFB(HANDLE hFile, long long llDistance, const chcore::TSmartPath& pathFile, bool& bSkip) -{ - bSkip = false; - bool bRetry = false; - do - { - bRetry = false; - - if(SetFilePointer64(hFile, llDistance, FILE_BEGIN) == -1) - { - DWORD dwLastError = GetLastError(); - - // log - ictranslate::CFormat fmt; - - fmt.SetFormat(_T("Error %errno while moving file pointer of %path to %pos")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), pathFile.ToString()); - fmt.SetParam(_t("%pos"), llDistance); - m_log.loge(fmt); - - FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eSeekError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - bRetry = true; - break; - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bSkip = true; - return eSubResult_Continue; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::SetEndOfFileFB(HANDLE hFile, const chcore::TSmartPath& pathFile, bool& bSkip) -{ - bSkip = false; - - bool bRetry = false; - do - { - if(!SetEndOfFile(hFile)) - { - // log - DWORD dwLastError = GetLastError(); - - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Error %errno while setting size of file %path to 0")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), pathFile.ToString()); - m_log.loge(fmt); - - FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eResizeError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - bRetry = true; - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bSkip = true; - return eSubResult_Continue; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::ReadFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const chcore::TSmartPath& pathFile, bool& bSkip) -{ - bSkip = false; - bool bRetry = false; - do - { - bRetry = false; - - if(!ReadFile(hFile, rBuffer, dwToRead, &rdwBytesRead, NULL)) - { - // log - DWORD dwLastError = GetLastError(); - - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Error %errno while trying to read %count bytes from source file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%count"), dwToRead); - fmt.SetParam(_t("%path"), pathFile.ToString()); - m_log.loge(fmt); - - FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eReadError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - bRetry = true; - break; - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bSkip = true; - return eSubResult_Continue; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::WriteFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const chcore::TSmartPath& pathFile, bool& bSkip) -{ - bSkip = false; - - bool bRetry = false; - do - { - bRetry = false; - - if(!WriteFile(hFile, rBuffer, dwToWrite, &rdwBytesWritten, NULL) || dwToWrite != rdwBytesWritten) - { - // log - DWORD dwLastError = GetLastError(); - - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Error %errno while trying to write %count bytes to destination file %path (CustomCopyFileFB)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%count"), dwToWrite); - fmt.SetParam(_t("%path"), pathFile.ToString()); - m_log.loge(fmt); - - FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eWriteError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - bRetry = true; - break; - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bSkip = true; - return eSubResult_Continue; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - } - while(bRetry); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::CustomCopyFileFB(CUSTOM_COPY_PARAMS* pData) -{ - TAutoFileHandle hSrc = INVALID_HANDLE_VALUE, - hDst = INVALID_HANDLE_VALUE; - ictranslate::CFormat fmt; - CTask::ESubOperationResult eResult = eSubResult_Continue; - bool bSkip = false; - - // calculate if we want to disable buffering for file transfer - // NOTE: we are using here the file size read when scanning directories for files; it might be - // outdated at this point, but at present we don't want to re-read file size since it - // will cost additional disk access - bool bNoBuffer = (GetTaskPropValue(m_tTaskDefinition.GetConfiguration()) && - pData->spSrcFile->GetLength64() >= GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); - - // first open the source file and handle any failures - eResult = OpenSourceFileFB(hSrc, pData->spSrcFile, bNoBuffer); - if(eResult != eSubResult_Continue) - return eResult; - else if(hSrc == INVALID_HANDLE_VALUE) - { - // invalid handle = operation skipped by user - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - // change attributes of a dest file - // NOTE: probably should be removed from here and report problems with read-only files - // directly to the user (as feedback request) - if(!GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) - SetFileAttributes(pData->pathDstFile.ToString(), FILE_ATTRIBUTE_NORMAL); - - // open destination file, handle the failures and possibly existence of the destination file - unsigned long long ullSeekTo = 0; - bool bDstFileFreshlyCreated = false; - - if(m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize() == 0) - { - // open destination file for case, when we start operation on this file (i.e. it is not resume of the - // old operation) - eResult = OpenDestinationFileFB(hDst, pData->pathDstFile, bNoBuffer, pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated); - if(eResult != eSubResult_Continue) - return eResult; - else if(hDst == INVALID_HANDLE_VALUE) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - } - else - { - // we are resuming previous operation - eResult = OpenExistingDestinationFileFB(hDst, pData->pathDstFile, bNoBuffer); - if(eResult != eSubResult_Continue) - return eResult; - else if(hDst == INVALID_HANDLE_VALUE) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - ullSeekTo = m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize(); - } - - if(!pData->bOnlyCreate) - { - // seek to the position where copying will start - 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); - - eResult = SetFilePointerFB(hSrc, ullMove, pData->spSrcFile->GetFullFilePath(), bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - eResult = SetFilePointerFB(hDst, ullMove, pData->pathDstFile, bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - // with either first or second seek we got 'skip' answer... - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - m_tTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ullMove); - m_localStats.IncreaseProcessedSize(ullMove); - } - - // 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 = SetEndOfFileFB(hDst, pData->pathDstFile, bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - pData->bProcessed = false; - return eSubResult_Continue; - } - } - - // copying - unsigned long ulToRead = 0; - unsigned long ulRead = 0; - unsigned long ulWritten = 0; - int iBufferIndex = 0; - bool bLastPart = false; - - do - { - // kill flag checks - if(m_workerThread.KillRequested()) - { - // log - fmt.SetFormat(_T("Kill request while main copying file %srcpath -> %dstpath")); - fmt.SetParam(_t("%srcpath"), pData->spSrcFile->GetFullFilePath().ToString()); - fmt.SetParam(_t("%dstpath"), pData->pathDstFile.ToString()); - m_log.logi(fmt); - return eSubResult_KillRequest; - } - - // recreate buffer if needed - if(m_cfgTracker.IsModified() && m_cfgTracker.IsModified(TOptionsSet() % eTO_DefaultBufferSize % eTO_OneDiskBufferSize % eTO_TwoDisksBufferSize % eTO_CDBufferSize % eTO_LANBufferSize % eTO_UseOnlyDefaultBuffer, true)) - { - BUFFERSIZES bs; - bs.m_bOnlyDefault = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiDefaultSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiOneDiskSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiTwoDisksSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiCDSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiLANSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - - // log - const BUFFERSIZES* pbs1 = pData->dbBuffer.GetSizes(); - - fmt.SetFormat(_T("Changing buffer size from [Def:%defsize, One:%onesize, Two:%twosize, CD:%cdsize, LAN:%lansize] to [Def:%defsize2, One:%onesize2, Two:%twosize2, CD:%cdsize2, LAN:%lansize2] wile copying %srcfile -> %dstfile (CustomCopyFileFB)")); - - fmt.SetParam(_t("%defsize"), pbs1->m_uiDefaultSize); - fmt.SetParam(_t("%onesize"), pbs1->m_uiOneDiskSize); - fmt.SetParam(_t("%twosize"), pbs1->m_uiTwoDisksSize); - fmt.SetParam(_t("%cdsize"), pbs1->m_uiCDSize); - fmt.SetParam(_t("%lansize"), pbs1->m_uiLANSize); - fmt.SetParam(_t("%defsize2"), bs.m_uiDefaultSize); - fmt.SetParam(_t("%onesize2"), bs.m_uiOneDiskSize); - fmt.SetParam(_t("%twosize2"), bs.m_uiTwoDisksSize); - fmt.SetParam(_t("%cdsize2"), bs.m_uiCDSize); - fmt.SetParam(_t("%lansize2"), bs.m_uiLANSize); - fmt.SetParam(_t("%srcfile"), pData->spSrcFile->GetFullFilePath().ToString()); - fmt.SetParam(_t("%dstfile"), pData->pathDstFile.ToString()); - - m_log.logi(fmt); - pData->dbBuffer.Create(&bs); - } - - // establish count of data to read - if(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) - iBufferIndex = BI_DEFAULT; - else - iBufferIndex = GetBufferIndex(pData->spSrcFile); - - ulToRead = bNoBuffer ? ROUNDUP(pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex], MAXSECTORSIZE) : pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex]; - - // read data from file to buffer - eResult = ReadFileFB(hSrc, pData->dbBuffer, ulToRead, ulRead, pData->spSrcFile->GetFullFilePath(), bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - if(ulRead > 0) - { - // determine if this is the last chunk of data we could get from the source file (EOF condition) - bLastPart = (ulToRead != ulRead); - - // handle not aligned part at the end of file when no buffering is enabled - if(bNoBuffer && bLastPart) - { - // 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 - - // 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(ulRead, MAXSECTORSIZE); - if(ulDataToWrite > 0) - { - eResult = WriteFileFB(hDst, pData->dbBuffer, ulDataToWrite, ulWritten, pData->pathDstFile, bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - // increase count of processed data - m_tTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulWritten); - m_localStats.IncreaseProcessedSize(ulWritten); - - // calculate count of bytes left to be written - ulRead -= ulWritten; - - // now remove part of data from buffer (ulWritten bytes) - pData->dbBuffer.CutDataFromBuffer(ulWritten); - } - - // close and re-open the destination file with buffering option for append - hDst.Close(); - - // are there any more data to be written? - if(ulRead != 0) - { - // re-open the destination file, this time with standard buffering to allow writing not aligned part of file data - eResult = OpenExistingDestinationFileFB(hDst, pData->pathDstFile, false); - if(eResult != eSubResult_Continue) - return eResult; - else if(hDst == INVALID_HANDLE_VALUE) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - // move file pointer to the end of destination file - eResult = SetFilePointerFB(hDst, m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize(), pData->pathDstFile, bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - // with either first or second seek we got 'skip' answer... - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - } - } - - // write - if(ulRead != 0) - { - eResult = WriteFileFB(hDst, pData->dbBuffer, ulRead, ulWritten, pData->pathDstFile, bSkip); - if(eResult != eSubResult_Continue) - return eResult; - else if(bSkip) - { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - pData->bProcessed = false; - return eSubResult_Continue; - } - - // increase count of processed data - m_tTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulRead); - m_localStats.IncreaseProcessedSize(ulRead); - } - } - } - while(ulRead != 0 && !bLastPart); - } - else - { - // we don't copy contents, but need to increase processed size - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); - } - - pData->bProcessed = true; - m_tTaskBasicProgressInfo.SetCurrentFileProcessedSize(0); - - return eSubResult_Continue; -} - -// function processes files/folders -CTask::ESubOperationResult CTask::ProcessFiles() -{ - // log - m_log.logi(_T("Processing files/folders (ProcessFiles)")); - - // count how much has been done (updates also a member in CTaskArray) - CalculateProcessedSize(); - - // begin at index which wasn't processed previously - size_t stSize = m_files.GetSize(); - bool bIgnoreFolders = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bool bForceDirectories = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - - // create a buffer of size m_nBufferSize - CUSTOM_COPY_PARAMS ccp; - ccp.bProcessed = false; - ccp.bOnlyCreate = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - - // remove changes in buffer sizes to avoid re-creation later - m_cfgTracker.RemoveModificationSet(TOptionsSet() % eTO_DefaultBufferSize % eTO_OneDiskBufferSize % eTO_TwoDisksBufferSize % eTO_CDBufferSize % eTO_LANBufferSize % eTO_UseOnlyDefaultBuffer); - - BUFFERSIZES bs; - bs.m_bOnlyDefault = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiDefaultSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiOneDiskSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiTwoDisksSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiCDSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - bs.m_uiLANSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - - ccp.dbBuffer.Create(&bs); - - // helpers - DWORD dwLastError = 0; - - // log - const BUFFERSIZES* pbs = ccp.dbBuffer.GetSizes(); - - ictranslate::CFormat fmt; - fmt.SetFormat(_T("Processing files/folders (ProcessFiles):\r\n\tOnlyCreate: %create\r\n\tBufferSize: [Def:%defsize, One:%onesize, Two:%twosize, CD:%cdsize, LAN:%lansize]\r\n\tFiles/folders count: %filecount\r\n\tIgnore Folders: %ignorefolders\r\n\tDest path: %dstpath\r\n\tCurrent index (0-based): %currindex")); - fmt.SetParam(_t("%create"), ccp.bOnlyCreate); - fmt.SetParam(_t("%defsize"), pbs->m_uiDefaultSize); - fmt.SetParam(_t("%onesize"), pbs->m_uiOneDiskSize); - fmt.SetParam(_t("%twosize"), pbs->m_uiTwoDisksSize); - fmt.SetParam(_t("%cdsize"), pbs->m_uiCDSize); - fmt.SetParam(_t("%lansize"), pbs->m_uiLANSize); - fmt.SetParam(_t("%filecount"), stSize); - fmt.SetParam(_t("%ignorefolders"), bIgnoreFolders); - fmt.SetParam(_t("%dstpath"), m_tTaskDefinition.GetDestinationPath().ToString()); - fmt.SetParam(_t("%currindex"), m_tTaskBasicProgressInfo.GetCurrentIndex()); - - m_log.logi(fmt); - - for(size_t stIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); stIndex < stSize; stIndex++) - { - // should we kill ? - if(m_workerThread.KillRequested()) - { - // log - m_log.logi(_T("Kill request while processing file in ProcessFiles")); - return eSubResult_KillRequest; - } - - // update m_stNextIndex, getting current CFileInfo - CFileInfoPtr spFileInfo = m_files.GetAt(m_tTaskBasicProgressInfo.GetCurrentIndex()); - - // set dest path with filename - ccp.pathDstFile = GetDestinationPath(spFileInfo, m_tTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1 | (int)bIgnoreFolders); - - // are the files/folders lie on the same partition ? - int iDstDriveNumber = 0; - bool bMove = m_tTaskDefinition.GetOperationType() == eOperation_Move; - if(bMove) - GetDriveData(m_tTaskDefinition.GetDestinationPath(), &iDstDriveNumber, NULL); - if(bMove && iDstDriveNumber != -1 && iDstDriveNumber == GetDriveNumber(spFileInfo) && GetMove(spFileInfo)) - { - bool bRetry = true; - if(bRetry && !MoveFile(spFileInfo->GetFullFilePath().ToString(), ccp.pathDstFile.ToString())) - { - dwLastError=GetLastError(); - //log - fmt.SetFormat(_T("Error %errno while calling MoveFile %srcpath -> %dstpath (ProcessFiles)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%srcpath"), spFileInfo->GetFullFilePath().ToString()); - fmt.SetParam(_t("%dstpath"), ccp.pathDstFile.ToString()); - m_log.loge(fmt); - - FEEDBACK_FILEERROR ferr = { spFileInfo->GetFullFilePath().ToString(), ccp.pathDstFile.ToString(), eFastMoveError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - continue; - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bRetry = false; - break; // just do nothing - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - else - spFileInfo->SetFlags(FIF_PROCESSED, FIF_PROCESSED); - } - else - { - // if folder - create it - if(spFileInfo->IsDirectory()) - { - bool bRetry = true; - if(bRetry && !CreateDirectory(ccp.pathDstFile.ToString(), NULL) && (dwLastError=GetLastError()) != ERROR_ALREADY_EXISTS ) - { - // log - fmt.SetFormat(_T("Error %errno while calling CreateDirectory %path (ProcessFiles)")); - fmt.SetParam(_t("%errno"), dwLastError); - fmt.SetParam(_t("%path"), ccp.pathDstFile.ToString()); - m_log.loge(fmt); - - FEEDBACK_FILEERROR ferr = { ccp.pathDstFile.ToString(), NULL, eCreateError, dwLastError }; - CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); - switch(frResult) - { - case CFeedbackHandler::eResult_Cancel: - return eSubResult_CancelRequest; - - case CFeedbackHandler::eResult_Retry: - continue; - - case CFeedbackHandler::eResult_Pause: - return eSubResult_PauseRequest; - - case CFeedbackHandler::eResult_Skip: - bRetry = false; - break; // just do nothing - default: - BOOST_ASSERT(FALSE); // unknown result - THROW(_T("Unhandled case"), 0, 0, 0); - } - } - - m_localStats.IncreaseProcessedSize(spFileInfo->GetLength64()); - spFileInfo->SetFlags(FIF_PROCESSED, FIF_PROCESSED); - } - else - { - // start copying/moving file - ccp.spSrcFile = spFileInfo; - ccp.bProcessed = false; - - // kopiuj dane - ESubOperationResult eResult = CustomCopyFileFB(&ccp); - if(eResult != eSubResult_Continue) - return eResult; - - spFileInfo->SetFlags(ccp.bProcessed ? FIF_PROCESSED : 0, FIF_PROCESSED); - - // if moving - delete file (only if config flag is set) - if(bMove && spFileInfo->GetFlags() & FIF_PROCESSED && !GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) - { - if(!GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) - SetFileAttributes(spFileInfo->GetFullFilePath().ToString(), FILE_ATTRIBUTE_NORMAL); - DeleteFile(spFileInfo->GetFullFilePath().ToString()); // there will be another try later, so I don't check - // if succeeded - } - } - - // set a time - if(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) - SetFileDirectoryTime(ccp.pathDstFile.ToString(), spFileInfo); // no error checking (but most probably it should be checked) - - // attributes - if(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) - SetFileAttributes(ccp.pathDstFile.ToString(), spFileInfo->GetAttributes()); // as above - } - - m_tTaskBasicProgressInfo.SetCurrentIndex(stIndex + 1); - } - - // delete buffer - it's not needed - ccp.dbBuffer.Delete(); - - // to look better (as 100%) - increase current index by 1 - m_tTaskBasicProgressInfo.SetCurrentIndex(stSize); - - // log - m_log.logi(_T("Finished processing in ProcessFiles")); - - return eSubResult_Continue; -} - -CTask::ESubOperationResult CTask::CheckForWaitState() -{ // limiting operation count SetTaskState(eTaskState_Waiting); bool bContinue = false; @@ -2248,14 +678,14 @@ { // log m_log.logi(_T("Kill request while waiting for begin permission (wait state)")); - return eSubResult_KillRequest; + return TSubTaskBase::eSubResult_KillRequest; } } - return eSubResult_Continue; + return TSubTaskBase::eSubResult_Continue; } -CTask::ESubOperationResult CTask::CheckForFreeSpaceFB() +TSubTaskBase::ESubOperationResult CTask::CheckForFreeSpaceFB() { ull_t ullNeededSize = 0, ullAvailableSize = 0; bool bRetry = false; @@ -2284,7 +714,7 @@ { case CFeedbackHandler::eResult_Cancel: m_log.logi(_T("Cancel request while checking for free space on disk.")); - return eSubResult_CancelRequest; + return TSubTaskBase::eSubResult_CancelRequest; case CFeedbackHandler::eResult_Retry: m_log.logi(_T("Retrying to read drive's free space...")); @@ -2293,7 +723,7 @@ case CFeedbackHandler::eResult_Ignore: m_log.logi(_T("Ignored warning about not enough place on disk to copy data.")); - return eSubResult_Continue; + return TSubTaskBase::eSubResult_Continue; default: BOOST_ASSERT(FALSE); // unknown result @@ -2304,7 +734,7 @@ } while(bRetry); - return eSubResult_Continue; + return TSubTaskBase::eSubResult_Continue; } DWORD WINAPI CTask::DelegateThreadProc(LPVOID pParam) @@ -2321,7 +751,7 @@ { try { - CTask::ESubOperationResult eResult = eSubResult_Continue; + TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; // initialize log file CString strPath = GetRelatedPath(ePathType_TaskLogFile); @@ -2350,7 +780,10 @@ // start tracking time for this thread m_localStats.EnableTimeTracking(); - for(; stSubOperationIndex < m_tTaskDefinition.GetOperationPlan().GetSubOperationsCount() && eResult == eSubResult_Continue; ++stSubOperationIndex) + // prepare context for subtasks + TSubTaskContext tSubTaskContext(m_tTaskDefinition, m_arrSourcePathsInfo, m_files, m_localStats, m_tTaskBasicProgressInfo, m_cfgTracker, m_log, m_piFeedbackHandler, m_workerThread); + + for(; stSubOperationIndex < m_tTaskDefinition.GetOperationPlan().GetSubOperationsCount() && eResult == TSubTaskBase::eSubResult_Continue; ++stSubOperationIndex) { // set current sub-operation index to allow resuming m_tTaskBasicProgressInfo.SetSubOperationIndex(stSubOperationIndex); @@ -2359,33 +792,41 @@ switch(eSubOperation) { case eSubOperation_Scanning: - // get rid of info about processed sizes - m_localStats.SetProcessedSize(0); - m_localStats.SetTotalSize(0); + { + // get rid of info about processed sizes + m_localStats.SetProcessedSize(0); + m_localStats.SetTotalSize(0); - // start searching - eResult = RecurseDirectories(); + // start searching + TSubTaskScanDirectories tSubTaskScanDir(tSubTaskContext); + //eResult = RecurseDirectories(); + eResult = tSubTaskScanDir.Exec(); - // check for free space - if(eResult == eSubResult_Continue) - eResult = CheckForFreeSpaceFB(); + // check for free space + if(eResult == TSubTaskBase::eSubResult_Continue) + eResult = CheckForFreeSpaceFB(); - // if we didn't wait for permission to start earlier, then ask now (but only in case this is the first search) - if(eResult == eSubResult_Continue && bReadTasksSize && stSubOperationIndex == 0) - { - m_localStats.DisableTimeTracking(); + // if we didn't wait for permission to start earlier, then ask now (but only in case this is the first search) + if(eResult == TSubTaskBase::eSubResult_Continue && bReadTasksSize && stSubOperationIndex == 0) + { + m_localStats.DisableTimeTracking(); - eResult = CheckForWaitState(); + eResult = CheckForWaitState(); - m_localStats.EnableTimeTracking(); - } + m_localStats.EnableTimeTracking(); + } - break; + break; + } case eSubOperation_Copying: - eResult = ProcessFiles(); - break; + { + TSubTaskCopyMove tSubTaskCopyMove(tSubTaskContext); + eResult = tSubTaskCopyMove.Exec(); + break; + } + case eSubOperation_Deleting: eResult = DeleteFiles(); break; @@ -2403,26 +844,26 @@ // change task status switch(eResult) { - case eSubResult_Error: + case TSubTaskBase::eSubResult_Error: m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_OperationError, NULL); SetTaskState(eTaskState_Error); break; - case eSubResult_CancelRequest: + case TSubTaskBase::eSubResult_CancelRequest: SetTaskState(eTaskState_Cancelled); break; - case eSubResult_PauseRequest: + case TSubTaskBase::eSubResult_PauseRequest: SetTaskState(eTaskState_Paused); break; - case eSubResult_KillRequest: + case TSubTaskBase::eSubResult_KillRequest: // the only operation if(GetTaskState() == eTaskState_Waiting) SetTaskState(eTaskState_Processing); break; - case eSubResult_Continue: + case TSubTaskBase::eSubResult_Continue: m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_OperationFinished, NULL); SetTaskState(eTaskState_Finished); break; @@ -2572,220 +1013,6 @@ } } -// finds another name for a copy of src file(folder) in dest location -chcore::TSmartPath CTask::FindFreeSubstituteName(chcore::TSmartPath pathSrcPath, chcore::TSmartPath pathDstPath) const -{ - // get the name from srcpath - pathSrcPath.StripSeparatorAtEnd(); - - chcore::TSmartPath pathFilename = pathSrcPath.GetFileName(); - - // set the dest path - CString strCheckPath; - ictranslate::CFormat fmt(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); - fmt.SetParam(_t("%name"), pathFilename.ToString()); - chcore::TSmartPath pathCheckPath(chcore::PathFromString((PCTSTR)fmt)); - - // when adding to strDstPath check if the path already exists - if so - try again - int iCounter=1; - CString strFmt = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); - while(PathExist(pathDstPath + pathCheckPath)) - { - fmt.SetFormat(strFmt); - fmt.SetParam(_t("%name"), pathFilename.ToString()); - fmt.SetParam(_t("%count"), ++iCounter); - pathCheckPath.FromString((PCTSTR)fmt); - } - - return pathCheckPath; -} - -chcore::TSmartPath CTask::GetDestinationPath(const CFileInfoPtr& spFileInfo, chcore::TSmartPath pathDst, int iFlags) const -{ - if(!spFileInfo) - THROW(_T("Invalid pointer"), 0, 0, 0); - - // iFlags: bit 0-ignore folders; bit 1-force creating directories - if (iFlags & 0x02) - { - // force create directories - chcore::TSmartPath pathCombined = pathDst + spFileInfo->GetFullFilePath().GetFileDir(); - - // force create directory - SHCreateDirectoryEx(NULL, pathCombined.ToString(), NULL); - - return pathCombined + spFileInfo->GetFullFilePath().GetFileName(); - } - else - { - size_t stSrcIndex = spFileInfo->GetSrcIndex(); - - if (!(iFlags & 0x01) && stSrcIndex != std::numeric_limits::max()) - { - // generate new dest name - if(!m_arrSourcePathsInfo.GetAt(stSrcIndex)->IsDestinationPathSet()) - { - chcore::TSmartPath pathSubst = FindFreeSubstituteName(spFileInfo->GetFullFilePath(), pathDst); - m_arrSourcePathsInfo.GetAt(stSrcIndex)->SetDestinationPath(pathSubst); - } - - return pathDst + m_arrSourcePathsInfo.GetAt(stSrcIndex)->GetDestinationPath() + spFileInfo->GetFilePath(); - } - else - return pathDst + spFileInfo->GetFullFilePath().GetFileName(); - } -} - -int CTask::GetBufferIndex(const CFileInfoPtr& spFileInfo) -{ - if(!spFileInfo) - THROW(_T("Invalid pointer"), 0, 0, 0); - if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) - THROW(_T("Received non-relative (standalone) path info"), 0, 0, 0); - - // check if this information has already been stored - size_t stBaseIndex = spFileInfo->GetSrcIndex(); - if(stBaseIndex >= m_arrSourcePathsInfo.GetCount()) - THROW(_T("Index out of bounds"), 0, 0, 0); - - TBasePathDataPtr spPathData = m_arrSourcePathsInfo.GetAt(stBaseIndex); - if(spPathData->IsBufferIndexSet()) - return spPathData->GetBufferIndex(); - - // buffer index wasn't cached previously - read it now - int iDriveNumber = 0; - UINT uiDriveType = 0; - int iDstDriveNumber = 0; - UINT uiDstDriveType = 0; - GetDriveData(m_tTaskDefinition.GetSourcePathAt(stBaseIndex), &iDriveNumber, &uiDriveType); - GetDriveData(m_tTaskDefinition.GetDestinationPath(), &iDstDriveNumber, &uiDstDriveType); - - // what kind of buffer - int iBufferIndex = BI_DEFAULT; - if(uiDriveType == DRIVE_REMOTE || uiDstDriveType == DRIVE_REMOTE) - iBufferIndex = BI_LAN; - else if(uiDriveType == DRIVE_CDROM || uiDstDriveType == DRIVE_CDROM) - iBufferIndex = BI_CD; - else if(uiDriveType == DRIVE_FIXED && uiDstDriveType == DRIVE_FIXED) - { - // two hdd's - is this the same physical disk ? - if(iDriveNumber == iDstDriveNumber || IsSamePhysicalDisk(iDriveNumber, iDstDriveNumber)) - iBufferIndex = BI_ONEDISK; - else - iBufferIndex = BI_TWODISKS; - } - else - iBufferIndex = BI_DEFAULT; - - spPathData->SetBufferIndex(iBufferIndex); - - return iBufferIndex; -} - -int CTask::GetDriveNumber(const CFileInfoPtr& spFileInfo) -{ - if(!spFileInfo) - THROW(_T("Invalid pointer"), 0, 0, 0); - if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) - THROW(_T("Received non-relative (standalone) path info"), 0, 0, 0); - - // check if this information has already been stored - size_t stBaseIndex = spFileInfo->GetSrcIndex(); - if(stBaseIndex >= m_arrSourcePathsInfo.GetCount()) - THROW(_T("Index out of bounds"), 0, 0, 0); - - TBasePathDataPtr spPathData = m_arrSourcePathsInfo.GetAt(stBaseIndex); - if(spPathData->IsDriveNumberSet()) - return spPathData->GetDriveNumber(); - - // buffer index wasn't cached previously - read it now - int iDriveNumber = 0; - GetDriveData(m_tTaskDefinition.GetSourcePathAt(stBaseIndex), &iDriveNumber, NULL); - - spPathData->SetDriveNumber(iDriveNumber); - - return iDriveNumber; -} - -bool CTask::GetMove(const CFileInfoPtr& spFileInfo) -{ - if(!spFileInfo) - THROW(_T("Invalid pointer"), 0, 0, 0); - if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) - THROW(_T("Received non-relative (standalone) path info"), 0, 0, 0); - - // check if this information has already been stored - size_t stBaseIndex = spFileInfo->GetSrcIndex(); - if(stBaseIndex >= m_arrSourcePathsInfo.GetCount()) - THROW(_T("Index out of bounds"), 0, 0, 0); - - TBasePathDataPtr spPathData = m_arrSourcePathsInfo.GetAt(stBaseIndex); - return spPathData->GetMove(); -} - -void CTask::GetDriveData(const chcore::TSmartPath& spPath, int* piDrvNum, UINT* puiDrvType) -{ - TCHAR drv[_MAX_DRIVE+1]; - - _tsplitpath(spPath.ToString(), drv, NULL, NULL, NULL); - if(lstrlen(drv) != 0) - { - // add '\\' - lstrcat(drv, _T("\\")); - _tcsupr(drv); - - // disk number - if(piDrvNum) - *piDrvNum=drv[0]-_T('A'); - - // disk type - if(puiDrvType) - { - *puiDrvType=GetDriveType(drv); - if(*puiDrvType == DRIVE_NO_ROOT_DIR) - *puiDrvType=DRIVE_UNKNOWN; - } - } - else - { - // there's no disk in a path - if(piDrvNum) - *piDrvNum=-1; - - if(puiDrvType) - { - // check for unc path - if(_tcsncmp(spPath.ToString(), _T("\\\\"), 2) == 0) - *puiDrvType=DRIVE_REMOTE; - else - *puiDrvType=DRIVE_UNKNOWN; - } - } -} - -bool CTask::PathExist(chcore::TSmartPath pathToCheck) -{ - WIN32_FIND_DATA fd; - - // search by exact name - HANDLE hFind = FindFirstFile(pathToCheck.ToString(), &fd); - if(hFind != INVALID_HANDLE_VALUE) - return true; - - // another try (add '\\' if needed and '*' for marking that we look for ie. c:\* - // instead of c:\, which would never be found prev. way) - pathToCheck.AppendIfNotExists(_T("*"), false); - - hFind = FindFirstFile(pathToCheck.ToString(), &fd); - if(hFind != INVALID_HANDLE_VALUE) - { - ::FindClose(hFind); - return true; - } - else - return false; -} - //////////////////////////////////////////////////////////////////////////////// // CTaskArray members CTaskArray::CTaskArray() : Index: src/ch/task.h =================================================================== diff -u -rb684bec49aaaea4b89ab2e599497f4085d8698a3 -r8c87d4185fbe5b952c49f72afcfd5f9fca338fb4 --- src/ch/task.h (.../task.h) (revision b684bec49aaaea4b89ab2e599497f4085d8698a3) +++ src/ch/task.h (.../task.h) (revision 8c87d4185fbe5b952c49f72afcfd5f9fca338fb4) @@ -28,6 +28,10 @@ #include "TTaskDefinition.h" #include "TTaskConfigTracker.h" #include "TBasePathData.h" +#include "TSubTaskBase.h" +#include "TTaskLocalStats.h" +#include "TTaskGlobalStats.h" +#include "TBasicProgressInfo.h" // enum representing current processing state of the task enum ETaskCurrentState @@ -88,180 +92,11 @@ int m_nPercent; }; -struct CUSTOM_COPY_PARAMS -{ - CFileInfoPtr spSrcFile; // CFileInfo - src file - chcore::TSmartPath pathDstFile; // dest path with filename - - CDataBuffer dbBuffer; // buffer handling - bool bOnlyCreate; // flag from configuration - skips real copying - only create - bool bProcessed; // has the element been processed ? (false if skipped) -}; - /////////////////////////////////////////////////////////////////////////// -// TTasksGlobalStats -class TTasksGlobalStats -{ -public: - TTasksGlobalStats(); - ~TTasksGlobalStats(); - - void IncreaseGlobalTotalSize(unsigned long long ullModify); - void DecreaseGlobalTotalSize(unsigned long long ullModify); - unsigned long long GetGlobalTotalSize() const; - - void IncreaseGlobalProcessedSize(unsigned long long ullModify); - void DecreaseGlobalProcessedSize(unsigned long long ullModify); - unsigned long long GetGlobalProcessedSize() const; - - void IncreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize); - void DecreaseGlobalProgressData(unsigned long long ullTasksPosition, unsigned long long ullTasksSize); - - int GetProgressPercents() const; - - void IncreaseRunningTasks(); - void DecreaseRunningTasks(); - size_t GetRunningTasksCount() const; - -private: - volatile unsigned long long m_ullGlobalTotalSize; - volatile unsigned long long m_ullGlobalProcessedSize; - - volatile size_t m_stRunningTasks; // count of current operations - mutable boost::shared_mutex m_lock; -}; - -/////////////////////////////////////////////////////////////////////////// -// TTaskLocalStats -class TTaskLocalStats -{ -public: - TTaskLocalStats(); - ~TTaskLocalStats(); - - void ConnectGlobalStats(TTasksGlobalStats& rtGlobalStats); - void DisconnectGlobalStats(); - - void IncreaseProcessedSize(unsigned long long ullAdd); - void DecreaseProcessedSize(unsigned long long ullSub); - void SetProcessedSize(unsigned long long ullSet); - unsigned long long GetProcessedSize() const; - unsigned long long GetUnProcessedSize() const; - - void IncreaseTotalSize(unsigned long long ullAdd); - void DecreaseTotalSize(unsigned long long ullSub); - void SetTotalSize(unsigned long long ullSet); - unsigned long long GetTotalSize() const; - - int GetProgressInPercent() const; - - void MarkTaskAsRunning(); - void MarkTaskAsNotRunning(); - bool IsRunning() const; - - void SetTimeElapsed(time_t timeElapsed); - time_t GetTimeElapsed(); - - void EnableTimeTracking(); - void DisableTimeTracking(); - void UpdateTime(); - -private: - volatile unsigned long long m_ullProcessedSize; - volatile unsigned long long m_ullTotalSize; - - volatile bool m_bTaskIsRunning; - - // time - volatile time_t m_timeElapsed; - volatile time_t m_timeLast; - - mutable boost::shared_mutex m_lock; - TTasksGlobalStats* m_prtGlobalStats; -}; - -/////////////////////////////////////////////////////////////////////////// -// TTaskBasicProgressInfo - -class TTaskBasicProgressInfo -{ -public: - TTaskBasicProgressInfo(); - ~TTaskBasicProgressInfo(); - - void SetCurrentIndex(size_t stIndex); // might be unneeded when serialization is implemented - void IncreaseCurrentIndex(); - size_t GetCurrentIndex() const; - - void SetCurrentFileProcessedSize(unsigned long long ullSize); - unsigned long long GetCurrentFileProcessedSize() const; - void IncreaseCurrentFileProcessedSize(unsigned long long ullSizeToAdd); - - void SetSubOperationIndex(size_t stSubOperationIndex); - size_t GetSubOperationIndex() const; - void IncreaseSubOperationIndex(); - - template - void load(Archive& ar, unsigned int /*uiVersion*/) - { - size_t stCurrentIndex = 0; - ar >> stCurrentIndex; - - unsigned long long ullCurrentFileProcessedSize = 0; - ar >> ullCurrentFileProcessedSize; - - size_t stSubOperationIndex = 0; - ar >> stSubOperationIndex; - - boost::unique_lock lock(m_lock); - - m_stCurrentIndex = stCurrentIndex; - m_ullCurrentFileProcessedSize = ullCurrentFileProcessedSize; - m_stSubOperationIndex = stSubOperationIndex; - } - - template - void save(Archive& ar, unsigned int /*uiVersion*/) const - { - m_lock.lock_shared(); - - size_t stCurrentIndex = m_stCurrentIndex; - unsigned long long ullCurrentFileProcessedSize = m_ullCurrentFileProcessedSize; - size_t stSubOperationIndex = m_stSubOperationIndex; - - m_lock.unlock_shared(); - - ar << stCurrentIndex; - ar << ullCurrentFileProcessedSize; - ar << stSubOperationIndex; - } - - BOOST_SERIALIZATION_SPLIT_MEMBER(); - -private: - volatile size_t m_stSubOperationIndex; // index of sub-operation from TOperationDescription - volatile size_t m_stCurrentIndex; // index to the m_files array stating currently processed item - volatile unsigned long long m_ullCurrentFileProcessedSize; // count of bytes processed for current file - - mutable boost::shared_mutex m_lock; -}; - -/////////////////////////////////////////////////////////////////////////// // CTask class CTask { -protected: - // enum using internally by the CTask class to pass the operation results between methods - enum ESubOperationResult - { - eSubResult_Continue, - eSubResult_KillRequest, - eSubResult_Error, - eSubResult_CancelRequest, - eSubResult_PauseRequest - }; - public: enum EPathType { @@ -336,41 +171,22 @@ /// Main function for the task processing thread DWORD WINAPI ThrdProc(); - ESubOperationResult RecurseDirectories(); - int ScanDirectory(chcore::TSmartPath pathDirName, size_t stSrcIndex, bool bRecurse, bool bIncludeDirs); + TSubTaskBase::ESubOperationResult DeleteFiles(); - ESubOperationResult ProcessFiles(); - ESubOperationResult CustomCopyFileFB(CUSTOM_COPY_PARAMS* pData); + TSubTaskBase::ESubOperationResult CheckForWaitState(); - ESubOperationResult DeleteFiles(); - - ESubOperationResult CheckForWaitState(); - // Helper filesystem methods - static bool SetFileDirectoryTime(LPCTSTR lpszName, const CFileInfoPtr& spFileInfo); - bool GetRequiredFreeSpace(ull_t *pi64Needed, ull_t *pi64Available); - ESubOperationResult OpenSourceFileFB(TAutoFileHandle& hFile, const CFileInfoPtr& spSrcFileInfo, bool bNoBuffering); - ESubOperationResult OpenDestinationFileFB(TAutoFileHandle& hFile, const chcore::TSmartPath& pathDstFile, bool bNoBuffering, const CFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated); - ESubOperationResult OpenExistingDestinationFileFB(TAutoFileHandle& hFile, const chcore::TSmartPath& pathDstFilePath, bool bNoBuffering); + TSubTaskBase::ESubOperationResult CheckForFreeSpaceFB(); - ESubOperationResult SetFilePointerFB(HANDLE hFile, long long llDistance, const chcore::TSmartPath& pathFile, bool& bSkip); - ESubOperationResult SetEndOfFileFB(HANDLE hFile, const chcore::TSmartPath& pathFile, bool& bSkip); - - ESubOperationResult ReadFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const chcore::TSmartPath& pathFile, bool& bSkip); - ESubOperationResult WriteFileFB(HANDLE hFile, CDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const chcore::TSmartPath& pathFile, bool& bSkip); - - ESubOperationResult CheckForFreeSpaceFB(); - // m_nStatus void SetStatusNL(UINT nStatus, UINT nMask); UINT GetStatusNL(UINT nMask = 0xffffffff); void CalculateProcessedSize(); void CalculateProcessedSizeNL(); - void CalculateTotalSize(); void CalculateTotalSizeNL(); void DeleteProgress(); @@ -392,16 +208,6 @@ static void OnCfgOptionChanged(const std::set& rsetChanges, void* pParam); - chcore::TSmartPath FindFreeSubstituteName(chcore::TSmartPath pathSrcPath, chcore::TSmartPath pathDstPath) const; - chcore::TSmartPath GetDestinationPath(const CFileInfoPtr& spFileInfo, chcore::TSmartPath strPath, int iFlags) const; - - int GetBufferIndex(const CFileInfoPtr& spFileInfo); - int GetDriveNumber(const CFileInfoPtr& spFileInfo); - bool GetMove(const CFileInfoPtr& spFileInfo); - - static void GetDriveData(const chcore::TSmartPath& spPath, int *piDrvNum, UINT *puiDrvType); - static bool PathExist(chcore::TSmartPath strPath); // check for file or folder existence - private: // task initial information (needed to start a task); might be a bit processed. TTaskDefinition m_tTaskDefinition;