diff options
Diffstat (limited to 'lib/shadow.cpp')
-rw-r--r-- | lib/shadow.cpp | 134 |
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()); +} |