Index: src/ch/FeedbackHandler.cpp =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/ch/FeedbackHandler.cpp (.../FeedbackHandler.cpp) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/ch/FeedbackHandler.cpp (.../FeedbackHandler.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -41,11 +41,14 @@ return eResult; } -chengine::EFeedbackResult CFeedbackHandler::FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo, FeedbackAlreadyExistsRuleList& rNewRules) +chengine::EFeedbackResult CFeedbackHandler::FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo, TString& strRenameName, FeedbackAlreadyExistsRuleList& rNewRules) { - CFeedbackReplaceDlg dlg(spSrcFileInfo, spDstFileInfo); + CFeedbackReplaceDlg dlg(spSrcFileInfo, spDstFileInfo, strRenameName); EFeedbackResult eResult = (EFeedbackResult)dlg.DoModal(); + if(eResult == eResult_Rename) + strRenameName = dlg.GetNewName(); + if(!dlg.GetRules().IsEmpty()) rNewRules = dlg.GetRules(); Index: src/ch/FeedbackHandler.h =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/ch/FeedbackHandler.h (.../FeedbackHandler.h) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/ch/FeedbackHandler.h (.../FeedbackHandler.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -30,7 +30,7 @@ { public: chengine::EFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, chengine::EFileError eFileError, unsigned long ulError, chengine::FeedbackErrorRuleList& rNewRules) override; - chengine::EFeedbackResult FileAlreadyExists(const chengine::TFileInfo& spSrcFileInfo, const chengine::TFileInfo& spDstFileInfo, chengine::FeedbackAlreadyExistsRuleList& rNewRules) override; + chengine::EFeedbackResult FileAlreadyExists(const chengine::TFileInfo& spSrcFileInfo, const chengine::TFileInfo& spDstFileInfo, string::TString& strRenameName, chengine::FeedbackAlreadyExistsRuleList& rNewRules) override; chengine::EFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize, chengine::FeedbackNotEnoughSpaceRuleList& rNewRules) override; chengine::EFeedbackResult OperationEvent(chengine::EOperationEvent eEvent, chengine::FeedbackOperationEventRuleList& rNewRules) override; Index: src/ch/FeedbackReplaceDlg.cpp =================================================================== diff -u -r88cf6e55a9216c5c10c169746baa854396746b41 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/ch/FeedbackReplaceDlg.cpp (.../FeedbackReplaceDlg.cpp) (revision 88cf6e55a9216c5c10c169746baa854396746b41) +++ src/ch/FeedbackReplaceDlg.cpp (.../FeedbackReplaceDlg.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -12,13 +12,15 @@ #include "../libchengine/FeedbackPredefinedRules.h" using namespace chengine; +using namespace string; IMPLEMENT_DYNAMIC(CFeedbackReplaceDlg, ictranslate::CLanguageDialog) -CFeedbackReplaceDlg::CFeedbackReplaceDlg(const chengine::TFileInfo& spSrcFile, const chengine::TFileInfo& spDstFile, CWnd* pParent /*=nullptr*/) +CFeedbackReplaceDlg::CFeedbackReplaceDlg(const chengine::TFileInfo& spSrcFile, const chengine::TFileInfo& spDstFile, const TString& strSuggestedName, CWnd* pParent /*=nullptr*/) : ictranslate::CLanguageDialog(IDD_FEEDBACK_REPLACE_DIALOG, pParent), m_rSrcFile(spSrcFile), - m_rDstFile(spDstFile) + m_rDstFile(spDstFile), + m_strNewName(strSuggestedName) { } @@ -38,6 +40,7 @@ DDX_Control(pDX, IDC_SRC_FILESIZE_EDIT, m_ctlSrcSize); DDX_Control(pDX, IDC_DST_FILENAME_EDIT, m_ctlDstName); + DDX_Control(pDX, IDC_DST_RENAME_EDIT, m_ctlDstRename); DDX_Control(pDX, IDC_DST_PATH_EDIT, m_ctlDstPath); DDX_Control(pDX, IDC_DST_MODIFIEDDATE_EDIT, m_ctlDstDate); DDX_Control(pDX, IDC_DST_FILESIZE_EDIT, m_ctlDstSize); @@ -94,10 +97,16 @@ AddResizableControl(IDC_DST_NAME_STATIC, 0.0, 0.0, 0.0, 0.0); AddResizableControl(IDC_DST_FILENAME_EDIT, 0.0, 0.0, 1.0, 0.0); + + AddResizableControl(IDC_DST_RENAME_STATIC, 0.0, 0.0, 0.0, 0.0); + AddResizableControl(IDC_DST_RENAME_EDIT, 0.0, 0.0, 1.0, 0.0); + AddResizableControl(IDC_DST_LOCATION_STATIC, 0.0, 0.0, 0.0, 0.0); AddResizableControl(IDC_DST_PATH_EDIT, 0.0, 0.0, 1.0, 0.0); + AddResizableControl(IDC_DST_SIZE_STATIC, 0.0, 0.0, 0.0, 0.0); AddResizableControl(IDC_DST_FILESIZE_EDIT, 0.0, 0.0, 1.0, 0.0); + AddResizableControl(IDC_DST_TIME_STATIC, 0.0, 0.0, 0.0, 0.0); AddResizableControl(IDC_DST_MODIFIEDDATE_EDIT, 0.0, 0.0, 1.0, 0.0); @@ -133,6 +142,8 @@ m_btnSkip.m_hMenu = m_menuMassSkip.GetSubMenu(0)->GetSafeHmenu(); m_btnSkip.m_bDefaultClick = TRUE; + m_ctlDstRename.SetWindowText(m_strNewName.c_str()); + return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } @@ -235,7 +246,13 @@ case ID_FEEDBACK_RENAME_WHENOLDERTHANDESTINATION: m_feedbackRules = FeedbackPredefinedRules::CreateAlreadyExistsRule(EPredefinedRuleCondition::eCondition_WhenOlderThanDst, eResult_Rename); break; + default: + { + CString strText; + m_ctlDstRename.GetWindowText(strText); + m_strNewName = strText; } + } EndDialog(chengine::EFeedbackResult::eResult_Rename); } Index: src/ch/FeedbackReplaceDlg.h =================================================================== diff -u -r88cf6e55a9216c5c10c169746baa854396746b41 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/ch/FeedbackReplaceDlg.h (.../FeedbackReplaceDlg.h) (revision 88cf6e55a9216c5c10c169746baa854396746b41) +++ src/ch/FeedbackReplaceDlg.h (.../FeedbackReplaceDlg.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -31,12 +31,13 @@ DECLARE_DYNAMIC(CFeedbackReplaceDlg) public: - CFeedbackReplaceDlg(const chengine::TFileInfo& spSrcFile, const chengine::TFileInfo& spDstFile, CWnd* pParent = nullptr); // standard constructor + CFeedbackReplaceDlg(const chengine::TFileInfo& spSrcFile, const chengine::TFileInfo& spDstFile, const string::TString& strSuggestedName, CWnd* pParent = nullptr); // standard constructor virtual ~CFeedbackReplaceDlg(); BOOL OnInitDialog() override; const chengine::FeedbackAlreadyExistsRuleList& GetRules() const; + string::TString GetNewName() const { return m_strNewName; } protected: void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV support @@ -52,11 +53,6 @@ afx_msg void OnBnClickedPauseButton(); afx_msg void OnBnClickedCancelButton(); - afx_msg void OnBnMassReplace(); - afx_msg void OnBnMassRename(); - afx_msg void OnBnMassResume(); - afx_msg void OnBnMassSkip(); - afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); DECLARE_MESSAGE_MAP() @@ -71,6 +67,7 @@ CEdit m_ctlSrcDate; CEdit m_ctlDstName; + CEdit m_ctlDstRename; CEdit m_ctlDstPath; CEdit m_ctlDstSize; CEdit m_ctlDstDate; @@ -93,6 +90,7 @@ const chengine::TFileInfo& m_rDstFile; chengine::FeedbackAlreadyExistsRuleList m_feedbackRules; // feedback rules resulting from choices made in this dialog box + string::TString m_strNewName; }; #endif Index: src/ch/ch.rc =================================================================== diff -u -r1e89e49b50c52838394e9c1d1ad95db5b22a8704 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/ch/ch.rc (.../ch.rc) (revision 1e89e49b50c52838394e9c1d1ad95db5b22a8704) +++ src/ch/ch.rc (.../ch.rc) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -391,38 +391,40 @@ CONTROL "Custom1",IDC_MAINUPDATEINFO_CUSTOM,"STATICEX",0x30,47,7,251,14 END -IDD_FEEDBACK_REPLACE_DIALOG DIALOGEX 0, 0, 364, 205 +IDD_FEEDBACK_REPLACE_DIALOG DIALOGEX 0, 0, 364, 224 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "File already exists" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "&Replace",IDC_REPLACE_BUTTON,"MfcMenuButton",WS_TABSTOP,7,162,81,14 - CONTROL "Re&name",IDC_RENAME_BUTTON,"MfcMenuButton",WS_TABSTOP,97,162,81,14 - CONTROL "R&esume",IDC_RESUME_BUTTON,"MfcMenuButton",WS_TABSTOP,187,162,81,14 - CONTROL "&Skip",IDC_SKIP_BUTTON,"MfcMenuButton",WS_TABSTOP,277,162,81,14 - CONTROL "&Pause",IDC_PAUSE_BUTTON,"MfcButton",WS_TABSTOP,187,183,81,14 - CONTROL "&Cancel",IDC_CANCEL_BUTTON,"MfcButton",WS_TABSTOP,277,183,81,14 - EDITTEXT IDC_DST_FILENAME_EDIT,94,102,251,12,ES_AUTOHSCROLL + CONTROL "&Replace",IDC_REPLACE_BUTTON,"MfcMenuButton",WS_TABSTOP,7,182,81,14 + CONTROL "Re&name",IDC_RENAME_BUTTON,"MfcMenuButton",WS_TABSTOP,97,182,81,14 + CONTROL "R&esume",IDC_RESUME_BUTTON,"MfcMenuButton",WS_TABSTOP,187,182,81,14 + CONTROL "&Skip",IDC_SKIP_BUTTON,"MfcMenuButton",WS_TABSTOP,277,182,81,14 + CONTROL "&Pause",IDC_PAUSE_BUTTON,"MfcButton",WS_TABSTOP,187,202,81,14 + CONTROL "&Cancel",IDC_CANCEL_BUTTON,"MfcButton",WS_TABSTOP,277,202,81,14 EDITTEXT IDC_SRC_FILENAME_EDIT,96,34,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_SRC_PATH_EDIT,96,46,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_SRC_FILESIZE_EDIT,96,58,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_SRC_MODIFIEDDATE_EDIT,96,70,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_DST_PATH_EDIT,94,117,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_DST_FILESIZE_EDIT,94,129,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_DST_MODIFIEDDATE_EDIT,94,141,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_DST_FILENAME_EDIT,96,106,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_DST_RENAME_EDIT,96,119,251,12,ES_AUTOHSCROLL + EDITTEXT IDC_DST_PATH_EDIT,96,135,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_DST_FILESIZE_EDIT,96,147,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_DST_MODIFIEDDATE_EDIT,96,159,251,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "File you are trying to copy already exists. What do you want to do?",IDC_INFO_STATIC,7,7,350,15 - ICON "",IDC_SRC_ICON_STATIC,20,38,20,20 - ICON "",IDC_DST_ICON_STATIC,20,108,20,20 + ICON "",IDC_SRC_ICON_STATIC,19,39,14,13 + ICON "",IDC_DST_ICON_STATIC,19,111,14,13 GROUPBOX "Source file",IDC_SRCFILE_STATIC,7,20,350,66 - GROUPBOX "Destination file",IDC_DSTFILE_STATIC,7,90,350,66 - LTEXT "Name:",IDC_SRC_NAME_STATIC,49,34,23,8 - LTEXT "Location:",IDC_SRC_LOCATION_STATIC,49,46,31,8 - LTEXT "Size:",IDC_SRC_SIZE_STATIC,49,58,18,8 - LTEXT "Modified:",IDC_SRC_TIME_STATIC,49,70,31,8 - LTEXT "Name:",IDC_DST_NAME_STATIC,47,104,23,8 - LTEXT "Location:",IDC_DST_LOCATION_STATIC,47,117,31,8 - LTEXT "Size:",IDC_DST_SIZE_STATIC,47,129,18,8 - LTEXT "Modified:",IDC_DST_TIME_STATIC,47,141,31,8 + GROUPBOX "Destination file",IDC_DSTFILE_STATIC,7,92,350,85 + LTEXT "Name:",IDC_SRC_NAME_STATIC,49,34,45,8 + LTEXT "Location:",IDC_SRC_LOCATION_STATIC,49,46,45,8 + LTEXT "Size:",IDC_SRC_SIZE_STATIC,49,58,45,8 + LTEXT "Modified:",IDC_SRC_TIME_STATIC,49,70,45,8 + LTEXT "Name:",IDC_DST_NAME_STATIC,49,106,45,8 + LTEXT "Rename to:",IDC_DST_RENAME_STATIC,49,121,45,8 + LTEXT "Location:",IDC_DST_LOCATION_STATIC,49,135,45,8 + LTEXT "Size:",IDC_DST_SIZE_STATIC,49,147,45,8 + LTEXT "Modified:",IDC_DST_TIME_STATIC,49,159,45,8 END @@ -559,7 +561,7 @@ LEFTMARGIN, 7 RIGHTMARGIN, 357 TOPMARGIN, 7 - BOTTOMMARGIN, 197 + BOTTOMMARGIN, 216 END END #endif // APSTUDIO_INVOKED @@ -609,7 +611,9 @@ 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 100, 0, 0 END IDD_CUSTOM_COPY_DIALOG AFX_DIALOG_LAYOUT Index: src/ch/resource.h =================================================================== diff -u -r88cf6e55a9216c5c10c169746baa854396746b41 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/ch/resource.h (.../resource.h) (revision 88cf6e55a9216c5c10c169746baa854396746b41) +++ src/ch/resource.h (.../resource.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -394,6 +394,8 @@ #define IDC_DST_LOCATION_STATIC 1383 #define IDC_DST_SIZE_STATIC 1384 #define IDC_DST_TIME_STATIC 1385 +#define IDC_DST_RENAME_EDIT 1387 +#define IDC_DST_RENAME_STATIC 1388 #define IDS_APPNAME_STRING 5000 #define IDS_PRIORITY0_STRING 5001 #define IDS_PRIORITY1_STRING 5002 @@ -739,11 +741,11 @@ #define ID_FEEDBACK_SKIP_ALLFILESWITHSAMEDATESANDSIZES 32824 #define ID_FEEDBACK_SKIP_FILESTHATAREOLDERTHANDESTINATION 32825 #define ID_FEEDBACK_SKIP_FILESTHATARENEWERTHANDESTINATION 32826 -#define ID_FEEDBACK_RENAME_WHENDESTIONATIONFILEEXISTS 32827 -#define ID_FEEDBACK_RENAME_WHENDATEORSIZEDIFFERS 32828 -#define ID_FEEDBACK_RENAME_WHENDATEANDSZEARESAME 32829 -#define ID_FEEDBACK_RENAME_WHENNEWERTHANDESTINATION 32830 -#define ID_FEEDBACK_RENAME_WHENOLDERTHANDESTINATION 32831 +#define ID_FEEDBACK_RENAME_WHENDESTIONATIONFILEEXISTS 32827 +#define ID_FEEDBACK_RENAME_WHENDATEORSIZEDIFFERS 32828 +#define ID_FEEDBACK_RENAME_WHENDATEANDSZEARESAME 32829 +#define ID_FEEDBACK_RENAME_WHENNEWERTHANDESTINATION 32830 +#define ID_FEEDBACK_RENAME_WHENOLDERTHANDESTINATION 32831 #define ID_FEEDBACK_RESUME_WHENFILEBIGGERTHANDESTINATION 32832 // Next default values for new objects Index: src/libchengine/FeedbackManager.cpp =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/FeedbackManager.cpp (.../FeedbackManager.cpp) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/FeedbackManager.cpp (.../FeedbackManager.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -26,6 +26,7 @@ using namespace serializer; using namespace chcore; +using namespace string; namespace chengine { @@ -82,22 +83,23 @@ return { eResult, bAutomatedResponse }; } - chengine::TFeedbackResult FeedbackManager::FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo) + chengine::TFeedbackResult FeedbackManager::FileAlreadyExists(const TFileInfoPtr& spSrcFileInfo, const TFileInfo& rDstFileInfo, const TSmartPath& suggestedPath) { bool bAutomatedResponse = true; EFeedbackResult eResult = eResult_Unknown; { boost::shared_lock lock(m_lock); - eResult = m_feedbackRules.GetAlreadyExistsRules().Matches(spSrcFileInfo, spDstFileInfo); + eResult = m_feedbackRules.GetAlreadyExistsRules().Matches(*spSrcFileInfo, rDstFileInfo); } if(eResult == eResult_Unknown) { FeedbackAlreadyExistsRuleList newRules; + TString strNewPath = suggestedPath.ToWString(); { TScopedRunningTimeTrackerPause scopedTimePause(m_pTimeTracker); TScopedRunningTimeTrackerPause scopedSecondaryTimePause(m_pSecondaryTimeTracker); - eResult = m_spFeedbackHandler->FileAlreadyExists(spSrcFileInfo, spDstFileInfo, newRules); + eResult = m_spFeedbackHandler->FileAlreadyExists(*spSrcFileInfo, rDstFileInfo, strNewPath, newRules); } if(eResult != eResult_Unknown) { @@ -107,8 +109,14 @@ boost::unique_lock lock(m_lock); m_feedbackRules.GetAlreadyExistsRules().Merge(newRules); } + else if(eResult == eResult_Rename) + { + spSrcFileInfo->SetDstRelativePath(PathFromWString(strNewPath)); + } } } + else if(eResult == eResult_Rename) + spSrcFileInfo->SetDstRelativePath(suggestedPath); return { eResult, bAutomatedResponse }; } Index: src/libchengine/FeedbackManager.h =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/FeedbackManager.h (.../FeedbackManager.h) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/FeedbackManager.h (.../FeedbackManager.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -40,7 +40,7 @@ FeedbackRules GetRules() const; TFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eFileError, unsigned long ulError); - TFeedbackResult FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo); + TFeedbackResult FileAlreadyExists(const TFileInfoPtr& spSrcFileInfo, const TFileInfo& rDstFileInfo, const chcore::TSmartPath& suggestedPath); TFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize); TFeedbackResult OperationEvent(EOperationEvent eEvent); Index: src/libchengine/IFeedbackHandler.h =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/IFeedbackHandler.h (.../IFeedbackHandler.h) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/IFeedbackHandler.h (.../IFeedbackHandler.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -39,7 +39,7 @@ virtual ~IFeedbackHandler(); virtual EFeedbackResult FileError(const string::TString& strSrcPath, const string::TString& strDstPath, EFileError eFileError, unsigned long ulError, FeedbackErrorRuleList& rNewRules) = 0; - virtual EFeedbackResult FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo, FeedbackAlreadyExistsRuleList& rNewRules) = 0; + virtual EFeedbackResult FileAlreadyExists(const TFileInfo& spSrcFileInfo, const TFileInfo& spDstFileInfo, string::TString& strRenameName, FeedbackAlreadyExistsRuleList& rNewRules) = 0; virtual EFeedbackResult NotEnoughSpace(const string::TString& strSrcPath, const string::TString& strDstPath, unsigned long long ullRequiredSize, FeedbackNotEnoughSpaceRuleList& rNewRules) = 0; virtual EFeedbackResult OperationEvent(EOperationEvent eEvent, FeedbackOperationEventRuleList& rNewRules) = 0; }; Index: src/libchengine/TDestinationPathProvider.cpp =================================================================== diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TDestinationPathProvider.cpp (.../TDestinationPathProvider.cpp) (revision 0d5b67ee96b435d63f7bf075dc8e28603793b187) +++ src/libchengine/TDestinationPathProvider.cpp (.../TDestinationPathProvider.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -27,7 +27,7 @@ throw TCoreException(eErr_InvalidArgument, L"spFilesystem", LOCATION); } - TSmartPath TDestinationPathProvider::CalculateDestinationPath(const TFileInfoPtr& spFileInfo) + TSmartPath TDestinationPathProvider::CalculateDestinationPath(const TFileInfoPtr& spFileInfo) const { if(!spFileInfo) throw TCoreException(eErr_InvalidArgument, L"spFileInfo", LOCATION); @@ -61,14 +61,63 @@ } } - TSmartPath pathResult = m_pathDestinationBase + spPathData->GetDestinationPath() + spFileInfo->GetFilePath(); + TSmartPath pathDstReplacement = spFileInfo->GetDstRelativePath(); + + TSmartPath pathResult = m_pathDestinationBase + spPathData->GetDestinationPath(); + if(pathDstReplacement.IsEmpty()) + pathResult += spFileInfo->GetFilePath(); + else + { + if(spFileInfo->GetFilePath().IsEmpty()) + { + pathResult.DeleteFileName(); + pathResult += pathDstReplacement; + } + else + pathResult += pathDstReplacement; + + } + pathResult.StripSeparatorAtEnd(); return pathResult; } - TSmartPath TDestinationPathProvider::CalculateForceDirectories(const TFileInfoPtr& spFileInfo) + chcore::TSmartPath TDestinationPathProvider::CalculateSuggestedDestinationPath(chcore::TSmartPath pathDst) const { + // get the name from src path + pathDst.StripSeparatorAtEnd(); + + TSmartPath pathFilename = pathDst.GetFileName(); + pathFilename.StripPath(L":"); + + // get rid of extracted filename to get the parent dir + pathDst.DeleteFileName(); + + // set the dest path + TString strCheckPath = m_strFirstAltName; + strCheckPath.Replace(_T("%name"), pathFilename.GetFileTitle().ToString()); + strCheckPath.Replace(_T("%ext"), pathFilename.GetExtension().ToString()); + + TSmartPath pathCheck(PathFromWString(strCheckPath)); + + // when adding to strDstPath check if the path already exists - if so - try again + int iCounter = 1; + TString strFmt = m_strNextAltName; + while(m_spFilesystem->PathExist(pathDst + pathCheck)) + { + strCheckPath = strFmt; + strCheckPath.Replace(_T("%name"), pathFilename.GetFileTitle().ToString()); + strCheckPath.Replace(_T("%ext"), pathFilename.GetExtension().ToString()); + strCheckPath.Replace(_T("%count"), boost::lexical_cast(++iCounter).c_str()); + pathCheck.FromString(strCheckPath); + } + + return pathCheck; + } + + TSmartPath TDestinationPathProvider::CalculateForceDirectories(const TFileInfoPtr& spFileInfo) const + { // force create directories TSmartPath tFileRoot = spFileInfo->GetFullFilePath().GetFileRoot(); tFileRoot.StripPath(L":"); @@ -86,7 +135,7 @@ return pathResult; } - TSmartPath TDestinationPathProvider::CalculateIgnoreDirectories(const TFileInfoPtr& spFileInfo) + TSmartPath TDestinationPathProvider::CalculateIgnoreDirectories(const TFileInfoPtr& spFileInfo) const { TSmartPath pathFilename = spFileInfo->GetFullFilePath(); pathFilename.StripPath(L":"); @@ -97,7 +146,7 @@ return pathResult; } - // finds another name for a copy of src file(folder) in dest location + // finds another name for a copy of src file(folder) in dest location; works only for paths that ends up directly in m_pathDestinationBase (without sub-directories) TSmartPath TDestinationPathProvider::FindFreeSubstituteName(TSmartPath pathSrcPath) const { // get the name from src path Index: src/libchengine/TDestinationPathProvider.h =================================================================== diff -u -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TDestinationPathProvider.h (.../TDestinationPathProvider.h) (revision 0d5b67ee96b435d63f7bf075dc8e28603793b187) +++ src/libchengine/TDestinationPathProvider.h (.../TDestinationPathProvider.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -31,11 +31,12 @@ TDestinationPathProvider(const IFilesystemPtr& spFilesystem, const chcore::TSmartPath& pathDestinationBase, bool bIgnoreFolders, bool bForceDirectories, const string::TString& strFirstAltName, const string::TString& strNextAltName); - chcore::TSmartPath CalculateDestinationPath(const TFileInfoPtr& spFileInfo); + chcore::TSmartPath CalculateDestinationPath(const TFileInfoPtr& spFileInfo) const; + chcore::TSmartPath CalculateSuggestedDestinationPath(chcore::TSmartPath pathDstPath) const; private: - chcore::TSmartPath CalculateForceDirectories(const TFileInfoPtr& spFileInfo); - chcore::TSmartPath CalculateIgnoreDirectories(const TFileInfoPtr& spFileInfo); + chcore::TSmartPath CalculateForceDirectories(const TFileInfoPtr& spFileInfo) const; + chcore::TSmartPath CalculateIgnoreDirectories(const TFileInfoPtr& spFileInfo) const; chcore::TSmartPath FindFreeSubstituteName(chcore::TSmartPath pathSrcPath) const; private: Index: src/libchengine/TFileInfo.cpp =================================================================== diff -u -r9ddf8fdd5f641491dd30c49eb90f8f740314b6af -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TFileInfo.cpp (.../TFileInfo.cpp) (revision 9ddf8fdd5f641491dd30c49eb90f8f740314b6af) +++ src/libchengine/TFileInfo.cpp (.../TFileInfo.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -39,6 +39,7 @@ TFileInfo::TFileInfo() : m_oidObjectID(0), m_pathFile(m_setModifications), + m_pathRelativeDstFile(m_setModifications), m_spBasePathData(m_setModifications), m_dwAttributes(m_setModifications, 0), m_uhFileSize(m_setModifications, 0), @@ -53,6 +54,7 @@ TFileInfo::TFileInfo(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, DWORD dwAttributes, ULONGLONG uhFileSize, const TFileTime& ftCreation, const TFileTime& ftLastAccess, const TFileTime& ftLastWrite, unsigned int uiFlags) : m_oidObjectID(0), m_pathFile(m_setModifications, rpathFile), + m_pathRelativeDstFile(m_setModifications), m_spBasePathData(m_setModifications, spBasePathData), m_dwAttributes(m_setModifications, dwAttributes), m_uhFileSize(m_setModifications, uhFileSize), @@ -74,6 +76,7 @@ unsigned int uiFlags) { m_pathFile = rpathFile; + m_pathRelativeDstFile.Modify().Clear(); m_spBasePathData = spBasePathData; m_dwAttributes = dwAttributes; m_uhFileSize = uhFileSize; @@ -90,6 +93,7 @@ unsigned int uiFlags) { m_pathFile = rpathFile; + m_pathRelativeDstFile.Modify().Clear(); m_spBasePathData.Modify().reset(); m_dwAttributes = dwAttributes; m_uhFileSize = uhFileSize; @@ -259,23 +263,26 @@ { if (m_setModifications.any()) { - ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, m_setModifications[eMod_Added]); + bool bAdded = m_setModifications[eMod_Added]; + ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, bAdded); - if (m_setModifications[eMod_Path]) + if(bAdded || m_setModifications[eMod_Path]) rRow.SetValue(_T("rel_path"), m_pathFile); - if (m_setModifications[eMod_BasePath]) + if(bAdded || m_setModifications[eMod_DstRelativePath]) + rRow.SetValue(_T("dst_rel_path"), m_pathRelativeDstFile); + if (bAdded || m_setModifications[eMod_BasePath]) rRow.SetValue(_T("base_path_id"), m_spBasePathData.Get()->GetObjectID()); - if (m_setModifications[eMod_Attributes]) + if (bAdded || m_setModifications[eMod_Attributes]) rRow.SetValue(_T("attr"), m_dwAttributes); - if (m_setModifications[eMod_FileSize]) + if (bAdded || m_setModifications[eMod_FileSize]) rRow.SetValue(_T("size"), m_uhFileSize); - if (m_setModifications[eMod_TimeCreated]) + if (bAdded || m_setModifications[eMod_TimeCreated]) rRow.SetValue(_T("time_created"), m_ftCreation.Get().ToUInt64()); - if (m_setModifications[eMod_TimeLastWrite]) + if (bAdded || m_setModifications[eMod_TimeLastWrite]) rRow.SetValue(_T("time_last_write"), m_ftLastWrite.Get().ToUInt64()); - if (m_setModifications[eMod_TimeLastAccess]) + if (bAdded || m_setModifications[eMod_TimeLastAccess]) rRow.SetValue(_T("time_last_access"), m_ftLastAccess.Get().ToUInt64()); - if (m_setModifications[eMod_Flags]) + if (bAdded || m_setModifications[eMod_Flags]) rRow.SetValue(_T("flags"), m_uiFlags); m_setModifications.reset(); @@ -286,6 +293,7 @@ { rColumns.AddColumn(_T("id"), ColumnType::value); rColumns.AddColumn(_T("rel_path"), IColumnsDefinition::eType_path); + rColumns.AddColumn(_T("dst_rel_path"), IColumnsDefinition::eType_path); rColumns.AddColumn(_T("base_path_id"), ColumnType::value); rColumns.AddColumn(_T("attr"), IColumnsDefinition::eType_ulong); rColumns.AddColumn(_T("size"), IColumnsDefinition::eType_ulonglong); @@ -301,6 +309,7 @@ unsigned long long ullTime = 0; spRowReader->GetValue(_T("id"), m_oidObjectID); spRowReader->GetValue(_T("rel_path"), m_pathFile.Modify()); + spRowReader->GetValue(_T("dst_rel_path"), m_pathRelativeDstFile.Modify()); spRowReader->GetValue(_T("base_path_id"), stBaseObjectID); spRowReader->GetValue(_T("attr"), m_dwAttributes.Modify()); spRowReader->GetValue(_T("size"), m_uhFileSize.Modify()); Index: src/libchengine/TFileInfo.h =================================================================== diff -u -r85b07e753393f661f7d8f528e4238ebb6e9e1204 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TFileInfo.h (.../TFileInfo.h) (revision 85b07e753393f661f7d8f528e4238ebb6e9e1204) +++ src/libchengine/TFileInfo.h (.../TFileInfo.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -72,6 +72,10 @@ chcore::TSmartPath GetFullFilePath() const; // returns full path void SetFilePath(const chcore::TSmartPath& tPath); + // dst file path + const chcore::TSmartPath& GetDstRelativePath() const { return m_pathRelativeDstFile; } + void SetDstRelativePath(const chcore::TSmartPath& tPath) { m_pathRelativeDstFile = tPath; } + // file size ULONGLONG GetLength64() const; void SetLength64(ULONGLONG uhSize); @@ -108,6 +112,7 @@ eMod_None = 0, eMod_Added, eMod_Path, + eMod_DstRelativePath, eMod_BasePath, eMod_Attributes, eMod_FileSize, @@ -128,6 +133,7 @@ serializer::object_id_t m_oidObjectID; serializer::TSharedModificationTracker m_pathFile; + serializer::TSharedModificationTracker m_pathRelativeDstFile; serializer::TSharedModificationTracker m_spBasePathData; serializer::TSharedModificationTracker m_dwAttributes; // attributes serializer::TSharedModificationTracker m_uhFileSize; Index: src/libchengine/TFilesystemFileFeedbackWrapper.cpp =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TFilesystemFileFeedbackWrapper.cpp (.../TFilesystemFileFeedbackWrapper.cpp) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TFilesystemFileFeedbackWrapper.cpp (.../TFilesystemFileFeedbackWrapper.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -46,16 +46,24 @@ throw TCoreException(eErr_InvalidArgument, L"spFilesystem is NULL", LOCATION); } - TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::HandleFileAlreadyExistsFB(const TFileInfoPtr& spSrcFileInfo, bool& bShouldAppend) + TSubTaskBase::ESubOperationResult TFilesystemFileFeedbackWrapper::HandleFileAlreadyExistsFB(const TFileInfoPtr& spSrcFileInfo, const TDestinationPathProvider& rDstPathProvider, bool& bShouldAppend, bool& bShouldRename) { bShouldAppend = false; + bShouldRename = false; // read info about the existing destination file, TFileInfo tDstFileInfo; m_spFile->GetFileInfo(tDstFileInfo); + // calculate suggested destination filename + TSmartPath pathOriginalPlannedDestination = tDstFileInfo.GetFullFilePath(); + pathOriginalPlannedDestination.DeleteFileName(); + pathOriginalPlannedDestination += spSrcFileInfo->GetFullFilePath().GetFileName(); + + TSmartPath suggestedPath = rDstPathProvider.CalculateSuggestedDestinationPath(pathOriginalPlannedDestination); + // src and dst files are the same - TFeedbackResult frResult = m_spFeedbackManager->FileAlreadyExists(*spSrcFileInfo, tDstFileInfo); + TFeedbackResult frResult = m_spFeedbackManager->FileAlreadyExists(spSrcFileInfo, tDstFileInfo, suggestedPath); switch(frResult.GetResult()) { case eResult_Overwrite: @@ -81,6 +89,10 @@ case eResult_Pause: return TSubTaskBase::eSubResult_PauseRequest; + case eResult_Rename: + bShouldRename = true; + return TSubTaskBase::eSubResult_Continue; + default: BOOST_ASSERT(FALSE); // unknown result throw TCoreException(eErr_UnhandledCase, L"Feedback result unknown", LOCATION); Index: src/libchengine/TFilesystemFileFeedbackWrapper.h =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TFilesystemFileFeedbackWrapper.h (.../TFilesystemFileFeedbackWrapper.h) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TFilesystemFileFeedbackWrapper.h (.../TFilesystemFileFeedbackWrapper.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -24,6 +24,7 @@ #include "IFilesystem.h" #include "../liblogger/TLogger.h" #include "FeedbackManager.h" +#include "TDestinationPathProvider.h" namespace chcore { @@ -40,7 +41,7 @@ const IFilesystemPtr& spFilesystem); TFilesystemFileFeedbackWrapper& operator=(const TFilesystemFileFeedbackWrapper&) = delete; - TSubTaskBase::ESubOperationResult HandleFileAlreadyExistsFB(const TFileInfoPtr& spSrcFileInfo, bool& bShouldAppend); + TSubTaskBase::ESubOperationResult HandleFileAlreadyExistsFB(const TFileInfoPtr& spSrcFileInfo, const TDestinationPathProvider& rDstPathProvider, bool& bShouldAppend, bool& bShouldRename); TSubTaskBase::ESubOperationResult TruncateFileFB(file_size_t fsNewSize); Index: src/libchengine/TOverlappedReaderWriterFB.cpp =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TOverlappedReaderWriterFB.cpp (.../TOverlappedReaderWriterFB.cpp) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TOverlappedReaderWriterFB.cpp (.../TOverlappedReaderWriterFB.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -28,7 +28,7 @@ TWorkerThreadController& rThreadController, TOverlappedThreadPool& rThreadPool, const TFileInfoPtr& spSrcFileInfo, - const TSmartPath& pathDst, + const TDestinationPathProvider& rDstPathProvider, const TSubTaskStatsInfoPtr& spStats, const logger::TLogFileDataPtr& spLogFileData, const TOverlappedMemoryPoolPtr& spMemoryPool, @@ -48,7 +48,7 @@ m_spRange(std::make_shared(ullResumePosition)), m_spMemoryPool(spMemoryPool), m_spReader(std::make_shared(spFilesystem, spFeedbackManager, rThreadController, spStats, spSrcFileInfo, spLogFileData, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), m_spRange, dwChunkSize, uiMaxConcurrentReads, uiMaxReadAhead, bNoBuffering, bProtectReadOnlyFiles)), - m_spWriter(std::make_shared(spFilesystem, spFeedbackManager, rThreadController, spStats, spSrcFileInfo, pathDst, spLogFileData, m_spReader->GetFinishedQueue(), m_spRange, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), uiMaxConcurrentWrites, bOnlyCreate, bNoBuffering, bProtectReadOnlyFiles, bUpdateFileAttributesAndTimes)) + m_spWriter(std::make_shared(spFilesystem, spFeedbackManager, rThreadController, spStats, spSrcFileInfo, rDstPathProvider, spLogFileData, m_spReader->GetFinishedQueue(), m_spRange, spMemoryPool ? spMemoryPool->GetBufferList() : TBufferListPtr(), uiMaxConcurrentWrites, bOnlyCreate, bNoBuffering, bProtectReadOnlyFiles, bUpdateFileAttributesAndTimes)) { } Index: src/libchengine/TOverlappedReaderWriterFB.h =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TOverlappedReaderWriterFB.h (.../TOverlappedReaderWriterFB.h) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TOverlappedReaderWriterFB.h (.../TOverlappedReaderWriterFB.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -38,7 +38,7 @@ TWorkerThreadController& rThreadController, TOverlappedThreadPool& rThreadPool, const TFileInfoPtr& spSrcFileInfo, - const TSmartPath& pathDst, + const TDestinationPathProvider& rDstPathProvider, const TSubTaskStatsInfoPtr& spStats, const logger::TLogFileDataPtr& spLogFileData, const TOverlappedMemoryPoolPtr& spBuffers, Index: src/libchengine/TOverlappedWriterFB.cpp =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TOverlappedWriterFB.cpp (.../TOverlappedWriterFB.cpp) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TOverlappedWriterFB.cpp (.../TOverlappedWriterFB.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -33,7 +33,7 @@ TWorkerThreadController& rThreadController, const TSubTaskStatsInfoPtr& spStats, const TFileInfoPtr& spSrcFileInfo, - const TSmartPath& pathDst, + const TDestinationPathProvider& rDstPathProvider, const logger::TLogFileDataPtr& spLogFileData, const TOrderedBufferQueuePtr& spBuffersToWrite, const TOverlappedProcessorRangePtr& spRange, @@ -43,6 +43,7 @@ bool bNoBuffering, bool bProtectReadOnlyFiles, bool bUpdateFileAttributesAndTimes) : + m_counterOnTheFly(), m_spWriter(std::make_shared(spLogFileData, spBuffersToWrite, spRange, spEmptyBuffers, stMaxOtfBuffers, m_counterOnTheFly.GetSharedCount())), m_spStats(spStats), @@ -54,7 +55,13 @@ m_eventWritingFinished(true, false), m_eventLocalKill(true, false), m_rThreadController(rThreadController), - m_spLog(logger::MakeLogger(spLogFileData, L"File-Writer")) + m_spLog(logger::MakeLogger(spLogFileData, L"File-Writer")), + m_spFilesystem(spFilesystem), + m_rDstPathProvider(rDstPathProvider), + m_spFeedbackManager(spFeedbackManager), + m_spLogFileData(spLogFileData), + m_bNoBuffering(bNoBuffering), + m_bProtectReadOnlyFiles(bProtectReadOnlyFiles) { if(!spFilesystem) throw TCoreException(eErr_InvalidArgument, L"spFilesystem is NULL", LOCATION); @@ -72,9 +79,6 @@ throw TCoreException(eErr_InvalidArgument, L"spLogFileData is NULL", LOCATION); if(!spBuffersToWrite) throw TCoreException(eErr_InvalidArgument, L"spBuffersToWrite is NULL", LOCATION); - - IFilesystemFilePtr fileDst = spFilesystem->CreateFileObject(IFilesystemFile::eMode_Write, pathDst, bNoBuffering, bProtectReadOnlyFiles); - m_spDstFile = std::make_shared(fileDst, spFeedbackManager, spLogFileData, rThreadController, spFilesystem); } TOverlappedWriterFB::~TOverlappedWriterFB() @@ -219,50 +223,73 @@ TSubTaskBase::ESubOperationResult TOverlappedWriterFB::Start() { - // open destination file, handle the failures and possibly existence of the destination file unsigned long long ullProcessedSize = m_spStats->GetCurrentItemProcessedSize(); unsigned long long ullSeekTo = ullProcessedSize; - bool bDstFileFreshlyCreated = false; - TSubTaskBase::ESubOperationResult eResult = m_spDstFile->IsFreshlyCreated(bDstFileFreshlyCreated); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; + TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; - file_size_t fsDstFileSize = 0; - eResult = m_spDstFile->GetFileSize(fsDstFileSize); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - - // try to resume if possible - bool bCanSilentResume = false; - if(m_spStats->CanCurrentItemSilentResume()) + bool bRetryAfterRename = false; + do { - if(fsDstFileSize == ullProcessedSize && fsDstFileSize <= m_spSrcFileInfo->GetLength64()) + bRetryAfterRename = false; + + TSmartPath pathFullDst = m_rDstPathProvider.CalculateDestinationPath(m_spSrcFileInfo); + + IFilesystemFilePtr fileDst = m_spFilesystem->CreateFileObject(IFilesystemFile::eMode_Write, pathFullDst, m_bNoBuffering, m_bProtectReadOnlyFiles); + m_spDstFile = std::make_shared(fileDst, m_spFeedbackManager, m_spLogFileData, m_rThreadController, m_spFilesystem); + + // open destination file, handle the failures and possibly existence of the destination file + bDstFileFreshlyCreated = false; + eResult = m_spDstFile->IsFreshlyCreated(bDstFileFreshlyCreated); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + file_size_t fsDstFileSize = 0; + eResult = m_spDstFile->GetFileSize(fsDstFileSize); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; + + // try to resume if possible + bool bCanSilentResume = false; + if(m_spStats->CanCurrentItemSilentResume()) { - ullSeekTo = fsDstFileSize; - bCanSilentResume = true; + if(fsDstFileSize == ullProcessedSize && fsDstFileSize <= m_spSrcFileInfo->GetLength64()) + { + ullSeekTo = fsDstFileSize; + bCanSilentResume = true; + } + else if(fsDstFileSize > ullProcessedSize && fsDstFileSize - ullProcessedSize == IFilesystemFile::MaxSectorSize && + m_spSrcFileInfo->GetLength64() > ullProcessedSize && m_spSrcFileInfo->GetLength64() < fsDstFileSize) + { + // special case - resuming file that was not finalized completely last time + ullSeekTo = ullProcessedSize; + bCanSilentResume = true; + } } - else if(fsDstFileSize > ullProcessedSize && fsDstFileSize - ullProcessedSize == IFilesystemFile::MaxSectorSize && - m_spSrcFileInfo->GetLength64() > ullProcessedSize && m_spSrcFileInfo->GetLength64() < fsDstFileSize) + + if(!bCanSilentResume && !bDstFileFreshlyCreated && fsDstFileSize > 0) { - // special case - resuming file that was not finalized completely last time - ullSeekTo = ullProcessedSize; - bCanSilentResume = true; - } - } + bool bShouldAppend = false; + bool bShouldRename = false; - if(!bCanSilentResume && !bDstFileFreshlyCreated && fsDstFileSize > 0) - { - bool bShouldAppend = false; - eResult = m_spDstFile->HandleFileAlreadyExistsFB(m_spSrcFileInfo, bShouldAppend); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; + eResult = m_spDstFile->HandleFileAlreadyExistsFB(m_spSrcFileInfo, m_rDstPathProvider, bShouldAppend, bShouldRename); + if(eResult != TSubTaskBase::eSubResult_Continue) + return eResult; - if(bShouldAppend) - ullSeekTo = std::min(fsDstFileSize, m_spSrcFileInfo->GetLength64()); - else - ullSeekTo = 0; + if(bShouldRename) + { + bRetryAfterRename = true; + ullSeekTo = 0; + m_spDstFile->Close(); + m_spDstFile.reset(); + } + if(bShouldAppend) + ullSeekTo = std::min(fsDstFileSize, m_spSrcFileInfo->GetLength64()); + else + ullSeekTo = 0; + } } + while(bRetryAfterRename); if(m_bOnlyCreate) { Index: src/libchengine/TOverlappedWriterFB.h =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TOverlappedWriterFB.h (.../TOverlappedWriterFB.h) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TOverlappedWriterFB.h (.../TOverlappedWriterFB.h) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -24,6 +24,7 @@ #include "TOverlappedProcessorRange.h" #include "TThreadedQueueRunner.h" #include "TEventCounter.h" +#include "TDestinationPathProvider.h" using namespace chcore; @@ -37,7 +38,7 @@ TWorkerThreadController& rThreadController, const TSubTaskStatsInfoPtr& spStats, const TFileInfoPtr& spSrcFileInfo, - const TSmartPath& pathDst, + const TDestinationPathProvider& rDstPathProvider, const logger::TLogFileDataPtr& spLogFileData, const TOrderedBufferQueuePtr& spBuffersToWrite, const TOverlappedProcessorRangePtr& spRange, @@ -87,6 +88,13 @@ bool m_bOnlyCreate = false; bool m_bUpdateFileAttributesAndTimes = false; + IFilesystemPtr m_spFilesystem; + const TDestinationPathProvider& m_rDstPathProvider; + FeedbackManagerPtr m_spFeedbackManager; + logger::TLogFileDataPtr m_spLogFileData; + bool m_bNoBuffering = false; + bool m_bProtectReadOnlyFiles = false; + TEvent m_eventProcessingFinished; TEvent m_eventWritingFinished; TEvent m_eventLocalKill; Index: src/libchengine/TSubTaskCopyMove.cpp =================================================================== diff -u -r08717141ce5f6926116c298cbc9442094a45bb67 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libchengine/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 08717141ce5f6926116c298cbc9442094a45bb67) +++ src/libchengine/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -57,7 +57,7 @@ } TFileInfoPtr spSrcFile; // CFileInfo - src file - TSmartPath pathDstFile; // dest path with filename + TDestinationPathProvider* pDstPathProvider = nullptr; TBufferSizes tBufferSizes; TOverlappedMemoryPoolPtr spMemoryPool; // buffer handling @@ -209,16 +209,14 @@ continue; } - // set dest path with filename - ccp.pathDstFile = tDstPathProvider.CalculateDestinationPath(spFileInfo); - // are the files/folders lie on the same partition ? bool bMove = GetContext().GetOperationType() == eOperation_Move; // if folder - create it if(spFileInfo->IsDirectory()) { - eResult = tFilesystemFBWrapper.CreateDirectoryFB(ccp.pathDstFile); + TSmartPath pathDstFile = tDstPathProvider.CalculateDestinationPath(spFileInfo); + eResult = tFilesystemFBWrapper.CreateDirectoryFB(pathDstFile); if(eResult == eSubResult_SkipFile) { spFileInfo->MarkAsProcessed(false); @@ -231,7 +229,7 @@ } else { - // start copying/moving file + ccp.pDstPathProvider = &tDstPathProvider; ccp.spSrcFile = spFileInfo; // copy data @@ -377,7 +375,7 @@ rThreadController, rThreadPool, pData->spSrcFile, - pData->pathDstFile, + *pData->pDstPathProvider, m_spSubTaskStats, m_spLog->GetLogFileData(), pData->spMemoryPool, Index: src/libserializer/TSQLiteTaskSchema.cpp =================================================================== diff -u -r9229cae5bff1308d7b096a0bd10d3dc3723918f9 -rb9453afbc6264bc3f3c6a7f86fadab7744e0fb16 --- src/libserializer/TSQLiteTaskSchema.cpp (.../TSQLiteTaskSchema.cpp) (revision 9229cae5bff1308d7b096a0bd10d3dc3723918f9) +++ src/libserializer/TSQLiteTaskSchema.cpp (.../TSQLiteTaskSchema.cpp) (revision b9453afbc6264bc3f3c6a7f86fadab7744e0fb16) @@ -79,7 +79,7 @@ tStatement.Prepare(_T("CREATE TABLE base_paths(id BIGINT UNIQUE, src_path varchar(32768) NOT NULL, skip_processing boolean NOT NULL, dst_path varchar(32768) NOT NULL)")); tStatement.Step(); - tStatement.Prepare(_T("CREATE TABLE scanned_files(id BIGINT UNIQUE, rel_path varchar(32768) NOT NULL, base_path_id BIGINT NOT NULL, attr INT NOT NULL, size BIGINT NOT NULL, time_created BIGINT NOT NULL, time_last_write BIGINT NOT NULL, time_last_access BIGINT NOT NULL, flags INT NOT NULL)")); + tStatement.Prepare(_T("CREATE TABLE scanned_files(id BIGINT UNIQUE, rel_path varchar(32768) NOT NULL, dst_rel_path varchar(32768) NOT NULL DEFAULT '', base_path_id BIGINT NOT NULL, attr INT NOT NULL, size BIGINT NOT NULL, time_created BIGINT NOT NULL, time_last_write BIGINT NOT NULL, time_last_access BIGINT NOT NULL, flags INT NOT NULL)")); tStatement.Step(); tStatement.Prepare(_T("CREATE TABLE task_config(id BIGINT UNIQUE, name varchar(256) NOT NULL, node_order INT NOT NULL, value varchar(32768) NOT NULL)")); @@ -316,6 +316,10 @@ _T("result INT NOT NULL)")); tStatement.Step(); + // adjust scanned_paths to include destination path + tStatement.Prepare(_T("ALTER TABLE scanned_files ADD COLUMN dst_rel_path varchar(32768) NOT NULL DEFAULT ''")); + tStatement.Step(); + tVersion.SetVersion(7); } }