summaryrefslogtreecommitdiff
path: root/lib/shadow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/shadow.cpp')
-rw-r--r--lib/shadow.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/shadow.cpp b/lib/shadow.cpp
new file mode 100644
index 00000000..73a2e8f7
--- /dev/null
+++ b/lib/shadow.cpp
@@ -0,0 +1,134 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
+// **************************************************************************
+
+#include "shadow.h"
+#include <stdexcept>
+#include <zen/win.h> //includes "windows.h"
+#include <zen/dll.h>
+#include <zen/assert_static.h>
+#include "ShadowCopy/shadow.h"
+#include <zen/scope_guard.h>
+
+using namespace zen;
+using namespace shadow;
+
+
+namespace
+{
+bool runningWOW64() //test if process is running under WOW64 (reference http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx)
+{
+ //dynamically load windows API function
+ typedef BOOL (WINAPI *IsWow64ProcessFun)(HANDLE hProcess, PBOOL Wow64Process);
+
+ const SysDllFun<IsWow64ProcessFun> isWow64Process(L"kernel32.dll", "IsWow64Process");
+ if (isWow64Process)
+ {
+ BOOL isWow64 = FALSE;
+ if (isWow64Process(::GetCurrentProcess(), &isWow64))
+ return isWow64 == TRUE;
+ }
+
+ return false;
+}
+}
+
+//#############################################################################################################
+
+
+class ShadowCopy::ShadowVolume
+{
+public:
+ ShadowVolume(const Zstring& volumeNameFormatted) : //throw(FileError)
+ createShadowCopy (getDllName(), createShadowCopyFctName),
+ releaseShadowCopy(getDllName(), releaseShadowCopyFctName),
+ backupHandle(0)
+ {
+ //check if shadow copy dll was loaded correctly
+ if (!createShadowCopy || !releaseShadowCopy)
+ throw FileError(_("Error accessing Volume Shadow Copy Service!") + "\n" +
+ _("Could not load a required DLL:") + " \"" + getDllName() + "\"");
+
+ //VSS does not support running under WOW64 except for Windows XP and Windows Server 2003
+ //(Reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx)
+ if (runningWOW64())
+ throw FileError(_("Error accessing Volume Shadow Copy Service!") + "\n" +
+ _("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version."));
+
+ //---------------------------------------------------------------------------------------------------------
+ //start shadow volume copy service:
+ wchar_t shadowVolName[1000];
+ wchar_t errorMessage[1000];
+
+ if (!createShadowCopy(volumeNameFormatted.c_str(),
+ shadowVolName,
+ 1000,
+ &backupHandle,
+ errorMessage,
+ 1000))
+ throw FileError(_("Error accessing Volume Shadow Copy Service!") + "\n" +
+ "(" + errorMessage + " Volume: \"" + volumeNameFormatted + "\")");
+
+ shadowVol = Zstring(shadowVolName) + FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash
+ }
+
+ ~ShadowVolume()
+ {
+ releaseShadowCopy(backupHandle); //fast! no performance optimization necessary
+ }
+
+ Zstring getShadowVolume() const //trailing path separator
+ {
+ return shadowVol;
+ }
+
+private:
+ ShadowVolume(const ShadowVolume&);
+ ShadowVolume& operator=(const ShadowVolume&);
+
+ const DllFun<CreateShadowCopyFct> createShadowCopy;
+ const DllFun<ReleaseShadowCopyFct> releaseShadowCopy;
+
+ Zstring shadowVol;
+
+ ShadowHandle backupHandle;
+};
+//#############################################################################################################
+
+
+Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
+{
+ wchar_t volumeNameRaw[1000];
+
+ if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName,
+ volumeNameRaw, //__out LPTSTR lpszVolumePathName,
+ 1000)) //__in DWORD cchBufferLength
+ throw FileError(_("Could not determine volume name for file:") + "\n\"" + inputFile + "\"");
+
+ Zstring volumeNameFormatted = volumeNameRaw;
+ if (!endsWith(volumeNameFormatted, FILE_NAME_SEPARATOR))
+ volumeNameFormatted += FILE_NAME_SEPARATOR;
+
+ //input file is always absolute! directory formatting takes care of this! Therefore volume name can always be found.
+ const size_t pos = inputFile.find(volumeNameFormatted); //inputFile needs NOT to begin with volumeNameFormatted: consider for example \\?\ prefix!
+ if (pos == Zstring::npos)
+ {
+ std::wstring msg = _("Volume name %x not part of filename %y!");
+ replace(msg, L"%x", std::wstring(L"\"") + volumeNameFormatted + "\"", false);
+ replace(msg, L"%y", std::wstring(L"\"") + inputFile + "\"", false);
+ throw FileError(msg);
+ }
+
+ //get or create instance of shadow volume
+ VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNameFormatted);
+ if (iter == shadowVol.end())
+ {
+ std::shared_ptr<ShadowVolume> newEntry(new ShadowVolume(volumeNameFormatted));
+ iter = shadowVol.insert(std::make_pair(volumeNameFormatted, newEntry)).first;
+ }
+
+ //return filename alias on shadow copy volume
+ return iter->second->getShadowVolume() + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length());
+}
bgstack15