Index: src/ch/FeedbackHandler.cpp =================================================================== diff -u -rd12e49decb8a3df3e28f6786d38542390484ac07 -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/ch/FeedbackHandler.cpp (.../FeedbackHandler.cpp) (revision d12e49decb8a3df3e28f6786d38542390484ac07) +++ src/ch/FeedbackHandler.cpp (.../FeedbackHandler.cpp) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -57,7 +57,7 @@ if(!pFeedbackParam) return eResult_Unknown; - FEEDBACK_ALREADYEXISTS* pData = (FEEDBACK_ALREADYEXISTS*)pFeedbackParam; + chcore::FEEDBACK_ALREADYEXISTS* pData = (chcore::FEEDBACK_ALREADYEXISTS*)pFeedbackParam; CFeedbackReplaceDlg dlg(pData->spSrcFileInfo, pData->spDstFileInfo); eFeedbackResult = (EFeedbackResult)dlg.DoModal(); bUseForAllItems = dlg.m_bAllItems; @@ -70,7 +70,7 @@ if(!pFeedbackParam) return eResult_Unknown; - FEEDBACK_FILEERROR* pData = (FEEDBACK_FILEERROR*)pFeedbackParam; + chcore::FEEDBACK_FILEERROR* pData = (chcore::FEEDBACK_FILEERROR*)pFeedbackParam; CFeedbackFileErrorDlg dlg(pData->pszSrcPath, pData->pszDstPath, pData->ulError); eFeedbackResult = (EFeedbackResult)dlg.DoModal(); bUseForAllItems = dlg.m_bAllItems; @@ -83,7 +83,7 @@ if(!pFeedbackParam) return eResult_Unknown; - FEEDBACK_NOTENOUGHSPACE* pData = (FEEDBACK_NOTENOUGHSPACE*)pFeedbackParam; + chcore::FEEDBACK_NOTENOUGHSPACE* pData = (chcore::FEEDBACK_NOTENOUGHSPACE*)pFeedbackParam; CFeedbackNotEnoughSpaceDlg dlg(pData->ullRequiredSize, pData->pszSrcPath, pData->pszDstPath); eFeedbackResult = (EFeedbackResult)dlg.DoModal(); bUseForAllItems = dlg.m_bAllItems; Index: src/ch/FeedbackHandler.h =================================================================== diff -u -r2aea3ad6f3c68be709ac65c70d9646eafe3b034c -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/ch/FeedbackHandler.h (.../FeedbackHandler.h) (revision 2aea3ad6f3c68be709ac65c70d9646eafe3b034c) +++ src/ch/FeedbackHandler.h (.../FeedbackHandler.h) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -21,55 +21,8 @@ #include "../libchcore/FeedbackHandlerBase.h" -struct FEEDBACK_ALREADYEXISTS -{ - chcore::TFileInfoPtr spSrcFileInfo; - chcore::TFileInfoPtr spDstFileInfo; -}; - -struct FEEDBACK_FILEERROR -{ - const tchar_t* pszSrcPath; - const tchar_t* pszDstPath; - EFileError eFileError; // error type - ulong_t ulError; // system error -}; - -struct FEEDBACK_NOTENOUGHSPACE -{ - ull_t ullRequiredSize; - const tchar_t* pszSrcPath; - const tchar_t* pszDstPath; -}; - class CFeedbackHandler : public chcore::IFeedbackHandler { -public: - enum EFeedbackType - { - eFT_Unknown = 0, - // requests for use feedback - eFT_FileAlreadyExists, - eFT_FileError, - eFT_NotEnoughSpace, - // notifications - eFT_OperationFinished, ///< Task has finished processing - eFT_OperationError, ///< Error encountered while processing task - eFT_LastType - }; - - enum EFeedbackResult - { - eResult_Unknown = 0, - eResult_Overwrite, - eResult_CopyRest, - eResult_Skip, - eResult_Cancel, - eResult_Pause, - eResult_Retry, - eResult_Ignore - }; - protected: CFeedbackHandler(); ~CFeedbackHandler(); Fisheye: Tag 4d20d0e58f37f06ac91287015b960308db54d47e refers to a dead (removed) revision in file `src/ch/TSubTaskContext.h'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 4d20d0e58f37f06ac91287015b960308db54d47e refers to a dead (removed) revision in file `src/ch/TSubTaskCopyMove.h'. Fisheye: No comparison available. Pass `N' to diff? Index: src/ch/ch.vc90.vcproj =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -434,14 +434,6 @@ RelativePath=".\task.h" > - - - - @@ -462,42 +454,6 @@ > - - - - - - - - - - - - - - - - - - RequestFeedback(CFeedbackHandler::eFT_OperationError, NULL); SetTaskState(eTaskState_Error); break; - case TSubTaskBase::eSubResult_CancelRequest: + case chcore::TSubTaskBase::eSubResult_CancelRequest: SetTaskState(eTaskState_Cancelled); break; - case TSubTaskBase::eSubResult_PauseRequest: + case chcore::TSubTaskBase::eSubResult_PauseRequest: SetTaskState(eTaskState_Paused); break; - case TSubTaskBase::eSubResult_KillRequest: + case chcore::TSubTaskBase::eSubResult_KillRequest: // the only operation if(GetTaskState() == eTaskState_Waiting) SetTaskState(eTaskState_Processing); break; - case TSubTaskBase::eSubResult_Continue: + case chcore::TSubTaskBase::eSubResult_Continue: m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_OperationFinished, NULL); SetTaskState(eTaskState_Finished); break; Index: src/ch/task.h =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/ch/task.h (.../task.h) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/ch/task.h (.../task.h) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -28,7 +28,7 @@ #include "../libchcore/TTaskDefinition.h" #include "../libchcore/TTaskConfigTracker.h" #include "../libchcore/TBasePathData.h" -#include "TSubTaskBase.h" +#include "../libchcore/TSubTaskBase.h" #include "../libchcore/TTaskLocalStats.h" #include "../libchcore/TTaskGlobalStats.h" #include "../libchcore/TBasicProgressInfo.h" @@ -174,7 +174,7 @@ /// Main function for the task processing thread DWORD WINAPI ThrdProc(); - TSubTaskBase::ESubOperationResult CheckForWaitState(); + chcore::TSubTaskBase::ESubOperationResult CheckForWaitState(); // m_nStatus void SetStatusNL(UINT nStatus, UINT nMask); Index: src/libchcore/ErrorCodes.h =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/libchcore/ErrorCodes.h (.../ErrorCodes.h) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/libchcore/ErrorCodes.h (.../ErrorCodes.h) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -69,6 +69,7 @@ // Filesystem errors eErr_FixedDriveWithoutDriveLetter = 3000, + eErr_CannotGetFileInfo = 3001, }; END_CHCORE_NAMESPACE Index: src/libchcore/FeedbackHandlerBase.h =================================================================== diff -u -rd5c3edd0d167db9b5d47d04248820fda49499a5e -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/libchcore/FeedbackHandlerBase.h (.../FeedbackHandlerBase.h) (revision d5c3edd0d167db9b5d47d04248820fda49499a5e) +++ src/libchcore/FeedbackHandlerBase.h (.../FeedbackHandlerBase.h) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -21,12 +21,60 @@ #include "libchcore.h" #include "../libicpf/interface.h" +#include "../common/ErrorConstants.h" BEGIN_CHCORE_NAMESPACE +struct FEEDBACK_ALREADYEXISTS +{ + chcore::TFileInfoPtr spSrcFileInfo; + chcore::TFileInfoPtr spDstFileInfo; +}; + +struct FEEDBACK_FILEERROR +{ + const wchar_t* pszSrcPath; + const wchar_t* pszDstPath; + EFileError eFileError; // error type + ulong_t ulError; // system error +}; + +struct FEEDBACK_NOTENOUGHSPACE +{ + ull_t ullRequiredSize; + const wchar_t* pszSrcPath; + const wchar_t* pszDstPath; +}; + class IFeedbackHandler : public icpf::IInterface { public: + enum EFeedbackType + { + eFT_Unknown = 0, + // requests for use feedback + eFT_FileAlreadyExists, + eFT_FileError, + eFT_NotEnoughSpace, + // notifications + eFT_OperationFinished, ///< Task has finished processing + eFT_OperationError, ///< Error encountered while processing task + eFT_LastType + }; + + enum EFeedbackResult + { + eResult_Unknown = 0, + eResult_Overwrite, + eResult_CopyRest, + eResult_Skip, + eResult_Cancel, + eResult_Pause, + eResult_Retry, + eResult_Ignore + }; + +public: virtual ull_t RequestFeedback(ull_t ullFeedbackID, ptr_t pFeedbackParam) = 0; }; Index: src/libchcore/TSubTaskBase.cpp =================================================================== diff -u --- src/libchcore/TSubTaskBase.cpp (revision 0) +++ src/libchcore/TSubTaskBase.cpp (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -0,0 +1,113 @@ +// ============================================================================ +// 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 TSubTaskBase.cpp +/// @date 2010/09/19 +/// @brief Contains implementation of some common subtask elements. +// ============================================================================ +#include "stdafx.h" +#include "TSubTaskBase.h" +#include "TBasePathData.h" +#include "TLocalFilesystem.h" +#include "TSubTaskContext.h" +#include "TTaskDefinition.h" +#include "TTaskConfiguration.h" +#include + +BEGIN_CHCORE_NAMESPACE + +/////////////////////////////////////////////////////////////////////////// +// TSubTaskBase + +TSubTaskBase::TSubTaskBase(TSubTaskContext& rContext) : +m_rContext(rContext) +{ +} + +TSubTaskBase::~TSubTaskBase() +{ +} + +TSmartPath TSubTaskBase::CalculateDestinationPath(const TFileInfoPtr& spFileInfo, TSmartPath pathDst, int iFlags) const +{ + const TBasePathDataContainer& rSourcePathsInfo = GetContext().GetBasePathDataContainer(); + + if(!spFileInfo) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + // iFlags: bit 0-ignore folders; bit 1-force creating directories + if(iFlags & 0x02) + { + // force create directories + TSmartPath pathCombined = pathDst + spFileInfo->GetFullFilePath().GetFileDir(); + + // force create directory + TLocalFilesystem::CreateDirectory(pathCombined, true); + + 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()) + { + 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 +TSmartPath TSubTaskBase::FindFreeSubstituteName(TSmartPath pathSrcPath, TSmartPath pathDstPath) const +{ + const TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + + // get the name from src path + pathSrcPath.StripSeparatorAtEnd(); + + TSmartPath pathFilename = pathSrcPath.GetFileName(); + + // set the dest path + TString strCheckPath = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + strCheckPath.Replace(_T("%name"), pathFilename.ToString()); + TSmartPath pathCheckPath(PathFromString(strCheckPath)); + + // when adding to strDstPath check if the path already exists - if so - try again + int iCounter = 1; + TString strFmt = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + while(TLocalFilesystem::PathExist(pathDstPath + pathCheckPath)) + { + strCheckPath = strFmt; + strCheckPath.Replace(_t("%name"), pathFilename.ToString()); + strCheckPath.Replace(_t("%count"), boost::lexical_cast(++iCounter).c_str()); + pathCheckPath.FromString(strCheckPath); + } + + return pathCheckPath; +} + +END_CHCORE_NAMESPACE Fisheye: tag 2aea3ad6f3c68be709ac65c70d9646eafe3b034c is not in file src/libchcore/TSubTaskBase.h Fisheye: Tag 4d20d0e58f37f06ac91287015b960308db54d47e refers to a dead (removed) revision in file `src/ch/TSubTaskBase.h'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: tag fb4c4006dee5aaf815d08bc3e89312445b994307 is not in file src/libchcore/TSubTaskContext.cpp Fisheye: Tag 4d20d0e58f37f06ac91287015b960308db54d47e refers to a dead (removed) revision in file `src/ch/TSubTaskContext.cpp'. Fisheye: No comparison available. Pass `N' to diff? Index: src/libchcore/TSubTaskContext.h =================================================================== diff -u --- src/libchcore/TSubTaskContext.h (revision 0) +++ src/libchcore/TSubTaskContext.h (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -0,0 +1,121 @@ +// ============================================================================ +// 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 TSubTaskContext.h +/// @date 2010/09/19 +/// @brief Contains declaration of subtask context class. +// ============================================================================ +#ifndef __TSUBTASKCONTEXT_H__ +#define __TSUBTASKCONTEXT_H__ + +#include "libchcore.h" + +namespace icpf +{ + class log_file; +} + +BEGIN_CHCORE_NAMESPACE + +class IFeedbackHandler; +class TTaskDefinition; +class TWorkerThreadController; +class TBasePathDataContainer; +class TTaskConfigTracker; +class TLocalFilesystem; +class TTaskLocalStats; +class TTaskBasicProgressInfo; +class TFileInfoArray; + +/////////////////////////////////////////////////////////////////////////// +// TSubTaskContext + +class LIBCHCORE_API TSubTaskContext +{ +public: + TSubTaskContext(TTaskDefinition& rTaskDefinition, TBasePathDataContainer& rBasePathDataContainer, TFileInfoArray& rFilesCache, TTaskLocalStats& rTaskLocalStats, + TTaskBasicProgressInfo& rTaskBasicProgressInfo, TTaskConfigTracker& rCfgTracker, icpf::log_file& rLog, + IFeedbackHandler* piFeedbackHandler, TWorkerThreadController& rThreadController, TLocalFilesystem& rfsLocal); + ~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; } + + TFileInfoArray& GetFilesCache() { return m_rFilesCache; } + const TFileInfoArray& 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; } + + IFeedbackHandler* GetFeedbackHandler() { return m_piFeedbackHandler; } + const IFeedbackHandler* GetFeedbackHandler() const { return m_piFeedbackHandler; } + + TWorkerThreadController& GetThreadController() { return m_rThreadController; } + const TWorkerThreadController& GetThreadController() const { return m_rThreadController; } + + TLocalFilesystem& GetLocalFilesystem() { return m_rfsLocal; } + const TLocalFilesystem& GetLocalFilesystem() const { return m_rfsLocal; } + +private: + TSubTaskContext(const TSubTaskContext& rSrc); + TSubTaskContext& operator=(const TSubTaskContext& rSrc); + +private: + TTaskDefinition& m_rTaskDefinition; + + // information about input paths + TBasePathDataContainer& m_rBasePathDataContainer; + + // data on which to operate + TFileInfoArray& m_rFilesCache; + + // local stats for task + TTaskLocalStats& m_rTaskLocalStats; + TTaskBasicProgressInfo& m_rTaskBasicProgressInfo; + + // configuration changes tracking + TTaskConfigTracker& m_rCfgTracker; + + // local filesystem access functions + TLocalFilesystem& m_rfsLocal; + + // additional data + icpf::log_file& m_rLog; + + // feedback handling + IFeedbackHandler* m_piFeedbackHandler; + + // thread control + TWorkerThreadController& m_rThreadController; +}; + +END_CHCORE_NAMESPACE + +#endif // __TSUBTASKCONTEXT_H__ Index: src/libchcore/TSubTaskCopyMove.cpp =================================================================== diff -u --- src/libchcore/TSubTaskCopyMove.cpp (revision 0) +++ src/libchcore/TSubTaskCopyMove.cpp (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -0,0 +1,1123 @@ +// ============================================================================ +// 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 TSubTaskCopyMove.cpp +/// @date 2010/09/19 +/// @brief Contains implementations of classes responsible for copy and move sub-operation. +// ============================================================================ +#include "stdafx.h" +#include "TSubTaskCopyMove.h" +#include "TSubTaskContext.h" +#include "TTaskConfiguration.h" +#include "TTaskDefinition.h" +#include "TLocalFilesystem.h" +#include "DataBuffer.h" +#include "../libicpf/log.h" +#include "TTaskLocalStats.h" +#include "TBasicProgressInfo.h" +#include "TTaskConfigTracker.h" +#include "TWorkerThreadController.h" +#include "FeedbackHandlerBase.h" +#include +#include "TBasePathData.h" +#include + +BEGIN_CHCORE_NAMESPACE + +// assume max sectors of 4kB (for rounding) +#define MAXSECTORSIZE 4096 + +struct CUSTOM_COPY_PARAMS +{ + TFileInfoPtr spSrcFile; // CFileInfo - src file + TSmartPath pathDstFile; // dest path with filename + + TDataBuffer 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(); + TFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + TTaskConfigTracker& rCfgTracker = GetContext().GetCfgTracker(); + TTaskBasicProgressInfo& rBasicProgressInfo = GetContext().GetTaskBasicProgressInfo(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + 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())); + + // now it's time to check if there is enough space on destination device + TSubTaskBase::ESubOperationResult eResult = CheckForFreeSpaceFB(); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + // 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); + + TBufferSizes bs; + bs.SetOnlyDefault(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetDefaultSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetOneDiskSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetTwoDisksSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetCDSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetLANSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + + ccp.dbBuffer.Create(bs); + + // helpers + DWORD dwLastError = 0; + + // log + const TBufferSizes& rbs = ccp.dbBuffer.GetSizes(); + + TString strFormat; + strFormat = _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"); + strFormat.Replace(_T("%create"), boost::lexical_cast(ccp.bOnlyCreate).c_str()); + strFormat.Replace(_T("%defsize"), boost::lexical_cast(rbs.GetDefaultSize()).c_str()); + strFormat.Replace(_T("%onesize"), boost::lexical_cast(rbs.GetOneDiskSize()).c_str()); + strFormat.Replace(_T("%twosize"), boost::lexical_cast(rbs.GetTwoDisksSize()).c_str()); + strFormat.Replace(_T("%cdsize"), boost::lexical_cast(rbs.GetCDSize()).c_str()); + strFormat.Replace(_T("%lansize"), boost::lexical_cast(rbs.GetLANSize()).c_str()); + strFormat.Replace(_T("%filecount"), boost::lexical_cast(stSize).c_str()); + strFormat.Replace(_T("%ignorefolders"), boost::lexical_cast(bIgnoreFolders).c_str()); + strFormat.Replace(_T("%dstpath"), rTaskDefinition.GetDestinationPath().ToString()); + strFormat.Replace(_T("%currindex"), boost::lexical_cast(rBasicProgressInfo.GetCurrentIndex()).c_str()); + + rLog.logi(strFormat); + + 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 + TFileInfoPtr 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 ? + wchar_t wchDestinationDrive = rTaskDefinition.GetDestinationPath().GetDriveLetter(); + bool bMove = rTaskDefinition.GetOperationType() == eOperation_Move; + TSmartPath pathCurrent = spFileInfo->GetFullFilePath(); + if(bMove && wchDestinationDrive != L'\0' && wchDestinationDrive == pathCurrent.GetDriveLetter() && GetMove(spFileInfo)) + { + bool bRetry = true; + if(bRetry && !TLocalFilesystem::FastMove(pathCurrent, ccp.pathDstFile)) + { + dwLastError=GetLastError(); + //log + strFormat = _T("Error %errno while calling MoveFile %srcpath -> %dstpath (ProcessFiles)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%srcpath"), spFileInfo->GetFullFilePath().ToString()); + strFormat.Replace(_T("%dstpath"), ccp.pathDstFile.ToString()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { spFileInfo->GetFullFilePath().ToString(), ccp.pathDstFile.ToString(), eFastMoveError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + continue; + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bRetry = false; + break; // just do nothing + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + else + spFileInfo->SetFlags(FIF_PROCESSED, FIF_PROCESSED); + } + else + { + // if folder - create it + if(spFileInfo->IsDirectory()) + { + bool bRetry = true; + if(bRetry && !TLocalFilesystem::CreateDirectory(ccp.pathDstFile, false) && (dwLastError=GetLastError()) != ERROR_ALREADY_EXISTS ) + { + // log + strFormat = _T("Error %errno while calling CreateDirectory %path (ProcessFiles)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), ccp.pathDstFile.ToString()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { ccp.pathDstFile.ToString(), NULL, eCreateError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + continue; + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bRetry = false; + break; // just do nothing + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + + rLocalStats.IncreaseProcessedSize(spFileInfo->GetLength64()); + spFileInfo->SetFlags(FIF_PROCESSED, FIF_PROCESSED); + } + else + { + // start copying/moving file + ccp.spSrcFile = spFileInfo; + ccp.bProcessed = false; + + // copy data + 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())) + TLocalFilesystem::SetAttributes(spFileInfo->GetFullFilePath(), FILE_ATTRIBUTE_NORMAL); + TLocalFilesystem::DeleteFile(spFileInfo->GetFullFilePath()); // there will be another try later, so I don't check + // if succeeded + } + } + + // set a time + if(GetTaskPropValue(rTaskDefinition.GetConfiguration())) + TLocalFilesystem::SetFileDirectoryTime(ccp.pathDstFile, spFileInfo->GetCreationTime(), spFileInfo->GetLastAccessTime(), spFileInfo->GetLastWriteTime()); // no error checking (but most probably it should be checked) + + // attributes + if(GetTaskPropValue(rTaskDefinition.GetConfiguration())) + TLocalFilesystem::SetAttributes(ccp.pathDstFile, 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 TFileInfoPtr& spFileInfo) +{ + if(!spFileInfo) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + if(spFileInfo->GetSrcIndex() == std::numeric_limits::max()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + // check if this information has already been stored + size_t stBaseIndex = spFileInfo->GetSrcIndex(); + if(stBaseIndex >= GetContext().GetBasePathDataContainer().GetCount()) + THROW_CORE_EXCEPTION(eErr_BoundsExceeded); + + TBasePathDataPtr spPathData = GetContext().GetBasePathDataContainer().GetAt(stBaseIndex); + return spPathData->GetMove(); +} + +int TSubTaskCopyMove::GetBufferIndex(const TFileInfoPtr& spFileInfo) +{ + if(!spFileInfo) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + TSmartPath pathSource = spFileInfo->GetFullFilePath(); + TSmartPath pathDestination = GetContext().GetTaskDefinition().GetDestinationPath(); + + TLocalFilesystem::EPathsRelation eRelation = GetContext().GetLocalFilesystem().GetPathsRelation(pathSource, pathDestination); + switch(eRelation) + { + case TLocalFilesystem::eRelation_Network: + return TBufferSizes::eBuffer_LAN; + + case TLocalFilesystem::eRelation_CDRom: + return TBufferSizes::eBuffer_CD; + + case TLocalFilesystem::eRelation_TwoPhysicalDisks: + return TBufferSizes::eBuffer_TwoDisks; + + case TLocalFilesystem::eRelation_SinglePhysicalDisk: + return TBufferSizes::eBuffer_OneDisk; + + //case eRelation_Other: + default: + return TBufferSizes::eBuffer_Default; + } +} + +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(); + + TLocalFilesystemFile fileSrc = TLocalFilesystem::CreateFileObject(); + TLocalFilesystemFile fileDst = TLocalFilesystem::CreateFileObject(); + + TString strFormat; + 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(fileSrc, pData->spSrcFile->GetFullFilePath(), bNoBuffer); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(!fileSrc.IsOpen()) + { + // 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(fileDst, pData->pathDstFile, bNoBuffer, pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(!fileDst.IsOpen()) + { + rLocalStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - rBasicProgressInfo.GetCurrentFileProcessedSize()); + pData->bProcessed = false; + return TSubTaskBase::eSubResult_Continue; + } + } + else + { + // we are resuming previous operation + eResult = OpenExistingDestinationFileFB(fileDst, pData->pathDstFile, bNoBuffer); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(!fileDst.IsOpen()) + { + 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(fileSrc, 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(fileDst, 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(fileDst, 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 + strFormat = _T("Kill request while main copying file %srcpath -> %dstpath"); + strFormat.Replace(_T("%srcpath"), pData->spSrcFile->GetFullFilePath().ToString()); + strFormat.Replace(_T("%dstpath"), pData->pathDstFile.ToString()); + rLog.logi(strFormat); + 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)) + { + TBufferSizes bs; + bs.SetOnlyDefault(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetDefaultSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetOneDiskSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetTwoDisksSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetCDSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + bs.SetLANSize(GetTaskPropValue(rTaskDefinition.GetConfiguration())); + + // log + const TBufferSizes& rbs1 = pData->dbBuffer.GetSizes(); + + strFormat = _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)"); + + strFormat.Replace(_T("%defsize"), boost::lexical_cast(rbs1.GetDefaultSize()).c_str()); + strFormat.Replace(_T("%onesize"), boost::lexical_cast(rbs1.GetOneDiskSize()).c_str()); + strFormat.Replace(_T("%twosize"), boost::lexical_cast(rbs1.GetTwoDisksSize()).c_str()); + strFormat.Replace(_T("%cdsize"), boost::lexical_cast(rbs1.GetCDSize()).c_str()); + strFormat.Replace(_T("%lansize"), boost::lexical_cast(rbs1.GetLANSize()).c_str()); + strFormat.Replace(_T("%defsize2"), boost::lexical_cast(bs.GetDefaultSize()).c_str()); + strFormat.Replace(_T("%onesize2"), boost::lexical_cast(bs.GetOneDiskSize()).c_str()); + strFormat.Replace(_T("%twosize2"), boost::lexical_cast(bs.GetTwoDisksSize()).c_str()); + strFormat.Replace(_T("%cdsize2"), boost::lexical_cast(bs.GetCDSize()).c_str()); + strFormat.Replace(_T("%lansize2"), boost::lexical_cast(bs.GetLANSize()).c_str()); + strFormat.Replace(_T("%srcfile"), pData->spSrcFile->GetFullFilePath().ToString()); + strFormat.Replace(_T("%dstfile"), pData->pathDstFile.ToString()); + + rLog.logi(strFormat); + pData->dbBuffer.Create(bs); + } + + // establish count of data to read + if(GetTaskPropValue(rTaskDefinition.GetConfiguration())) + iBufferIndex = TBufferSizes::eBuffer_Default; + else + iBufferIndex = GetBufferIndex(pData->spSrcFile); + rLocalStats.SetCurrentBufferIndex(iBufferIndex); + + ulToRead = bNoBuffer ? ROUNDUP(pData->dbBuffer.GetSizes().GetSizeByType((TBufferSizes::EBufferType)iBufferIndex), MAXSECTORSIZE) : pData->dbBuffer.GetSizes().GetSizeByType((TBufferSizes::EBufferType)iBufferIndex); + + // read data from file to buffer + eResult = ReadFileFB(fileSrc, 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(fileDst, 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 + fileDst.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(fileDst, pData->pathDstFile, false); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(!fileDst.IsOpen()) + { + 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(fileDst, 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(fileDst, 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(TLocalFilesystemFile& fileSrc, const TSmartPath& spPathToOpen, bool bNoBuffering) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + BOOST_ASSERT(!spPathToOpen.IsEmpty()); + if(spPathToOpen.IsEmpty()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + bool bRetry = false; + + fileSrc.Close(); + + do + { + bRetry = false; + + if(!fileSrc.OpenExistingForReading(spPathToOpen, bNoBuffering)) + { + DWORD dwLastError = GetLastError(); + + FEEDBACK_FILEERROR feedStruct = { spPathToOpen.ToString(), NULL, eCreateError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &feedStruct); + + switch(frResult) + { + case IFeedbackHandler::eResult_Skip: + break; // will return INVALID_HANDLE_VALUE + + case IFeedbackHandler::eResult_Cancel: + { + // log + TString strFormat = _T("Cancel request [error %errno] while opening source file %path (OpenSourceFileFB)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), spPathToOpen.ToString()); + rLog.loge(strFormat); + + return TSubTaskBase::eSubResult_CancelRequest; + } + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Retry: + { + // log + TString strFormat = _T("Retrying [error %errno] to open source file %path (OpenSourceFileFB)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), spPathToOpen.ToString()); + rLog.loge(strFormat); + + bRetry = true; + break; + } + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenDestinationFileFB(TLocalFilesystemFile& fileDst, const TSmartPath& pathDstFile, bool bNoBuffering, const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bool bRetry = false; + + ullSeekTo = 0; + bFreshlyCreated = true; + + fileDst.Close(); + do + { + bRetry = false; + + if(!fileDst.CreateNewForWriting(pathDstFile, bNoBuffering)) + { + DWORD dwLastError = GetLastError(); + if(dwLastError == ERROR_FILE_EXISTS) + { + bFreshlyCreated = false; + + // pass it to the specialized method + TSubTaskBase::ESubOperationResult eResult = OpenExistingDestinationFileFB(fileDst, pathDstFile, bNoBuffering); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + else if(!fileDst.IsOpen()) + 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 + TFileInfoPtr spDstFileInfo(boost::make_shared()); + + if(!TLocalFilesystem::GetFileInfo(pathDstFile, spDstFileInfo)) + THROW_CORE_EXCEPTION_WIN32(eErr_CannotGetFileInfo, GetLastError()); + + // src and dst files are the same + FEEDBACK_ALREADYEXISTS feedStruct = { spSrcFileInfo, spDstFileInfo }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileAlreadyExists, &feedStruct); + // check for dialog result + switch(frResult) + { + case IFeedbackHandler::eResult_Overwrite: + ullSeekTo = 0; + break; + + case IFeedbackHandler::eResult_CopyRest: + ullSeekTo = spDstFileInfo->GetLength64(); + break; + + case IFeedbackHandler::eResult_Skip: + return TSubTaskBase::eSubResult_Continue; + + case IFeedbackHandler::eResult_Cancel: + { + // log + TString strFormat = _T("Cancel request while checking result of dialog before opening source file %path (CustomCopyFileFB)"); + strFormat.Replace(_T("%path"), pathDstFile.ToString()); + rLog.logi(strFormat); + + return TSubTaskBase::eSubResult_CancelRequest; + } + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + else + { + FEEDBACK_FILEERROR feedStruct = { pathDstFile.ToString(), NULL, eCreateError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &feedStruct); + switch(frResult) + { + case IFeedbackHandler::eResult_Retry: + { + // log + TString strFormat = _T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), pathDstFile.ToString()); + rLog.loge(strFormat); + + bRetry = true; + + break; + } + case IFeedbackHandler::eResult_Cancel: + { + // log + TString strFormat = _T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), pathDstFile.ToString()); + rLog.loge(strFormat); + + return TSubTaskBase::eSubResult_CancelRequest; + } + + case IFeedbackHandler::eResult_Skip: + break; // will return invalid handle value + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenExistingDestinationFileFB(TLocalFilesystemFile& fileDst, const TSmartPath& pathDstFile, bool bNoBuffering) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bool bRetry = false; + + fileDst.Close(); + + do + { + bRetry = false; + + if(!fileDst.OpenExistingForWriting(pathDstFile, bNoBuffering)) + { + DWORD dwLastError = GetLastError(); + FEEDBACK_FILEERROR feedStruct = { pathDstFile.ToString(), NULL, eCreateError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &feedStruct); + switch (frResult) + { + case IFeedbackHandler::eResult_Retry: + { + // log + TString strFormat = _T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%path"), pathDstFile.ToString()); + rLog.loge(strFormat); + + bRetry = true; + + break; + } + case IFeedbackHandler::eResult_Cancel: + { + // log + TString strFormat = _T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), pathDstFile.ToString()); + rLog.loge(strFormat); + + return TSubTaskBase::eSubResult_CancelRequest; + } + + case IFeedbackHandler::eResult_Skip: + break; // will return invalid handle value + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::SetFilePointerFB(TLocalFilesystemFile& file, long long llDistance, const TSmartPath& pathFile, bool& bSkip) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + bool bRetry = false; + do + { + bRetry = false; + + if(!file.SetFilePointer(llDistance, FILE_BEGIN)) + { + DWORD dwLastError = GetLastError(); + + // log + TString strFormat = _T("Error %errno while moving file pointer of %path to %pos"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + strFormat.Replace(_t("%pos"), boost::lexical_cast(llDistance).c_str()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eSeekError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::SetEndOfFileFB(TLocalFilesystemFile& file, const TSmartPath& pathFile, bool& bSkip) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + + bool bRetry = false; + do + { + if(!file.SetEndOfFile()) + { + // log + DWORD dwLastError = GetLastError(); + + TString strFormat = _T("Error %errno while setting size of file %path to 0"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eResizeError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + bRetry = true; + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::ReadFileFB(TLocalFilesystemFile& file, TDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const TSmartPath& pathFile, bool& bSkip) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + bool bRetry = false; + do + { + bRetry = false; + + if(!file.ReadFile(rBuffer, dwToRead, rdwBytesRead)) + { + // log + DWORD dwLastError = GetLastError(); + + TString strFormat = _T("Error %errno while trying to read %count bytes from source file %path (CustomCopyFileFB)"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%count"), boost::lexical_cast(dwToRead).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eReadError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::WriteFileFB(TLocalFilesystemFile& file, TDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const TSmartPath& pathFile, bool& bSkip) +{ + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + icpf::log_file& rLog = GetContext().GetLog(); + + bSkip = false; + + bool bRetry = false; + do + { + bRetry = false; + + if(!file.WriteFile(rBuffer, dwToWrite, rdwBytesWritten)) + { + // log + DWORD dwLastError = GetLastError(); + + TString strFormat = _T("Error %errno while trying to write %count bytes to destination file %path (CustomCopyFileFB)"); + strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_t("%count"), boost::lexical_cast(dwToWrite).c_str()); + strFormat.Replace(_t("%path"), pathFile.ToString()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { pathFile.ToString(), NULL, eWriteError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bSkip = true; + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::CheckForFreeSpaceFB() +{ + icpf::log_file& rLog = GetContext().GetLog(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + TTaskLocalStats& rLocalStats = GetContext().GetTaskLocalStats(); + TLocalFilesystem& rLocalFilesystem = GetContext().GetLocalFilesystem(); + + ull_t ullNeededSize = 0, ullAvailableSize = 0; + bool bRetry = false; + + do + { + bRetry = false; + + rLog.logi(_T("Checking for free space on destination disk...")); + + ullNeededSize = rLocalStats.GetUnProcessedSize(); // it'd be nice to round up to take cluster size into consideration, + + // get free space + bool bResult = rLocalFilesystem.GetDynamicFreeSpace(rTaskDefinition.GetDestinationPath(), ullAvailableSize); + if(bResult && ullNeededSize > ullAvailableSize) + { + TString strFormat = _T("Not enough free space on disk - needed %needsize bytes for data, available: %availablesize bytes."); + strFormat.Replace(_t("%needsize"), boost::lexical_cast(ullNeededSize).c_str()); + strFormat.Replace(_t("%availablesize"), boost::lexical_cast(ullAvailableSize).c_str()); + rLog.logw(strFormat); + + if(rTaskDefinition.GetSourcePathCount() > 0) + { + FEEDBACK_NOTENOUGHSPACE feedStruct = { ullNeededSize, rTaskDefinition.GetSourcePathAt(0).ToString(), rTaskDefinition.GetDestinationPath().ToString() }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_NotEnoughSpace, &feedStruct); + + // default + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + rLog.logi(_T("Cancel request while checking for free space on disk.")); + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + rLog.logi(_T("Retrying to read drive's free space...")); + bRetry = true; + break; + + case IFeedbackHandler::eResult_Ignore: + rLog.logi(_T("Ignored warning about not enough place on disk to copy data.")); + return TSubTaskBase::eSubResult_Continue; + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + } + while(bRetry); + + return TSubTaskBase::eSubResult_Continue; +} + +END_CHCORE_NAMESPACE Index: src/libchcore/TSubTaskCopyMove.h =================================================================== diff -u --- src/libchcore/TSubTaskCopyMove.h (revision 0) +++ src/libchcore/TSubTaskCopyMove.h (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -0,0 +1,65 @@ +// ============================================================================ +// 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 TSubTaskCopyMove.h +/// @date 2010/09/18 +/// @brief Contains declarations of classes responsible for copy and move sub-operation. +// ============================================================================ +#ifndef __TSUBTASKCOPYMOVE_H__ +#define __TSUBTASKCOPYMOVE_H__ + +#include "libchcore.h" +#include "TSubTaskBase.h" + +BEGIN_CHCORE_NAMESPACE + +class TDataBuffer; +class TLocalFilesystemFile; +typedef boost::shared_ptr TFileInfoPtr; +struct CUSTOM_COPY_PARAMS; + +class LIBCHCORE_API TSubTaskCopyMove : public TSubTaskBase +{ +public: + TSubTaskCopyMove(TSubTaskContext& tSubTaskContext); + + ESubOperationResult Exec(); + +private: + bool GetMove(const TFileInfoPtr& spFileInfo); + int GetBufferIndex(const TFileInfoPtr& spFileInfo); + + ESubOperationResult CustomCopyFileFB(CUSTOM_COPY_PARAMS* pData); + + ESubOperationResult OpenSourceFileFB(TLocalFilesystemFile& fileSrc, const TSmartPath& spPathToOpen, bool bNoBuffering); + ESubOperationResult OpenDestinationFileFB(TLocalFilesystemFile& fileDst, const TSmartPath& pathDstFile, bool bNoBuffering, const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated); + ESubOperationResult OpenExistingDestinationFileFB(TLocalFilesystemFile& fileDst, const TSmartPath& pathDstFilePath, bool bNoBuffering); + + ESubOperationResult SetFilePointerFB(TLocalFilesystemFile& file, long long llDistance, const TSmartPath& pathFile, bool& bSkip); + ESubOperationResult SetEndOfFileFB(TLocalFilesystemFile& file, const TSmartPath& pathFile, bool& bSkip); + + ESubOperationResult ReadFileFB(TLocalFilesystemFile& file, TDataBuffer& rBuffer, DWORD dwToRead, DWORD& rdwBytesRead, const TSmartPath& pathFile, bool& bSkip); + ESubOperationResult WriteFileFB(TLocalFilesystemFile& file, TDataBuffer& rBuffer, DWORD dwToWrite, DWORD& rdwBytesWritten, const TSmartPath& pathFile, bool& bSkip); + ESubOperationResult CreateDirectoryFB(const TSmartPath& pathDirectory); + + ESubOperationResult CheckForFreeSpaceFB(); +}; + +END_CHCORE_NAMESPACE + +#endif Index: src/libchcore/TSubTaskDelete.cpp =================================================================== diff -u --- src/libchcore/TSubTaskDelete.cpp (revision 0) +++ src/libchcore/TSubTaskDelete.cpp (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -0,0 +1,144 @@ +// ============================================================================ +// 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 TSubTaskDelete.cpp +/// @date 2010/09/19 +/// @brief Contains implementation of classes responsible for delete sub-operation. +// ============================================================================ +#include "stdafx.h" +#include "TSubTaskDelete.h" +#include "TSubTaskContext.h" +#include "TBasicProgressInfo.h" +#include "TWorkerThreadController.h" +#include "TTaskConfiguration.h" +#include "TTaskDefinition.h" +//#include "FeedbackHandler.h" +#include "TLocalFilesystem.h" +#include "..\libicpf\log.h" +#include "FeedbackHandlerBase.h" +#include + +BEGIN_CHCORE_NAMESPACE + +TSubTaskDelete::TSubTaskDelete(TSubTaskContext& rContext) : + TSubTaskBase(rContext) +{ +} + +TSubTaskBase::ESubOperationResult TSubTaskDelete::Exec() +{ + // log + icpf::log_file& rLog = GetContext().GetLog(); + TFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + TTaskBasicProgressInfo& rBasicProgressInfo = GetContext().GetTaskBasicProgressInfo(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + + // log + rLog.logi(_T("Deleting files (DeleteFiles)...")); + + // current processed path + BOOL bSuccess; + TFileInfoPtr spFileInfo; + TString strFormat; + + // index points to 0 or next item to process + size_t stIndex = rBasicProgressInfo.GetCurrentIndex(); + while(stIndex < rFilesCache.GetSize()) + { + // set index in pTask to currently deleted element + rBasicProgressInfo.SetCurrentIndex(stIndex); + + // check for kill flag + if(rThreadController.KillRequested()) + { + // log + rLog.logi(_T("Kill request while deleting files (Delete Files)")); + return TSubTaskBase::eSubResult_KillRequest; + } + + // current processed element + spFileInfo = rFilesCache.GetAt(rFilesCache.GetSize() - stIndex - 1); + if(!(spFileInfo->GetFlags() & FIF_PROCESSED)) + { + ++stIndex; + continue; + } + + // delete data + if(spFileInfo->IsDirectory()) + { + if(!GetTaskPropValue(rTaskDefinition.GetConfiguration())) + TLocalFilesystem::SetAttributes(spFileInfo->GetFullFilePath(), FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY); + bSuccess = TLocalFilesystem::RemoveDirectory(spFileInfo->GetFullFilePath()); + } + else + { + // set files attributes to normal - it'd slow processing a bit, but it's better. + if(!GetTaskPropValue(rTaskDefinition.GetConfiguration())) + TLocalFilesystem::SetAttributes(spFileInfo->GetFullFilePath(), FILE_ATTRIBUTE_NORMAL); + bSuccess = TLocalFilesystem::DeleteFile(spFileInfo->GetFullFilePath()); + } + + // operation failed + DWORD dwLastError = GetLastError(); + if(!bSuccess && dwLastError != ERROR_PATH_NOT_FOUND && dwLastError != ERROR_FILE_NOT_FOUND) + { + // log + strFormat = _T("Error #%errno while deleting file/folder %path"); + strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); + strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.loge(strFormat); + + FEEDBACK_FILEERROR ferr = { spFileInfo->GetFullFilePath().ToString(), NULL, eDeleteError, dwLastError }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + rLog.logi(_T("Cancel request while deleting file.")); + return TSubTaskBase::eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + continue; // no stIndex bump, since we are trying again + + case IFeedbackHandler::eResult_Pause: + return TSubTaskBase::eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + break; // just do nothing + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + + ++stIndex; + }//while + + // add 1 to current index + rBasicProgressInfo.IncreaseCurrentIndex(); + + // log + rLog.logi(_T("Deleting files finished")); + + return TSubTaskBase::eSubResult_Continue; +} + +END_CHCORE_NAMESPACE Fisheye: tag c866a5e96f5eaf160278a8c128bf86e342cc2409 is not in file src/libchcore/TSubTaskDelete.h Fisheye: Tag 4d20d0e58f37f06ac91287015b960308db54d47e refers to a dead (removed) revision in file `src/ch/TSubTaskDelete.h'. Fisheye: No comparison available. Pass `N' to diff? Index: src/libchcore/TSubTaskScanDirectory.cpp =================================================================== diff -u --- src/libchcore/TSubTaskScanDirectory.cpp (revision 0) +++ src/libchcore/TSubTaskScanDirectory.cpp (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -0,0 +1,266 @@ +// ============================================================================ +// 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 TSubTaskScanDirectory.cpp +/// @date 2010/09/18 +/// @brief Contains implementation of classes related to scan directory subtask. +// ============================================================================ +#include "stdafx.h" +#include "TSubTaskScanDirectory.h" +#include "TSubTaskContext.h" +#include "TTaskConfiguration.h" +#include "TTaskDefinition.h" +//#include "FeedbackHandler.h" +#include "TLocalFilesystem.h" +#include "FeedbackHandlerBase.h" +#include "TBasePathData.h" +#include "TWorkerThreadController.h" +#include "TTaskLocalStats.h" +#include +#include "..\libicpf\log.h" + +BEGIN_CHCORE_NAMESPACE + +TSubTaskScanDirectories::TSubTaskScanDirectories(TSubTaskContext& rContext) : + TSubTaskBase(rContext) +{ +} + +TSubTaskScanDirectories::~TSubTaskScanDirectories() +{ +} + +TSubTaskScanDirectories::ESubOperationResult TSubTaskScanDirectories::Exec() +{ + // log + icpf::log_file& rLog = GetContext().GetLog(); + TFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + IFeedbackHandler* piFeedbackHandler = GetContext().GetFeedbackHandler(); + const TBasePathDataContainer& rarrSourcePathsInfo = GetContext().GetBasePathDataContainer(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + TTaskLocalStats& rTaskLocalStats = GetContext().GetTaskLocalStats(); + + rLog.logi(_T("Searching for files...")); + + // reset progress + rTaskLocalStats.SetProcessedSize(0); + rTaskLocalStats.SetTotalSize(0); + + // delete the content of rFilesCache + rFilesCache.Clear(); + + // read filtering options + TFiltersArray afFilters; + GetTaskPropValue(rTaskDefinition.GetConfiguration(), afFilters); + + // enter some data to rFilesCache + wchar_t wchDestinationDriveLetter = rTaskDefinition.GetDestinationPath().GetDriveLetter(); + + bool bIgnoreDirs = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bool bForceDirectories = GetTaskPropValue(rTaskDefinition.GetConfiguration()); + bool bMove = rTaskDefinition.GetOperationType() == eOperation_Move; + + // add everything + TString strFormat; + bool bRetry = true; + bool bSkipInputPath = false; + + size_t stSize = rTaskDefinition.GetSourcePathCount(); + for(size_t stIndex = 0; stIndex < stSize ; stIndex++) + { + TFileInfoPtr spFileInfo; + + bSkipInputPath = false; + + spFileInfo.reset(new TFileInfo()); + + // 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 = TLocalFilesystem::GetFileInfo(rTaskDefinition.GetSourcePathAt(stIndex), spFileInfo, stIndex, &rTaskDefinition.GetSourcePaths()); + if(!bExists) + { + FEEDBACK_FILEERROR ferr = { rTaskDefinition.GetSourcePathAt(stIndex).ToString(), NULL, eFastMoveError, ERROR_FILE_NOT_FOUND }; + IFeedbackHandler::EFeedbackResult frResult = (IFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_FileError, &ferr); + switch(frResult) + { + case IFeedbackHandler::eResult_Cancel: + rFilesCache.Clear(); + return eSubResult_CancelRequest; + + case IFeedbackHandler::eResult_Retry: + bRetry = true; + break; + + case IFeedbackHandler::eResult_Pause: + rFilesCache.Clear(); + return eSubResult_PauseRequest; + + case IFeedbackHandler::eResult_Skip: + bSkipInputPath = true; + break; // just do nothing + + default: + BOOST_ASSERT(FALSE); // unknown result + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + } + while(bRetry); + + // if we have chosen to skip the input path then there's nothing to do + if(bSkipInputPath) + continue; + + // log + strFormat = _T("Adding file/folder (clipboard) : %path ..."); + strFormat.Replace(_T("%path"), rTaskDefinition.GetSourcePathAt(stIndex).ToString()); + rLog.logi(strFormat); + + // 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()) + { + TSmartPath pathSubst = FindFreeSubstituteName(spFileInfo->GetFullFilePath(), rTaskDefinition.GetDestinationPath()); + rarrSourcePathsInfo.GetAt(stIndex)->SetDestinationPath(pathSubst); + } + else + rarrSourcePathsInfo.GetAt(stIndex)->SetDestinationPath(spFileInfo->GetFullFilePath().GetFileName()); + } + + wchar_t wchSourceDriveLetter = spFileInfo->GetFullFilePath().GetDriveLetter(); + + // 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 + strFormat = _T("Added folder %path"); + strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.logi(strFormat); + } + + // don't add folder contents when moving inside one disk boundary + if(bIgnoreDirs || !bMove || wchDestinationDriveLetter == L'\0' || wchDestinationDriveLetter != wchSourceDriveLetter || + TLocalFilesystem::PathExist(CalculateDestinationPath(spFileInfo, rTaskDefinition.GetDestinationPath(), ((int)bForceDirectories) << 1)) ) + { + // log + strFormat = _T("Recursing folder %path"); + strFormat.Replace(_t("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.logi(strFormat); + + // 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 && wchDestinationDriveLetter != L'\0' && wchDestinationDriveLetter == wchSourceDriveLetter && + !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 + strFormat = _T("Added file %path"); + strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString()); + rLog.logi(strFormat); + } + } + + // calc size of all files + rTaskLocalStats.SetTotalSize(rFilesCache.CalculateTotalSize()); + + // log + rLog.logi(_T("Searching for files finished")); + + return eSubResult_Continue; +} + +int TSubTaskScanDirectories::ScanDirectory(TSmartPath pathDirName, size_t stSrcIndex, bool bRecurse, bool bIncludeDirs, TFiltersArray& afFilters) +{ + TFileInfoArray& rFilesCache = GetContext().GetFilesCache(); + TTaskDefinition& rTaskDefinition = GetContext().GetTaskDefinition(); + TWorkerThreadController& rThreadController = GetContext().GetThreadController(); + + TLocalFilesystemFind finder = TLocalFilesystem::CreateFinderObject(pathDirName, PathFromString(_T("*"))); + TFileInfoPtr spFileInfo(boost::make_shared()); + + while(finder.FindNext(spFileInfo)) + { + if(rThreadController.KillRequested()) + break; + + if(!spFileInfo->IsDirectory()) + { + if(afFilters.Match(spFileInfo)) + { + spFileInfo->SetParentObject(stSrcIndex, &rTaskDefinition.GetSourcePaths()); + rFilesCache.AddFileInfo(spFileInfo); + spFileInfo = boost::make_shared(); + } + } + else + { + TSmartPath pathCurrent = spFileInfo->GetFullFilePath(); + if(bIncludeDirs) + { + spFileInfo->SetParentObject(stSrcIndex, &rTaskDefinition.GetSourcePaths()); + rFilesCache.AddFileInfo(spFileInfo); + spFileInfo = boost::make_shared(); + } + + if(bRecurse) + ScanDirectory(pathCurrent, stSrcIndex, bRecurse, bIncludeDirs, afFilters); + } + } + + return 0; +} + +END_CHCORE_NAMESPACE Fisheye: tag 2aea3ad6f3c68be709ac65c70d9646eafe3b034c is not in file src/libchcore/TSubTaskScanDirectory.h Fisheye: Tag 4d20d0e58f37f06ac91287015b960308db54d47e refers to a dead (removed) revision in file `src/ch/TSubTaskScanDirectory.h'. Fisheye: No comparison available. Pass `N' to diff? Index: src/libchcore/TTaskConfiguration.h =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/libchcore/TTaskConfiguration.h (.../TTaskConfiguration.h) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/libchcore/TTaskConfiguration.h (.../TTaskConfiguration.h) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -122,8 +122,8 @@ TASK_PROPERTY(eTO_Filters, chcore::TFiltersArray, _T("Operation.Filtering"), chcore::TFiltersArray()); // Naming settings -TASK_PROPERTY(eTO_AlternateFilenameFormatString_First, CString, _T("Naming.AlternateFilenameFormatFirst"), _T("Copy of %name")); -TASK_PROPERTY(eTO_AlternateFilenameFormatString_AfterFirst, CString, _T("Naming.AlternateFilenameFormatAfterFirst"), _T("Copy (%count) of %name")); +TASK_PROPERTY(eTO_AlternateFilenameFormatString_First, TString, _T("Naming.AlternateFilenameFormatFirst"), _T("Copy of %name")); +TASK_PROPERTY(eTO_AlternateFilenameFormatString_AfterFirst, TString, _T("Naming.AlternateFilenameFormatAfterFirst"), _T("Copy (%count) of %name")); ///////////////////////////////////////////////////////////////////////////////////////////// // other properties names Index: src/libchcore/libchcore.vc90.vcproj =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r4d20d0e58f37f06ac91287015b960308db54d47e --- src/libchcore/libchcore.vc90.vcproj (.../libchcore.vc90.vcproj) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/libchcore/libchcore.vc90.vcproj (.../libchcore.vc90.vcproj) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) @@ -392,6 +392,14 @@ > + + + + @@ -419,6 +427,42 @@ RelativePath=".\TTaskLocalStats.h" > + + + + + + + + + + + + + + + + + +