// ************************************************************************** // * 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 //includes "windows.h" #include #include "system_constants.h" #include "dll_loader.h" #include #include "assert_static.h" #include "build_info.h" #include "ShadowCopy\shadow.h" #include "string_conv.h" #include "Loki/ScopeGuard.h" using shadow::ShadowCopy; using shadow::WaitingForShadow; using ffs3::FileError; namespace { bool newerThanXP() { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osvi)) return osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 1) ; //XP has majorVersion == 5, minorVersion == 1 //Server 2003 has majorVersion == 5, minorVersion == 2 //version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx return false; } 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); static const IsWow64ProcessFun isWow64Process = util::getDllFun(L"kernel32.dll", "IsWow64Process"); if (isWow64Process) { BOOL isWow64 = FALSE; if (isWow64Process(::GetCurrentProcess(), &isWow64)) return isWow64 == TRUE; } return false; } const std::wstring& getShadowDllName() { /* distinguish a bunch of VSS builds: we use XP and Server 2003 implementations... VSS version and compatibility overview: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx */ assert_static(util::is32BitBuild || util::is64BitBuild); static const std::wstring filename( newerThanXP() ? (util::is64BitBuild ? L"Shadow_Server2003_x64.dll" : L"Shadow_Server2003_Win32.dll") : (util::is64BitBuild ? L"Shadow_XP_x64.dll" : L"Shadow_XP_Win32.dll")); return filename; } } //############################################################################################################# ShadowCopy::ShadowCopy(WaitingForShadow* callback) : callback_(callback) {} //############################################################################################################# class ShadowCopy::ShadowVolume { public: ShadowVolume(const Zstring& volumeNameFormatted) : //throw(FileError) backupHandle(0) { using namespace shadow; if (!createShadowCopy) createShadowCopy = util::getDllFun(getShadowDllName(), createShadowCopyFctName); if (!releaseShadowCopy) releaseShadowCopy = util::getDllFun(getShadowDllName(), releaseShadowCopyFctName); //check if shadow copy dll was loaded correctly if (createShadowCopy == NULL || releaseShadowCopy == NULL) throw FileError(wxString(_("Error starting Volume Shadow Copy Service!")) + wxT("\n") + _("Could not load a required DLL:") + wxT(" \"") + getShadowDllName().c_str() + wxT("\"")); //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) static const bool wow64Active = runningWOW64(); if (wow64Active) throw FileError(wxString(_("Error starting Volume Shadow Copy Service!")) + wxT("\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(wxString(_("Error starting Volume Shadow Copy Service!")) + wxT("\n") + wxT("(") + errorMessage + wxT(" Volume: \"") + volumeNameFormatted.c_str() + wxT("\")")); shadowVol = Zstring(shadowVolName) + common::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&); static shadow::CreateShadowCopyFct createShadowCopy; static shadow::ReleaseShadowCopyFct releaseShadowCopy; Zstring shadowVol; ShadowHandle backupHandle; }; shadow::CreateShadowCopyFct ShadowCopy::ShadowVolume::createShadowCopy; shadow::ReleaseShadowCopyFct ShadowCopy::ShadowVolume::releaseShadowCopy; //############################################################################################################# Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { using namespace ffs3; wchar_t volumeNameRaw[1000]; if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, volumeNameRaw, //__out LPTSTR lpszVolumePathName, 1000)) //__in DWORD cchBufferLength throw FileError(wxString(_("Could not determine volume name for file:")) + wxT("\n\"") + zToWx(inputFile) + wxT("\"")); Zstring volumeNameFormatted = volumeNameRaw; if (!volumeNameFormatted.EndsWith(common::FILE_NAME_SEPARATOR)) volumeNameFormatted += common::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) { wxString msg = _("Volume name %x not part of filename %y!"); msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(volumeNameFormatted) + wxT("\""), false); msg.Replace(wxT("%y"), wxString(wxT("\"")) + zToWx(inputFile) + wxT("\""), false); throw FileError(msg); } //get or create instance of shadow volume VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNameFormatted); if (iter == shadowVol.end()) { boost::shared_ptr 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()); }