summaryrefslogtreecommitdiff
path: root/library/shadow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/shadow.cpp')
-rw-r--r--library/shadow.cpp148
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());
+}
+
+
+
+
+
+
+
+
+
bgstack15