// ************************************************************************** // * 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-2010 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** // #include "shadow.h" #include //includes "windows.h" #include #include "systemConstants.h" #include "dllLoader.h" #include #include "staticAssert.h" #include "buildInfo.h" using FreeFileSync::ShadowCopy; 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 *IsWow64ProcessFunc)( HANDLE hProcess, PBOOL Wow64Process); static const IsWow64ProcessFunc isWow64Process = Utility::loadDllFunction(L"kernel32.dll", "IsWow64Process"); if (isWow64Process) { BOOL isWow64 = FALSE; if ((*isWow64Process)(::GetCurrentProcess(), &isWow64)) return isWow64 == TRUE; } return false; } const wxString& 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 */ static const wxString filename( newerThanXP() ? (Utility::is64BitBuild ? wxT("Shadow_Server2003_x64.dll") : wxT("Shadow_Server2003_Win32.dll")) : (Utility::is64BitBuild ? wxT("Shadow_XP_x64.dll") : wxT("Shadow_XP_Win32.dll"))); assert_static(Utility::is32BitBuild || Utility::is64BitBuild); return filename; } //############################################################################################################# ShadowCopy::ShadowCopy() : backupHandle(NULL) {} ShadowCopy::~ShadowCopy() { if (backupHandle != NULL) { typedef void (*ReleaseShadowCopyFct)(void* backupHandle); static const ReleaseShadowCopyFct releaseShadowCopy = Utility::loadDllFunction(getShadowDllName().c_str(), "releaseShadowCopy"); if (releaseShadowCopy == NULL) throw std::logic_error("Could not load \"releaseShadowCopy\"!"); //shouldn't arrive here! releaseShadowCopy(backupHandle); } } Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { 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); static const CreateShadowCopyFct createShadowCopy = Utility::loadDllFunction(getShadowDllName().c_str(), "createShadowCopy"); typedef void (*ReleaseShadowCopyFct)(void* backupHandle); static const ReleaseShadowCopyFct releaseShadowCopy = Utility::loadDllFunction(getShadowDllName().c_str(), "releaseShadowCopy"); //check if shadow copy dll was loaded correctly if ( createShadowCopy == NULL || releaseShadowCopy == NULL) { wxString errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + _("Could not load a required DLL:") + wxT(" \"") + getShadowDllName() + 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) { wxString errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + _("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.")); } //--------------------------------------------------------------------------------------------------------- wchar_t volumeNameRaw[1000]; if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, volumeNameRaw, //__out LPTSTR lpszVolumePathName, 1000)) //__in DWORD cchBufferLength { wxString errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); throw FileError(errorMsg + wxT("\n\n") + _("Could not determine volume name for file:") + wxT("\n\"") + inputFile.c_str() + wxT("\"")); } Zstring volumeNameFormatted = volumeNameRaw; if (!volumeNameFormatted.EndsWith(globalFunctions::FILE_NAME_SEPARATOR)) volumeNameFormatted += globalFunctions::FILE_NAME_SEPARATOR; if (volumeNameFormatted != realVolumeLast) { //release old shadow copy if (backupHandle != NULL) { 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 (!createShadowCopy( volumeNameFormatted.c_str(), shadowVolName, 1000, &backupHandleTmp, errorMessage, 1000)) { wxString errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")); throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + wxT("(") + errorMessage + wxT(")")); } realVolumeLast = volumeNameFormatted; shadowVolumeLast = Zstring(shadowVolName) + globalFunctions::FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash backupHandle = backupHandleTmp; } //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 errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")); wxString msg = _("Volume name %x not part of filename %y!"); msg.Replace(wxT("%x"), wxString(wxT("\"")) + volumeNameFormatted.c_str() + wxT("\""), false); msg.Replace(wxT("%y"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\""), false); throw FileError(errorMsg + wxT("\n\n") + msg); } //return filename alias on shadow copy volume return shadowVolumeLast + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length()); }