diff options
Diffstat (limited to 'library/shadow.cpp')
-rw-r--r-- | library/shadow.cpp | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/library/shadow.cpp b/library/shadow.cpp new file mode 100644 index 00000000..c353bcb2 --- /dev/null +++ b/library/shadow.cpp @@ -0,0 +1,148 @@ +#include "shadow.h" +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include <wx/intl.h> +#include "../structures.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) throw(FreeFileSync::FileError) +{ + //check if shadow copy dll was loaded correctly + if (!isOkay()) + throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + 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 + throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") + + _("Could not determine volume name for file:") + wxT("\n\"") + inputFile + wxT("\"")); + + Zstring volumeNameFormatted = volumeNameRaw; + if (!volumeNameFormatted.EndsWith(FreeFileSync::FILE_NAME_SEPARATOR)) + volumeNameFormatted += FreeFileSync::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)) + throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") + + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + + wxT("(") + errorMessage + wxT(")")); + + realVolumeLast = volumeNameFormatted; + shadowVolumeLast = Zstring(shadowVolName) + FreeFileSync::FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash + backupHandle = backupHandleTmp; + } + + const size_t pos = inputFile.find(volumeNameFormatted); + if (pos == Zstring::npos) + { + Zstring msg = _("Volume name %x not part of filename %y!"); + msg.Replace(wxT("%x"), Zstring(wxT("\"")) + volumeNameFormatted + wxT("\""), false); + msg.Replace(wxT("%y"), Zstring(wxT("\"")) + inputFile + wxT("\""), false); + throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") + + msg); + } + + //return filename alias on shadow copy volume + return shadowVolumeLast + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length()); +} + + + + + + + + + |