#include "shadow.h" #include //includes "windows.h" #include #include "systemConstants.h" using FreeFileSync::ShadowCopy; bool newerThanXP() { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //symbolic links are supported starting with Vista 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) { typedef BOOL (WINAPI *IsWow64ProcessFunc)( HANDLE hProcess, PBOOL Wow64Process); const IsWow64ProcessFunc isWow64Process = reinterpret_cast( ::GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process")); if (isWow64Process != NULL) { BOOL isWow64 = FALSE; if ((*isWow64Process)(::GetCurrentProcess(), &isWow64)) return isWow64 == TRUE; } return false; } class ShadowCopy::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 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 */ #if defined _WIN64 //note: _WIN32 is defined for 64-bit compilations, too, while _WIN64 only for 64-bit static const wxString filename(newerThanXP() ? wxT("Shadow_Server2003_x64.dll") : wxT("Shadow_XP_x64.dll")); #elif defined(_WIN32) static const wxString filename(newerThanXP() ? wxT("Shadow_Server2003_win32.dll") : wxT("Shadow_XP_win32.dll")); #else Are we at 128 bit already? #endif return filename; } ShadowlDllHandler() : createShadowCopy(NULL), releaseShadowCopy(NULL), hShadow(NULL) { //get a handle to the DLL module containing the required functionality hShadow = ::LoadLibrary(getShadowDllName().c_str()); if (hShadow) { createShadowCopy = reinterpret_cast(::GetProcAddress(hShadow, "createShadowCopy")); releaseShadowCopy = reinterpret_cast(::GetProcAddress(hShadow, "releaseShadowCopy")); } } ~ShadowlDllHandler() { if (hShadow) ::FreeLibrary(hShadow); } CreateShadowCopyFct createShadowCopy; ReleaseShadowCopyFct releaseShadowCopy; private: HINSTANCE hShadow; }; //############################################################################################################# ShadowCopy::ShadowCopy() : backupHandle(NULL) { shadowDll = new ShadowlDllHandler; } ShadowCopy::~ShadowCopy() { if (backupHandle != NULL) shadowDll->releaseShadowCopy(backupHandle); delete shadowDll; } Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { //check if shadow copy dll was loaded correctly if ( shadowDll->createShadowCopy == NULL || shadowDll->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(" \"") + ShadowlDllHandler::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) { shadowDll->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 (!shadowDll->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; } const size_t pos = inputFile.find(volumeNameFormatted); 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()); }