diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:00:17 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:00:17 +0200 |
commit | fd0853d2623dd278b08288331ed42e3be59252fb (patch) | |
tree | a7645daeaef8bdbed064faf4eb88e72cee58726c /shared/shadow.cpp | |
parent | 2.1 (diff) | |
download | FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.tar.gz FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.tar.bz2 FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.zip |
2.2
Diffstat (limited to 'shared/shadow.cpp')
-rw-r--r-- | shared/shadow.cpp | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/shared/shadow.cpp b/shared/shadow.cpp new file mode 100644 index 00000000..abdca1a9 --- /dev/null +++ b/shared/shadow.cpp @@ -0,0 +1,158 @@ +#include "shadow.h" +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include <wx/intl.h> +#include "globalfunctions.h" + +using FreeFileSync::ShadowCopy; + + +class ShadowlDllHandler //dynamically load windows API functions +{ + typedef bool (*CreateShadowCopyFct)( //volumeName must end with "\", while shadowVolName does not end with "\" + const wchar_t* volumeName, + wchar_t* shadowVolName, + unsigned int shadowBufferLen, + void** backupHandle, + wchar_t* errorMessage, + unsigned int errorBufferLen); + + typedef void (*ReleaseShadowCopyFct)(void* backupHandle); + +public: + static const ShadowlDllHandler& getInstance() + { + static ShadowlDllHandler instance; + return instance; + } + + CreateShadowCopyFct createShadowCopy; + ReleaseShadowCopyFct releaseShadowCopy; + +private: + ShadowlDllHandler() : + createShadowCopy(NULL), + releaseShadowCopy(NULL), + hShadow(NULL) + { + //get a handle to the DLL module containing the required functionality + hShadow = ::LoadLibrary(L"Shadow.dll"); + if (hShadow) + { + createShadowCopy = reinterpret_cast<CreateShadowCopyFct>(::GetProcAddress(hShadow, "createShadowCopy")); + releaseShadowCopy = reinterpret_cast<ReleaseShadowCopyFct>(::GetProcAddress(hShadow, "releaseShadowCopy")); + } + } + + ~ShadowlDllHandler() + { + if (hShadow) ::FreeLibrary(hShadow); + } + + HINSTANCE hShadow; +}; + + +ShadowCopy::ShadowCopy() : + backupHandle(NULL) {} + + +ShadowCopy::~ShadowCopy() +{ + if (backupHandle != NULL) + ShadowlDllHandler::getInstance().releaseShadowCopy(backupHandle); +} + + +bool ShadowCopy::isOkay() +{ + //check that all functions could be loaded + return ShadowlDllHandler::getInstance().createShadowCopy != NULL && + ShadowlDllHandler::getInstance().releaseShadowCopy != NULL; +} + + +Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) +{ + //check if shadow copy dll was loaded correctly + if (!isOkay()) + { + wxString errorMsg = _("Error copying locked file %x!"); + errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); + throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + + _("Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature.")); + } + + + wchar_t volumeNameRaw[1000]; + + if (!GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, + volumeNameRaw, //__out LPTSTR lpszVolumePathName, + 1000)) //__in DWORD cchBufferLength + { + wxString errorMsg = _("Error copying locked file %x!"); + errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); + throw FileError(errorMsg + wxT("\n\n") + _("Could not determine volume name for file:") + wxT("\n\"") + inputFile.c_str() + wxT("\"")); + } + + Zstring volumeNameFormatted = volumeNameRaw; + if (!volumeNameFormatted.EndsWith(globalFunctions::FILE_NAME_SEPARATOR)) + volumeNameFormatted += globalFunctions::FILE_NAME_SEPARATOR; + + if (volumeNameFormatted != realVolumeLast) + { + //release old shadow copy + if (backupHandle != NULL) + { + ShadowlDllHandler::getInstance().releaseShadowCopy(backupHandle); + backupHandle = NULL; + } + realVolumeLast.clear(); //...if next call fails... + shadowVolumeLast.clear(); //...if next call fails... + + //start shadow volume copy service: + wchar_t shadowVolName[1000]; + void* backupHandleTmp = NULL; + wchar_t errorMessage[1000]; + + if (!ShadowlDllHandler::getInstance().createShadowCopy( + volumeNameFormatted.c_str(), + shadowVolName, + 1000, + &backupHandleTmp, + errorMessage, + 1000)) + { + wxString errorMsg = _("Error copying locked file %x!"); + errorMsg.Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")); + throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + + wxT("(") + errorMessage + wxT(")")); + } + + realVolumeLast = volumeNameFormatted; + shadowVolumeLast = Zstring(shadowVolName) + globalFunctions::FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash + backupHandle = backupHandleTmp; + } + + const size_t pos = inputFile.find(volumeNameFormatted); + if (pos == Zstring::npos) + { + wxString errorMsg = _("Error copying locked file %x!"); + errorMsg.Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")); + + wxString msg = _("Volume name %x not part of filename %y!"); + msg.Replace(wxT("%x"), wxString(wxT("\"")) + volumeNameFormatted.c_str() + wxT("\""), false); + msg.Replace(wxT("%y"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\""), false); + throw FileError(errorMsg + wxT("\n\n") + msg); + } + //return filename alias on shadow copy volume + return shadowVolumeLast + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length()); +} + + + + + + + + + |