Index: src/libchcore/TFilesystemFeedbackWrapper.cpp
===================================================================
diff -u -N -r09d769045d1d5c45d8df16d209c754b872348c26 -r25722a1d39e5d4bb49c5a60cbee3dda6c02cb193
--- src/libchcore/TFilesystemFeedbackWrapper.cpp	(.../TFilesystemFeedbackWrapper.cpp)	(revision 09d769045d1d5c45d8df16d209c754b872348c26)
+++ src/libchcore/TFilesystemFeedbackWrapper.cpp	(.../TFilesystemFeedbackWrapper.cpp)	(revision 25722a1d39e5d4bb49c5a60cbee3dda6c02cb193)
@@ -23,15 +23,16 @@
 
 namespace chcore
 {
-	TFilesystemFeedbackWrapper::TFilesystemFeedbackWrapper(const IFilesystemPtr& spFilesystem, icpf::log_file& rLog) :
+	TFilesystemFeedbackWrapper::TFilesystemFeedbackWrapper(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemPtr& spFilesystem, icpf::log_file& rLog) :
+		m_spFeedbackHandler(spFeedbackHandler),
 		m_spFilesystem(spFilesystem),
 		m_rLog(rLog)
 	{
 		if (!spFilesystem)
 			THROW_CORE_EXCEPTION_MSG(eErr_InvalidArgument, L"Filesystem not provided");
 	}
 
-	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::CreateDirectoryFB(const IFeedbackHandlerPtr& spFeedbackHandler, const TSmartPath& pathDirectory)
+	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::CreateDirectoryFB(const TSmartPath& pathDirectory)
 	{
 		bool bRetry = false;
 		do
@@ -59,7 +60,7 @@
 			strFormat.Replace(_T("%path"), pathDirectory.ToString());
 			m_rLog.loge(strFormat.c_str());
 
-			EFeedbackResult frResult = spFeedbackHandler->FileError(pathDirectory.ToWString(), TString(), EFileError::eCreateError, dwLastError);
+			EFeedbackResult frResult = m_spFeedbackHandler->FileError(pathDirectory.ToWString(), TString(), EFileError::eCreateError, dwLastError);
 			switch (frResult)
 			{
 			case EFeedbackResult::eResult_Cancel:
@@ -85,7 +86,7 @@
 		return TSubTaskBase::eSubResult_Continue;
 	}
 
-	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::CheckForFreeSpaceFB(const IFeedbackHandlerPtr& spFeedbackHandler, const TSmartPath& pathFirstSrc, const TSmartPath& pathDestination, unsigned long long ullNeededSize)
+	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::CheckForFreeSpaceFB(const TSmartPath& pathFirstSrc, const TSmartPath& pathDestination, unsigned long long ullNeededSize)
 	{
 		unsigned long long ullAvailableSize = 0;
 		bool bRetry = false;
@@ -117,7 +118,7 @@
 				strFormat.Replace(_T("%path"), pathDestination.ToString());
 				m_rLog.loge(strFormat.c_str());
 
-				EFeedbackResult frResult = spFeedbackHandler->FileError(pathDestination.ToWString(), TString(), EFileError::eCheckForFreeSpace, dwLastError);
+				EFeedbackResult frResult = m_spFeedbackHandler->FileError(pathDestination.ToWString(), TString(), EFileError::eCheckForFreeSpace, dwLastError);
 				switch (frResult)
 				{
 				case EFeedbackResult::eResult_Cancel:
@@ -146,7 +147,7 @@
 				strFormat.Replace(_t("%availablesize"), boost::lexical_cast<std::wstring>(ullAvailableSize).c_str());
 				m_rLog.logw(strFormat.c_str());
 
-				EFeedbackResult frResult = spFeedbackHandler->NotEnoughSpace(pathFirstSrc.ToWString(), pathDestination.ToWString(), ullNeededSize);
+				EFeedbackResult frResult = m_spFeedbackHandler->NotEnoughSpace(pathFirstSrc.ToWString(), pathDestination.ToWString(), ullNeededSize);
 				switch (frResult)
 				{
 				case EFeedbackResult::eResult_Cancel:
@@ -172,4 +173,240 @@
 		return TSubTaskBase::eSubResult_Continue;
 	}
 
+	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::RemoveDirectoryFB(const TFileInfoPtr& spFileInfo, bool bProtectReadOnlyFiles)
+	{
+		bool bRetry = false;
+		do
+		{
+			bRetry = false;
+
+			// #bug - changing read-only attribute should only be done when user explicitly requests it (via feedback response)
+			// for now it is ignored
+			try
+			{
+				if (!bProtectReadOnlyFiles)
+					m_spFilesystem->SetAttributes(spFileInfo->GetFullFilePath(), FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
+			}
+			catch (const TFileException&)
+			{
+			}
+
+			DWORD dwLastError = ERROR_SUCCESS;
+			try
+			{
+				m_spFilesystem->RemoveDirectory(spFileInfo->GetFullFilePath());
+				return TSubTaskBase::eSubResult_Continue;
+			}
+			catch (const TFileException& e)
+			{
+				dwLastError = e.GetNativeError();
+			}
+
+			if (dwLastError == ERROR_PATH_NOT_FOUND || dwLastError == ERROR_FILE_NOT_FOUND)
+				return TSubTaskBase::eSubResult_Continue;
+
+			// log
+			TString strFormat = _T("Error #%errno while deleting file/folder %path");
+			strFormat.Replace(_T("%errno"), boost::lexical_cast<std::wstring>(dwLastError).c_str());
+			strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString());
+			m_rLog.loge(strFormat.c_str());
+
+			EFeedbackResult frResult = m_spFeedbackHandler->FileError(spFileInfo->GetFullFilePath().ToWString(), TString(), EFileError::eDeleteError, dwLastError);
+			switch (frResult)
+			{
+			case EFeedbackResult::eResult_Cancel:
+				m_rLog.logi(_T("Cancel request while deleting file."));
+				return TSubTaskBase::eSubResult_CancelRequest;
+
+			case EFeedbackResult::eResult_Retry:
+				bRetry = true;
+				continue;	// no fcIndex bump, since we are trying again
+
+			case EFeedbackResult::eResult_Pause:
+				return TSubTaskBase::eSubResult_PauseRequest;
+
+			case EFeedbackResult::eResult_Skip:
+				break;		// just do nothing
+
+			default:
+				BOOST_ASSERT(FALSE);		// unknown result
+				THROW_CORE_EXCEPTION(eErr_UnhandledCase);
+			}
+		} while (bRetry);
+
+		return TSubTaskBase::eSubResult_Continue;
+	}
+
+	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::DeleteFileFB(const TFileInfoPtr& spFileInfo, bool bProtectReadOnlyFiles)
+	{
+		bool bRetry = false;
+		do
+		{
+			bRetry = false;
+
+			// #bug - changing read-only attribute should only be done when user explicitly requests it (via feedback response)
+			// for now it is ignored
+			try
+			{
+				if (!bProtectReadOnlyFiles)
+					m_spFilesystem->SetAttributes(spFileInfo->GetFullFilePath(), FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
+			}
+			catch (const TFileException&)
+			{
+			}
+
+			DWORD dwLastError = ERROR_SUCCESS;
+			try
+			{
+				m_spFilesystem->DeleteFile(spFileInfo->GetFullFilePath());
+				return TSubTaskBase::eSubResult_Continue;
+			}
+			catch (const TFileException& e)
+			{
+				dwLastError = e.GetNativeError();
+			}
+
+			if (dwLastError == ERROR_PATH_NOT_FOUND || dwLastError == ERROR_FILE_NOT_FOUND)
+				return TSubTaskBase::eSubResult_Continue;
+
+			// log
+			TString strFormat = _T("Error #%errno while deleting file/folder %path");
+			strFormat.Replace(_T("%errno"), boost::lexical_cast<std::wstring>(dwLastError).c_str());
+			strFormat.Replace(_T("%path"), spFileInfo->GetFullFilePath().ToString());
+			m_rLog.loge(strFormat.c_str());
+
+			EFeedbackResult frResult = m_spFeedbackHandler->FileError(spFileInfo->GetFullFilePath().ToWString(), TString(), EFileError::eDeleteError, dwLastError);
+			switch (frResult)
+			{
+			case EFeedbackResult::eResult_Cancel:
+				m_rLog.logi(_T("Cancel request while deleting file."));
+				return TSubTaskBase::eSubResult_CancelRequest;
+
+			case EFeedbackResult::eResult_Retry:
+				bRetry = true;
+				continue;	// no fcIndex bump, since we are trying again
+
+			case EFeedbackResult::eResult_Pause:
+				return TSubTaskBase::eSubResult_PauseRequest;
+
+			case EFeedbackResult::eResult_Skip:
+				break;		// just do nothing
+
+			default:
+				BOOST_ASSERT(FALSE);		// unknown result
+				THROW_CORE_EXCEPTION(eErr_UnhandledCase);
+			}
+		} while (bRetry);
+
+		return TSubTaskBase::eSubResult_Continue;
+	}
+
+	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::FastMoveFB(const TFileInfoPtr& spFileInfo, const TSmartPath& pathDestination, const TBasePathDataPtr& spBasePath, bool& bSkip)
+	{
+		bool bRetry = false;
+		do
+		{
+			bRetry = false;
+
+			TSmartPath pathSrc = spBasePath->GetSrcPath();
+
+			DWORD dwLastError = ERROR_SUCCESS;
+			try
+			{
+				m_spFilesystem->FastMove(pathSrc, pathDestination);
+				spBasePath->SetSkipFurtherProcessing(true);		// mark that this path should not be processed any further
+				return TSubTaskBase::eSubResult_Continue;
+			}
+			catch (const TFileException& e)
+			{
+				dwLastError = e.GetNativeError();
+			}
+
+			// check if this is one of the errors, that will just cause fast move to skip
+			if (dwLastError == ERROR_ACCESS_DENIED || dwLastError == ERROR_ALREADY_EXISTS || dwLastError == ERROR_NOT_SAME_DEVICE)
+			{
+				bSkip = true;
+				break;
+			}
+			else
+			{
+				//log
+				TString strFormat = _T("Error %errno while calling fast move %srcpath -> %dstpath (TSubTaskFastMove)");
+				strFormat.Replace(_T("%errno"), boost::lexical_cast<std::wstring>(dwLastError).c_str());
+				strFormat.Replace(_T("%srcpath"), spFileInfo->GetFullFilePath().ToString());
+				strFormat.Replace(_T("%dstpath"), pathDestination.ToString());
+				m_rLog.loge(strFormat.c_str());
+
+				EFeedbackResult frResult = m_spFeedbackHandler->FileError(pathSrc.ToWString(), pathDestination.ToWString(), EFileError::eFastMoveError, dwLastError);
+				switch (frResult)
+				{
+				case EFeedbackResult::eResult_Cancel:
+					return TSubTaskBase::eSubResult_CancelRequest;
+
+				case EFeedbackResult::eResult_Retry:
+					bRetry = true;
+					break;
+
+				case EFeedbackResult::eResult_Pause:
+					return TSubTaskBase::eSubResult_PauseRequest;
+
+				case EFeedbackResult::eResult_Skip:
+					bSkip = true;
+					break;		// just do nothing
+
+				default:
+					BOOST_ASSERT(FALSE);		// unknown result
+					THROW_CORE_EXCEPTION(eErr_UnhandledCase);
+				}
+			}
+		} while (bRetry);
+
+		return TSubTaskBase::eSubResult_Continue;
+	}
+
+	TSubTaskBase::ESubOperationResult TFilesystemFeedbackWrapper::GetFileInfoFB(const TSmartPath& pathCurrent, TFileInfoPtr& spFileInfo, const TBasePathDataPtr& spBasePath, bool& bSkip)
+	{
+		bool bRetry = false;
+		do
+		{
+			bRetry = false;
+
+			// read attributes of src file/folder
+			DWORD dwLastError = ERROR_SUCCESS;
+			try
+			{
+				m_spFilesystem->GetFileInfo(pathCurrent, spFileInfo, spBasePath);
+				return TSubTaskBase::eSubResult_Continue;
+			}
+			catch (const TFileException& e)
+			{
+				dwLastError = e.GetNativeError();
+			}
+
+			EFeedbackResult frResult = m_spFeedbackHandler->FileError(pathCurrent.ToWString(), TString(), EFileError::eFastMoveError, dwLastError);
+			switch (frResult)
+			{
+			case EFeedbackResult::eResult_Cancel:
+				return TSubTaskBase::eSubResult_CancelRequest;
+
+			case EFeedbackResult::eResult_Retry:
+				bRetry = true;
+				break;
+
+			case EFeedbackResult::eResult_Pause:
+				return TSubTaskBase::eSubResult_PauseRequest;
+
+			case EFeedbackResult::eResult_Skip:
+				bSkip = true;
+				break;		// just do nothing
+
+			default:
+				BOOST_ASSERT(FALSE);		// unknown result
+				THROW_CORE_EXCEPTION(eErr_UnhandledCase);
+			}
+		} while (bRetry);
+
+		return TSubTaskBase::eSubResult_Continue;
+	}
+
 }