Index: src/ch/task.cpp =================================================================== diff -u -N -r49b67b7417f8b42ce581ebfe604f47df841f763b -r9c71c0a84781c524c0091ee86914d5cc3bbf5190 --- src/ch/task.cpp (.../task.cpp) (revision 49b67b7417f8b42ce581ebfe604f47df841f763b) +++ src/ch/task.cpp (.../task.cpp) (revision 9c71c0a84781c524c0091ee86914d5cc3bbf5190) @@ -21,7 +21,11 @@ #include "StringHelpers.h" #include "../common/FileSupport.h" #include "ch.h" +#include "FeedbackHandler.h" +// assume max sectors of 4kB (for rounding) +#define MAXSECTORSIZE 4096 + //////////////////////////////////////////////////////////////////////////// // CTask members @@ -49,7 +53,6 @@ m_bKill=false; m_bKilled=true; m_pcs=pCreateData->pcs; - m_pfnTaskProc=pCreateData->pfnTaskProc; m_lTimeElapsed=0; m_lLastTime=-1; m_puiOperationsPending=pCreateData->puiOperationsPending; @@ -639,7 +642,7 @@ m_bSaved=false; // save SetKillFlag(false); SetKilledFlag(false); - CWinThread* pThread=AfxBeginThread(m_pfnTaskProc, this, GetPriority()); + CWinThread* pThread=AfxBeginThread(ThrdProc, this, GetPriority()); m_cs.Lock(); m_pThread=pThread; @@ -1112,12 +1115,11 @@ // NOTE: do not delete the feedback factory, since we are not responsible for releasing it } -void CTaskArray::Create(chcore::IFeedbackHandlerFactory* piFeedbackHandlerFactory, UINT (*pfnTaskProc)(LPVOID pParam)) +void CTaskArray::Create(chcore::IFeedbackHandlerFactory* piFeedbackHandlerFactory) { - BOOST_ASSERT(piFeedbackHandlerFactory && pfnTaskProc); + BOOST_ASSERT(piFeedbackHandlerFactory); m_tcd.pcs=&m_cs; - m_tcd.pfnTaskProc=pfnTaskProc; m_tcd.pTasksAll=&m_uhRange; m_tcd.pTasksProcessed=&m_uhPosition; m_tcd.puiOperationsPending=&m_uiOperationsPending; @@ -1494,3 +1496,1006 @@ m_cs.Unlock(); return bFlag; } + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// case insensitive replacement +void CTask::ReplaceNoCase(CString& rString, CString strOld, CString strNew) +{ + if (rString.Left(strOld.GetLength()).CompareNoCase(strOld) == 0) + rString=strNew+rString.Right(rString.GetLength()-strOld.GetLength()); +} + +bool CTask::TimeToFileTime(const COleDateTime& time, LPFILETIME pFileTime) +{ + SYSTEMTIME sysTime; + sysTime.wYear = (WORD)time.GetYear(); + sysTime.wMonth = (WORD)time.GetMonth(); + sysTime.wDay = (WORD)time.GetDay(); + sysTime.wHour = (WORD)time.GetHour(); + sysTime.wMinute = (WORD)time.GetMinute(); + sysTime.wSecond = (WORD)time.GetSecond(); + sysTime.wMilliseconds = 0; + + // convert system time to local file time + FILETIME localTime; + if (!SystemTimeToFileTime((LPSYSTEMTIME)&sysTime, &localTime)) + return false; + + // convert local file time to UTC file time + if (!LocalFileTimeToFileTime(&localTime, pFileTime)) + return false; + + return true; +} + +bool CTask::SetFileDirectoryTime(LPCTSTR lpszName, CFileInfo* pSrcInfo) +{ + FILETIME creation, lastAccess, lastWrite; + + if (!TimeToFileTime(pSrcInfo->GetCreationTime(), &creation) + || !TimeToFileTime(pSrcInfo->GetLastAccessTime(), &lastAccess) + || !TimeToFileTime(pSrcInfo->GetLastWriteTime(), &lastWrite) ) + return false; + + HANDLE handle=CreateFile(lpszName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + return false; + + if (!SetFileTime(handle, &creation, &lastAccess, &lastWrite)) + { + CloseHandle(handle); + return false; + } + + if (!CloseHandle(handle)) + return false; + + return true; +} + +// searching for files +void CTask::RecurseDirectories(CTask* pTask) +{ + TRACE("Searching for files...\n"); + + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFSEARCHINGFORFILES_STRING)); + + // update status + pTask->SetStatus(ST_SEARCHING, ST_STEP_MASK); + + // delete the content of m_files + pTask->FilesRemoveAll(); + + // enter some data to m_files + int nSize=pTask->GetClipboardDataSize(); // size of m_clipboard + const CFiltersArray* pFilters=pTask->GetFilters(); + int iDestDrvNumber=pTask->GetDestDriveNumber(); + bool bIgnoreDirs=(pTask->GetStatus(ST_SPECIAL_MASK) & ST_IGNORE_DIRS) != 0; + bool bForceDirectories=(pTask->GetStatus(ST_SPECIAL_MASK) & ST_FORCE_DIRS) != 0; + bool bMove=pTask->GetStatus(ST_OPERATION_MASK) == ST_MOVE; + CFileInfo fi; + fi.SetClipboard(pTask->GetClipboard()); + + // add everything + ictranslate::CFormat fmt; + for (int i=0;iGetClipboardData(i)->GetPath(), i)) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFMISSINGCLIPBOARDINPUT_STRING)); + fmt.SetParam(_t("%path"), pTask->GetClipboardData(i)->GetPath()); + pTask->m_log.logw(fmt); + continue; + } + else + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFADDINGCLIPBOARDFILE_STRING)); + fmt.SetParam(_t("%path"), pTask->GetClipboardData(i)->GetPath()); + pTask->m_log.logi(fmt); + } + + // found file/folder - check if the dest name has been generated + if (pTask->GetClipboardData(i)->m_astrDstPaths.GetSize() == 0) + { + // generate something - if dest folder == src folder - search for copy + if (pTask->GetDestPath().GetPath() == fi.GetFileRoot()) + { + CString strSubst; + FindFreeSubstituteName(fi.GetFullFilePath(), pTask->GetDestPath().GetPath(), &strSubst); + pTask->GetClipboardData(i)->m_astrDstPaths.Add(strSubst); + } + else + pTask->GetClipboardData(i)->m_astrDstPaths.Add(fi.GetFileName()); + } + + // add if needed + if (fi.IsDirectory()) + { + // add if folder's aren't ignored + if (!bIgnoreDirs && !bForceDirectories) + { + pTask->FilesAdd(fi); + + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFADDEDFOLDER_STRING)); + fmt.SetParam(_t("%path"), fi.GetFullFilePath()); + pTask->m_log.logi(fmt); + } + + // don't add folder contents when moving inside one disk boundary + if (bIgnoreDirs || !bMove || pTask->GetCopies() > 1 || iDestDrvNumber == -1 + || iDestDrvNumber != fi.GetDriveNumber() || CFileInfo::Exist(fi.GetDestinationPath(pTask->GetDestPath().GetPath(), 0, ((int)bForceDirectories) << 1)) ) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFRECURSINGFOLDER_STRING)); + fmt.SetParam(_t("%path"), fi.GetFullFilePath()); + pTask->m_log.logi(fmt); + + // no movefile possibility - use CustomCopyFile + pTask->GetClipboardData(i)->SetMove(false); + + pTask->FilesAddDir(fi.GetFullFilePath(), pFilters, i, true, !bIgnoreDirs || bForceDirectories); + } + + // check for kill need + if (pTask->GetKillFlag()) + { + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFADDINGKILLREQEST_STRING)); + throw new CProcessingException(E_KILL_REQUEST, pTask); + } + } + else + { + if (bMove && pTask->GetCopies() == 1 && iDestDrvNumber != -1 && iDestDrvNumber == fi.GetDriveNumber() && + !CFileInfo::Exist(fi.GetDestinationPath(pTask->GetDestPath().GetPath(), 0, ((int)bForceDirectories) << 1)) ) + { + // if moving within one partition boundary set the file size to 0 so the overall size will + // be ok + fi.SetLength64(0); + } + else + pTask->GetClipboardData(i)->SetMove(false); // no MoveFile + + pTask->FilesAdd(fi); // file - add + + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFADDEDFILE_STRING)); + fmt.SetParam(_t("%path"), fi.GetFullFilePath()); + pTask->m_log.logi(fmt); + } + } + + // calc size of all files + pTask->CalcAllSize(); + + // update *m_pnTasksAll; + pTask->IncreaseAllTasksSize(pTask->GetAllSize()); + + // change state to ST_COPYING - finished searching for files + pTask->SetStatus(ST_COPYING, ST_STEP_MASK); + + // save task status + pTask->Store(true); + pTask->Store(false); + + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFSEARCHINGFINISHED_STRING)); +} + +// delete files - after copying +void CTask::DeleteFiles(CTask* pTask) +{ + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFDELETINGFILES_STRING)); + + // current processed path + BOOL bSuccess; + CFileInfo fi; + ictranslate::CFormat fmt; + + // index points to 0 or next item to process + for (int i=pTask->GetCurrentIndex();iFilesGetSize();i++) + { + // set index in pTask to currently deleted element + pTask->SetCurrentIndex(i); + + // check for kill flag + if (pTask->GetKillFlag()) + { + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFDELETINGKILLREQUEST_STRING)); + throw new CProcessingException(E_KILL_REQUEST, pTask); + } + + // current processed element + fi=pTask->FilesGetAt(pTask->FilesGetSize()-i-1); + if(!(fi.GetFlags() & FIF_PROCESSED)) + continue; + + // delete data + if (fi.IsDirectory()) + { + if (!GetConfig().get_bool(PP_CMPROTECTROFILES)) + SetFileAttributes(fi.GetFullFilePath(), FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY); + bSuccess=RemoveDirectory(fi.GetFullFilePath()); + } + else + { + // set files attributes to normal - it'd slow processing a bit, but it's better. + if (!GetConfig().get_bool(PP_CMPROTECTROFILES)) + SetFileAttributes(fi.GetFullFilePath(), FILE_ATTRIBUTE_NORMAL); + bSuccess=DeleteFile(fi.GetFullFilePath()); + } + + // operation failed + DWORD dwLastError=GetLastError(); + if (!bSuccess && dwLastError != ERROR_PATH_NOT_FOUND && dwLastError != ERROR_FILE_NOT_FOUND) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFDELETINGERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), fi.GetFullFilePath()); + pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pTask, dwLastError, fmt); + } + }//for + + // change status to finished + pTask->SetStatus(ST_FINISHED, ST_STEP_MASK); + + // add 1 to current index - looks better + pTask->IncreaseCurrentIndex(); + + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFDELETINGFINISHED_STRING)); +} + +void CTask::CustomCopyFile(CUSTOM_COPY_PARAMS* pData) +{ + HANDLE hSrc=INVALID_HANDLE_VALUE, hDst=INVALID_HANDLE_VALUE; + ictranslate::CFormat fmt; + try + { + // do we copy rest or recopy ? + bool bCopyRest=GetConfig().get_bool(PP_CMUSEAUTOCOMPLETEFILES); + + // Data regarding dest file + CFileInfo fiDest; + bool bExist=fiDest.Create(pData->strDstFile, -1); + + chcore::IFeedbackHandler* piFeedbackHandler = pData->pTask->GetFeedbackHandler(); + BOOST_ASSERT(piFeedbackHandler); + + pData->pTask->SetLastProcessedIndex(-1); + + // if dest file size >0 - we can do somethng more than usual + if(bExist) + { + // src and dst files are the same + FEEDBACK_ALREADYEXISTS feedStruct = { pData->pfiSrcFile, &fiDest }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileAlreadyExists, &feedStruct); + // check for dialog result + switch(frResult) + { + case CFeedbackHandler::eResult_Overwrite: + { + bCopyRest=false; + break; + } + case CFeedbackHandler::eResult_CopyRest: + { + bCopyRest=true; + break; + } + case CFeedbackHandler::eResult_Skip: + { + pData->pTask->IncreaseProcessedSize(pData->pfiSrcFile->GetLength64()); + pData->pTask->IncreaseProcessedTasksSize(pData->pfiSrcFile->GetLength64()); + pData->bProcessed = false; + return; + } + case CFeedbackHandler::eResult_Cancel: + { + // log + if (GetConfig().get_bool(PP_CMCREATELOG)) + { + fmt.SetFormat(GetResManager().LoadString(IDS_OTFPRECHECKCANCELREQUEST_STRING)); + fmt.SetParam(_t("%path"), pData->pfiSrcFile->GetFullFilePath()); + pData->pTask->m_log.logi(fmt); + } + throw new CProcessingException(E_CANCEL, pData->pTask); + break; + } + case CFeedbackHandler::eResult_Pause: + { + throw new CProcessingException(E_PAUSE, pData->pTask); + break; + } + default: + { + BOOST_ASSERT(FALSE); // unknown result + throw new CProcessingException(E_ERROR, pData->pTask, 0, _t("Unknown feedback result type")); + break; + } + } + }// bExist + + // change attributes of a dest file + if (!GetConfig().get_bool(PP_CMPROTECTROFILES)) + SetFileAttributes(pData->strDstFile, FILE_ATTRIBUTE_NORMAL); + + // first or second pass ? only for FFNB + bool bFirstPass=true; + + // check size of src file to know whether use flag FILE_FLAG_NOBUFFERING +l_start: + bool bNoBuffer=(bFirstPass && GetConfig().get_bool(PP_BFUSENOBUFFERING) && pData->pfiSrcFile->GetLength64() >= (unsigned long long)GetConfig().get_signed_num(PP_BFBOUNDARYLIMIT)); + + // refresh data about file + if (!bFirstPass) + bExist=fiDest.Create(pData->strDstFile, -1); + + // open src +l_openingsrc: + hSrc=CreateFile(pData->pfiSrcFile->GetFullFilePath(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffer ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + if (hSrc == INVALID_HANDLE_VALUE) + { + DWORD dwLastError=GetLastError(); + CString strFile = pData->pfiSrcFile->GetFullFilePath(); + FEEDBACK_FILEERROR feedStruct = { (PCTSTR)strFile, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); + + switch (frResult) + { + case CFeedbackHandler::eResult_Skip: + pData->pTask->IncreaseProcessedSize(pData->pfiSrcFile->GetLength64()); + pData->pTask->IncreaseProcessedTasksSize(pData->pfiSrcFile->GetLength64()); + pData->bProcessed = false; + return; + break; + case CFeedbackHandler::eResult_Cancel: + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFOPENINGCANCELREQUEST_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pData->pfiSrcFile->GetFullFilePath()); + pData->pTask->m_log.loge(fmt); + throw new CProcessingException(E_CANCEL, pData->pTask); + break; + case CFeedbackHandler::eResult_Pause: + throw new CProcessingException(E_PAUSE, pData->pTask); + break; + case CFeedbackHandler::eResult_Retry: + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFOPENINGRETRY_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pData->pfiSrcFile->GetFullFilePath()); + pData->pTask->m_log.loge(fmt); + goto l_openingsrc; + break; + default: + { + BOOST_ASSERT(FALSE); // unknown result + throw new CProcessingException(E_ERROR, pData->pTask, 0, _t("Unknown feedback result type")); + break; + } + } + } + + // open dest +l_openingdst: + hDst=CreateFile(pData->strDstFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffer ? FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH : 0), NULL); + if (hDst == INVALID_HANDLE_VALUE) + { + DWORD dwLastError=GetLastError(); + CString strFile = pData->strDstFile; + + FEEDBACK_FILEERROR feedStruct = { (PCTSTR)strFile, dwLastError }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &feedStruct); + switch (frResult) + { + case CFeedbackHandler::eResult_Retry: + // change attributes + if (!GetConfig().get_bool(PP_CMPROTECTROFILES)) + SetFileAttributes(pData->strDstFile, FILE_ATTRIBUTE_NORMAL); + + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFDESTOPENINGRETRY_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pData->strDstFile); + pData->pTask->m_log.loge(fmt); + goto l_openingdst; + break; + case CFeedbackHandler::eResult_Cancel: + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFDESTOPENINGCANCELREQUEST_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pData->strDstFile); + pData->pTask->m_log.loge(fmt); + throw new CProcessingException(E_CANCEL, pData->pTask); + break; + case CFeedbackHandler::eResult_Skip: + pData->pTask->IncreaseProcessedSize(pData->pfiSrcFile->GetLength64()); + pData->pTask->IncreaseProcessedTasksSize(pData->pfiSrcFile->GetLength64()); + pData->bProcessed = false; + return; + break; + case CFeedbackHandler::eResult_Pause: + throw new CProcessingException(E_PAUSE, pData->pTask); + break; + default: + { + BOOST_ASSERT(FALSE); // unknown result + throw new CProcessingException(E_ERROR, pData->pTask, 0, _t("Unknown feedback result type")); + break; + } + } + } + + // seeking + DWORD dwLastError=0; + if (!pData->bOnlyCreate) + { + if ( bCopyRest ) // if copy rest + { + if (!bFirstPass || (bExist && fiDest.GetLength64() > 0)) + { + // try to move file pointers to the end + ULONGLONG ullMove=(bNoBuffer ? ROUNDDOWN(fiDest.GetLength64(), MAXSECTORSIZE) : fiDest.GetLength64()); + if (SetFilePointer64(hSrc, ullMove, FILE_BEGIN) == -1 || SetFilePointer64(hDst, ullMove, FILE_BEGIN) == -1) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFMOVINGPOINTERSERROR_STRING)); + fmt.SetParam(_t("%errno"), GetLastError()); + fmt.SetParam(_t("%srcpath"), pData->pfiSrcFile->GetFullFilePath()); + fmt.SetParam(_t("%dstpath"), pData->strDstFile); + fmt.SetParam(_t("%pos"), ullMove); + pData->pTask->m_log.loge(fmt); + + // seek failed - seek to begin + if (SetFilePointer64(hSrc, 0, FILE_BEGIN) == -1 || SetFilePointer64(hDst, 0, FILE_BEGIN) == -1) + { + // log + dwLastError=GetLastError(); + fmt.SetFormat(GetResManager().LoadString(IDS_OTFRESTORINGPOINTERSERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%srcpath"), pData->pfiSrcFile->GetFullFilePath()); + fmt.SetParam(_t("%dstpath"), pData->strDstFile); + pData->pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pData->pTask, dwLastError, fmt); + } + else + { + // file pointers restored - if second pass subtract what's needed + if (!bFirstPass) + { + pData->pTask->IncreaseProcessedSize(-static_cast<__int64>(ullMove)); + pData->pTask->IncreaseProcessedTasksSize(-static_cast<__int64>(ullMove)); + } + } + } + else + { + // file pointers moved - so we have skipped some work - update positions + if (bFirstPass) // przy drugim obiegu jest ju� uwzgl�dnione + { + pData->pTask->IncreaseProcessedSize(ullMove); + pData->pTask->IncreaseProcessedTasksSize(ullMove); + } + } + } + } + else + if (!SetEndOfFile(hDst)) // if recopying - reset the dest file + { + // log + dwLastError=GetLastError(); + fmt.SetFormat(GetResManager().LoadString(IDS_OTFSETTINGZEROSIZEERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), pData->strDstFile); + pData->pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pData->pTask, dwLastError, fmt); + } + + // copying + unsigned long tord, rd, wr; + int iBufferIndex; + do + { + // kill flag checks + if (pData->pTask->GetKillFlag()) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFCOPYINGKILLREQUEST_STRING)); + fmt.SetParam(_t("%srcpath"), pData->pfiSrcFile->GetFullFilePath()); + fmt.SetParam(_t("%dstpath"), pData->strDstFile); + pData->pTask->m_log.logi(fmt); + throw new CProcessingException(E_KILL_REQUEST, pData->pTask); + } + + // recreate buffer if needed + if (!(*pData->dbBuffer.GetSizes() == *pData->pTask->GetBufferSizes())) + { + // log + const BUFFERSIZES *pbs1=pData->dbBuffer.GetSizes(), *pbs2=pData->pTask->GetBufferSizes(); + + fmt.SetFormat(GetResManager().LoadString(IDS_OTFCHANGINGBUFFERSIZE_STRING)); + + fmt.SetParam(_t("%defsize"), pbs1->m_uiDefaultSize); + fmt.SetParam(_t("%onesize"), pbs1->m_uiOneDiskSize); + fmt.SetParam(_t("%twosize"), pbs1->m_uiTwoDisksSize); + fmt.SetParam(_t("%cdsize"), pbs1->m_uiCDSize); + fmt.SetParam(_t("%lansize"), pbs1->m_uiLANSize); + fmt.SetParam(_t("%defsize2"), pbs2->m_uiDefaultSize); + fmt.SetParam(_t("%onesize2"), pbs2->m_uiOneDiskSize); + fmt.SetParam(_t("%twosize2"), pbs2->m_uiTwoDisksSize); + fmt.SetParam(_t("%cdsize2"), pbs2->m_uiCDSize); + fmt.SetParam(_t("%lansize2"), pbs2->m_uiLANSize); + fmt.SetParam(_t("%srcfile"), pData->pfiSrcFile->GetFullFilePath()); + fmt.SetParam(_t("%dstfile"), pData->strDstFile); + + pData->pTask->m_log.logi(fmt); + pData->pTask->SetBufferSizes(pData->dbBuffer.Create(pData->pTask->GetBufferSizes())); + } + + // establish count of data to read + iBufferIndex=pData->pTask->GetBufferSizes()->m_bOnlyDefault ? 0 : pData->pfiSrcFile->GetBufferIndex(); + tord=bNoBuffer ? ROUNDUP(pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex], MAXSECTORSIZE) : pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex]; + + // read + if (!ReadFile(hSrc, pData->dbBuffer, tord, &rd, NULL)) + { + // log + dwLastError=GetLastError(); + fmt.SetFormat(GetResManager().LoadString(IDS_OTFREADINGERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%count"), tord); + fmt.SetParam(_t("%path"), pData->pfiSrcFile->GetFullFilePath()); + pData->pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pData->pTask, dwLastError, fmt); + } + + // change count of stored data + if (bNoBuffer && (ROUNDUP(rd, MAXSECTORSIZE)) != rd) + { + // we need to copy rest so do the second pass + // close files + CloseHandle(hSrc); + CloseHandle(hDst); + + // second pass + bFirstPass=false; + bCopyRest=true; // nedd to copy rest + + goto l_start; + } + + // zapisz + if (!WriteFile(hDst, pData->dbBuffer, rd, &wr, NULL) || wr != rd) + { + // log + dwLastError=GetLastError(); + fmt.SetFormat(GetResManager().LoadString(IDS_OTFWRITINGERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%count"), rd); + fmt.SetParam(_t("%path"), pData->strDstFile); + pData->pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pData->pTask, dwLastError, fmt); + } + + // increase count of processed data + pData->pTask->IncreaseProcessedSize(rd); + pData->pTask->IncreaseProcessedTasksSize(rd); + // TRACE("Read: %d, Written: %d\n", rd, wr); + } + while ( rd != 0 ); + } + else + { + // we don't copy contents, but need to increase processed size + pData->pTask->IncreaseProcessedSize(pData->pfiSrcFile->GetLength64()); + pData->pTask->IncreaseProcessedTasksSize(pData->pfiSrcFile->GetLength64()); + } + + // close files + CloseHandle(hSrc); + CloseHandle(hDst); + + pData->bProcessed = true; + } + catch(...) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFCAUGHTEXCEPTIONCCF_STRING)); + fmt.SetParam(_t("%errno"), GetLastError()); + fmt.SetParam(_t("%timestamp"), GetTickCount()); + pData->pTask->m_log.loge(fmt); + + // close handles + if (hSrc != INVALID_HANDLE_VALUE) + CloseHandle(hSrc); + if (hDst != INVALID_HANDLE_VALUE) + CloseHandle(hDst); + + throw; + } +} + +// function processes files/folders +void CTask::ProcessFiles(CTask* pTask) +{ + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFPROCESSINGFILES_STRING)); + + // count how much has been done (updates also a member in CTaskArray) + pTask->CalcProcessedSize(); + + // create a buffer of size pTask->m_nBufferSize + CUSTOM_COPY_PARAMS ccp; + ccp.bProcessed = false; + ccp.pTask=pTask; + ccp.bOnlyCreate=(pTask->GetStatus(ST_SPECIAL_MASK) & ST_IGNORE_CONTENT) != 0; + ccp.dbBuffer.Create(pTask->GetBufferSizes()); + + // helpers + //CFileInfo fi; // for currently processed element + DWORD dwLastError; + + // begin at index which wasn't processed previously + int nSize=pTask->FilesGetSize(); // wielko�� tablicy + int iCopiesCount=pTask->GetCopies(); // ilo�� kopii + bool bIgnoreFolders=(pTask->GetStatus(ST_SPECIAL_MASK) & ST_IGNORE_DIRS) != 0; + bool bForceDirectories=(pTask->GetStatus(ST_SPECIAL_MASK) & ST_FORCE_DIRS) != 0; + const CDestPath& dpDestPath=pTask->GetDestPath(); + + // log + const BUFFERSIZES* pbs=ccp.dbBuffer.GetSizes(); + + ictranslate::CFormat fmt; + fmt.SetFormat(GetResManager().LoadString(IDS_OTFPROCESSINGFILESDATA_STRING)); + fmt.SetParam(_t("%create"), ccp.bOnlyCreate); + fmt.SetParam(_t("%defsize"), pbs->m_uiDefaultSize); + fmt.SetParam(_t("%onesize"), pbs->m_uiOneDiskSize); + fmt.SetParam(_t("%twosize"), pbs->m_uiTwoDisksSize); + fmt.SetParam(_t("%cdsize"), pbs->m_uiCDSize); + fmt.SetParam(_t("%lansize"), pbs->m_uiLANSize); + fmt.SetParam(_t("%filecount"), nSize); + fmt.SetParam(_t("%copycount"), iCopiesCount); + fmt.SetParam(_t("%ignorefolders"), bIgnoreFolders); + fmt.SetParam(_t("%dstpath"), dpDestPath.GetPath()); + fmt.SetParam(_t("%currpass"), pTask->GetCurrentCopy()); + fmt.SetParam(_t("%currindex"), pTask->GetCurrentIndex()); + + pTask->m_log.logi(fmt); + + for (unsigned char j=pTask->GetCurrentCopy();jSetCurrentCopy(j); + for (int i=pTask->GetCurrentIndex();iSetCurrentIndex(i); + CFileInfo& fi=pTask->FilesGetAtCurrentIndex(); + + // should we kill ? + if (pTask->GetKillFlag()) + { + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFPROCESSINGKILLREQUEST_STRING)); + throw new CProcessingException(E_KILL_REQUEST, pTask); + } + + // set dest path with filename + ccp.strDstFile=fi.GetDestinationPath(dpDestPath.GetPath(), j, ((int)bForceDirectories) << 1 | (int)bIgnoreFolders); + + // are the files/folders lie on the same partition ? + bool bMove=pTask->GetStatus(ST_OPERATION_MASK) == ST_MOVE; + if (bMove && dpDestPath.GetDriveNumber() != -1 && dpDestPath.GetDriveNumber() == fi.GetDriveNumber() && iCopiesCount == 1 && fi.GetMove()) + { + if (!MoveFile(fi.GetFullFilePath(), ccp.strDstFile)) + { + dwLastError=GetLastError(); + //log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFMOVEFILEERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%srcpath"), fi.GetFullFilePath()); + fmt.SetParam(_t("%dstpath"), ccp.strDstFile); + pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pTask, dwLastError, fmt); + } + else + fi.SetFlags(FIF_PROCESSED, FIF_PROCESSED); + } + else + { + // if folder - create it + if ( fi.IsDirectory() ) + { + if (!CreateDirectory(ccp.strDstFile, NULL) && (dwLastError=GetLastError()) != ERROR_ALREADY_EXISTS ) + { + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFCREATEDIRECTORYERROR_STRING)); + fmt.SetParam(_t("%errno"), dwLastError); + fmt.SetParam(_t("%path"), ccp.strDstFile); + pTask->m_log.loge(fmt); + throw new CProcessingException(E_ERROR, pTask, dwLastError, fmt); + } + + pTask->IncreaseProcessedSize(fi.GetLength64()); + pTask->IncreaseProcessedTasksSize(fi.GetLength64()); + fi.SetFlags(FIF_PROCESSED, FIF_PROCESSED); + } + else + { + // start copying/moving file + ccp.pfiSrcFile=&fi; + ccp.bProcessed = false; + + // kopiuj dane + CustomCopyFile(&ccp); + fi.SetFlags(ccp.bProcessed ? FIF_PROCESSED : 0, FIF_PROCESSED); + + // if moving - delete file (only if config flag is set) + if (bMove && fi.GetFlags() & FIF_PROCESSED && !GetConfig().get_bool(PP_CMDELETEAFTERFINISHED) && j == iCopiesCount-1) + { + if (!GetConfig().get_bool(PP_CMPROTECTROFILES)) + SetFileAttributes(fi.GetFullFilePath(), FILE_ATTRIBUTE_NORMAL); + DeleteFile(fi.GetFullFilePath()); // there will be another try later, so I don't check + // if succeeded + } + } + + // set a time + if (GetConfig().get_bool(PP_CMSETDESTDATE)) + SetFileDirectoryTime(ccp.strDstFile, &fi); // no error check - ma�o istotne + + // attributes + if (GetConfig().get_bool(PP_CMSETDESTATTRIBUTES)) + SetFileAttributes(ccp.strDstFile, fi.GetAttributes()); // j.w. + } + } + + // current copy finished - change what's needed + pTask->SetCurrentIndex(0); + } + + // delete buffer - it's not needed + ccp.dbBuffer.Delete(); + + // change status + if (pTask->GetStatus(ST_OPERATION_MASK) == ST_MOVE) + { + pTask->SetStatus(ST_DELETING, ST_STEP_MASK); + // set the index to 0 before deleting + pTask->SetCurrentIndex(0); + } + else + { + pTask->SetStatus(ST_FINISHED, ST_STEP_MASK); + + // to look better - increase current index by 1 + pTask->SetCurrentIndex(nSize); + } + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFPROCESSINGFINISHED_STRING)); +} + +void CTask::CheckForWaitState(CTask* pTask) +{ + // limiting operation count + pTask->SetStatus(ST_WAITING, ST_WAITING_MASK); + bool bContinue=false; + while (!bContinue) + { + if (pTask->CanBegin()) + { + TRACE("CAN BEGIN ALLOWED TO CONTINUE...\n"); + pTask->SetStatus(0, ST_WAITING); + bContinue=true; + + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFWAITINGFINISHED_STRING)); + + // return; // skips sleep and kill flag checking + } + + Sleep(50); // not to make it too hard for processor + + if (pTask->GetKillFlag()) + { + // log + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFWAITINGKILLREQUEST_STRING)); + throw new CProcessingException(E_KILL_REQUEST, pTask); + } + } +} + +UINT CTask::ThrdProc(LPVOID pParam) +{ + TRACE("\n\nENTERING ThrdProc (new task started)...\n"); + CTask* pTask=static_cast(pParam); + chcore::IFeedbackHandler* piFeedbackHandler = pTask->GetFeedbackHandler(); + + TCHAR szPath[_MAX_PATH]; + + tstring_t strPath = pTask->GetTaskPath(); + strPath += pTask->GetUniqueName()+_T(".log"); + + pTask->m_log.init(strPath.c_str(), 262144, icpf::log_file::level_debug, false, false); + + // set thread boost + HANDLE hThread=GetCurrentThread(); + ::SetThreadPriorityBoost(hThread, GetConfig().get_bool(PP_CMDISABLEPRIORITYBOOST)); + + CTime tm=CTime::GetCurrentTime(); + + ictranslate::CFormat fmt; + fmt.SetFormat(GetResManager().LoadString(IDS_OTFTHREADSTART_STRING)); + fmt.SetParam(_t("%year"), tm.GetYear()); + fmt.SetParam(_t("%month"), tm.GetMonth()); + fmt.SetParam(_t("%day"), tm.GetDay()); + fmt.SetParam(_t("%hour"), tm.GetHour()); + fmt.SetParam(_t("%minute"), tm.GetMinute()); + fmt.SetParam(_t("%second"), tm.GetSecond()); + pTask->m_log.logi(fmt); + + try + { + // to make the value stable + bool bReadTasksSize=GetConfig().get_bool(PP_CMREADSIZEBEFOREBLOCKING); + + if (!bReadTasksSize) + CheckForWaitState(pTask); // operation limiting + + // set what's needed + pTask->m_lLastTime=(long)time(NULL); // last time (start counting) + + // search for files if needed + if ((pTask->GetStatus(ST_STEP_MASK) == ST_NULL_STATUS + || pTask->GetStatus(ST_STEP_MASK) == ST_SEARCHING)) + { + // get rid of info about processed sizes + pTask->DecreaseProcessedTasksSize(pTask->GetProcessedSize()); + pTask->SetProcessedSize(0); + pTask->DecreaseAllTasksSize(pTask->GetAllSize()); + pTask->SetAllSize(0); + + // start searching + RecurseDirectories(pTask); + } + + // check for free space + ull_t ullNeededSize = 0, ullAvailableSize = 0; +l_showfeedback: + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFCHECKINGSPACE_STRING)); + + if (!pTask->GetRequiredFreeSpace(&ullNeededSize, &ullAvailableSize)) + { + fmt.SetFormat(GetResManager().LoadString(IDS_OTFNOTENOUGHFREESPACE_STRING)); + fmt.SetParam(_t("%needsize"), ullNeededSize); + fmt.SetParam(_t("%availablesize"), ullAvailableSize); + pTask->m_log.logw(fmt); + + BOOST_ASSERT(piFeedbackHandler); + + if(pTask->GetClipboardDataSize() > 0) + { + CString strSrcPath = pTask->GetClipboardData(0)->GetPath(); + CString strDstPath = pTask->GetDestPath().GetPath(); + FEEDBACK_NOTENOUGHSPACE feedStruct = { ullNeededSize, (PCTSTR)strSrcPath, (PCTSTR)strDstPath }; + CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_NotEnoughSpace, &feedStruct); + + // default + switch (frResult) + { + case CFeedbackHandler::eResult_Cancel: + { + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFFREESPACECANCELREQUEST_STRING)); + throw new CProcessingException(E_CANCEL, pTask); + break; + } + case CFeedbackHandler::eResult_Retry: + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFFREESPACERETRYING_STRING)); + goto l_showfeedback; + break; + case CFeedbackHandler::eResult_Skip: + pTask->m_log.logi(GetResManager().LoadString(IDS_OTFFREESPACEIGNORE_STRING)); + break; + default: + BOOST_ASSERT(FALSE); // unknown result + throw new CProcessingException(E_ERROR, pTask, 0, _t("Unknown feedback result type")); + break; + } + } + } + + if (bReadTasksSize) + { + pTask->UpdateTime(); + pTask->m_lLastTime=-1; + + CheckForWaitState(pTask); + + pTask->m_lLastTime=(long)time(NULL); + } + + // Phase II - copying/moving + if (pTask->GetStatus(ST_STEP_MASK) == ST_COPYING) + { + // decrease processed in ctaskarray - the rest will be done in ProcessFiles + pTask->DecreaseProcessedTasksSize(pTask->GetProcessedSize()); + ProcessFiles(pTask); + } + + // deleting data - III phase + if (pTask->GetStatus(ST_STEP_MASK) == ST_DELETING) + DeleteFiles(pTask); + + // refresh time + pTask->UpdateTime(); + + // save progress before killed + pTask->Store(false); + + // we are ending + pTask->DecreaseOperationsPending(); + + // play sound + piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_OperationFinished, NULL); + + tm=CTime::GetCurrentTime(); + fmt.SetFormat(GetResManager().LoadString(IDS_OTFTHREADFINISHED_STRING)); + fmt.SetParam(_t("%year"), tm.GetYear()); + fmt.SetParam(_t("%month"), tm.GetMonth()); + fmt.SetParam(_t("%day"), tm.GetDay()); + fmt.SetParam(_t("%hour"), tm.GetHour()); + fmt.SetParam(_t("%minute"), tm.GetMinute()); + fmt.SetParam(_t("%second"), tm.GetSecond()); + pTask->m_log.logi(fmt); + + // we have been killed - the last operation + InterlockedIncrement(pTask->m_plFinished); + pTask->CleanupAfterKill(); + pTask->SetKilledFlag(); + } + catch(CProcessingException* e) + { + // increment count of beginnings + InterlockedIncrement(pTask->m_plFinished); + + // refresh time + pTask->UpdateTime(); + + // log + fmt.SetFormat(GetResManager().LoadString(IDS_OTFCAUGHTEXCEPTIONMAIN_STRING)); + fmt.SetParam(_t("%errno"), e->m_dwError); + fmt.SetParam(_t("%type"), e->m_iType); + pTask->m_log.loge(fmt); + + if (e->m_iType == E_ERROR) + piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_OperationError, NULL); + + // pause task if requested + if(e->m_iType == E_PAUSE) + pTask->SetStatus(ST_PAUSED, ST_PAUSED); + + // cleanup changes flags and calls cleanup for a task + e->Cleanup(); + delete e; + + if (pTask->GetStatus(ST_WAITING_MASK) & ST_WAITING) + pTask->SetStatus(0, ST_WAITING); + + pTask->DecreaseOperationsPending(); + pTask->SetContinueFlag(false); + pTask->SetForceFlag(false); + + return 0xffffffff; // almost like -1 + } + + TRACE("TASK FINISHED - exiting ThrdProc.\n"); + return 0; +}