diff options
Diffstat (limited to 'lib/ShadowCopy/shadow.cpp')
-rw-r--r-- | lib/ShadowCopy/shadow.cpp | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/lib/ShadowCopy/shadow.cpp b/lib/ShadowCopy/shadow.cpp new file mode 100644 index 00000000..12e9fa60 --- /dev/null +++ b/lib/ShadowCopy/shadow.cpp @@ -0,0 +1,187 @@ +// ************************************************************************** +// * 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 <algorithm> +#include <string> +#include <comdef.h> +#include <zen/com_ptr.h> +#include <zen/com_error.h> + +#define WIN32_LEAN_AND_MEAN +#include "windows.h" + +#ifdef USE_SHADOW_XP +#include "xp/inc/vss.h" +#include "xp/inc/vswriter.h" +#include "xp/inc/vsbackup.h" + +#elif defined USE_SHADOW_2003 +#include "Server 2003/inc/vss.h" +#include "Server 2003/inc/vswriter.h" +#include "Server 2003/inc/vsbackup.h" +#else +adapt! +#endif + +using namespace zen; + + +namespace +{ +inline +void copyString(const std::wstring& input, wchar_t* buffer, size_t bufferSize) +{ + if (bufferSize > 0) + { + //size_t endPos = input.copy(buffer, bufferSize - 1); + //buffer[endPos] = 0; + const size_t maxSize = std::min(input.length(), bufferSize - 1); + std::copy(input.begin(), input.begin() + maxSize, buffer); + buffer[maxSize] = 0; + } +} + +inline +void writeErrorMsg(const wchar_t* input, HRESULT hr, wchar_t* output, unsigned int outputLen) +{ + copyString(generateErrorMsg(input, hr), output, outputLen); +} +} + + +bool shadow::createShadowCopy(const wchar_t* volumeName, + wchar_t* shadowVolName, + unsigned int shadowBufferLen, + ShadowHandle* handle, + wchar_t* errorMessage, + unsigned int errorBufferLen) +{ + //MessageBox(0, L"backup err", L"", 0); */ + *handle = 0; + HRESULT hr = NULL; + + ComPtr<IVssBackupComponents> backupComp; + if (FAILED(hr = CreateVssBackupComponents(backupComp.init()))) + { + if (hr == E_ACCESSDENIED) + writeErrorMsg(L"The caller does not have sufficient backup privileges or is not an administrator.", hr, errorMessage, errorBufferLen); + else + writeErrorMsg(L"Error calling \"CreateVssBackupComponents\".", hr, errorMessage, errorBufferLen); + return false; + } + + if (FAILED(hr = backupComp->InitializeForBackup())) + { + writeErrorMsg(L"Error calling \"InitializeForBackup\".", hr, errorMessage, errorBufferLen); + return false; + } + + if (FAILED(hr = backupComp->SetBackupState(false, false, VSS_BT_FULL))) + { + writeErrorMsg(L"Error calling \"SetBackupState\".", hr, errorMessage, errorBufferLen); + return false; + } + + ComPtr<IVssAsync> vssWriters; + if (FAILED(hr = backupComp->GatherWriterMetadata(vssWriters.init()))) + { + //this can happen if XP-version of VSS is used on Windows Vista (which needs at least VSS-Server2003 build) + writeErrorMsg(L"Error calling \"GatherWriterMetadata\".", hr, errorMessage, errorBufferLen); + return false; + } + + //wait for shadow copy writers to complete + if (FAILED(hr = vssWriters->Wait())) + { + writeErrorMsg(L"Error calling \"vssWriters->Wait\".", hr, errorMessage, errorBufferLen); + return false; + } + + vssWriters->QueryStatus(&hr, NULL); //check if the async operation succeeded... + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"vssWriters->QueryStatus\".", hr, errorMessage, errorBufferLen); + return false; + } + + VSS_ID snapshotSetId = {0}; + if (FAILED(hr = backupComp->StartSnapshotSet(&snapshotSetId))) + { + writeErrorMsg(L"Error calling \"StartSnapshotSet\".", hr, errorMessage, errorBufferLen); + return false; + } + + VSS_ID SnapShotId = {0}; + if (FAILED(hr = backupComp->AddToSnapshotSet(const_cast<wchar_t*>(volumeName), GUID_NULL, &SnapShotId))) + { + writeErrorMsg(L"Error calling \"AddToSnapshotSet\".", hr, errorMessage, errorBufferLen); + return false; + } + + ComPtr<IVssAsync> vssPrepare; + if (FAILED(hr = backupComp->PrepareForBackup(vssPrepare.init()))) + { + writeErrorMsg(L"Error calling \"PrepareForBackup\".", hr, errorMessage, errorBufferLen); + return false; + } + + if (FAILED(hr = vssPrepare->Wait())) + { + writeErrorMsg(L"Error calling \"vssPrepare->Wait\".", hr, errorMessage, errorBufferLen); + return false; + } + + vssPrepare->QueryStatus(&hr, NULL); //check if the async operation succeeded... + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"vssPrepare->QueryStatus\".", hr, errorMessage, errorBufferLen); + return false; + } + + ComPtr<IVssAsync> vssDoShadowCopy; + if (FAILED(hr = backupComp->DoSnapshotSet(vssDoShadowCopy.init()))) + { + writeErrorMsg(L"Error calling \"DoSnapshotSet\".", hr, errorMessage, errorBufferLen); + return false; + } + + if (FAILED(hr = vssDoShadowCopy->Wait())) + { + writeErrorMsg(L"Error calling \"vssDoShadowCopy->Wait\".", hr, errorMessage, errorBufferLen); + return false; + } + + vssDoShadowCopy->QueryStatus(&hr, NULL); //check if the async operation succeeded... + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"vssDoShadowCopy->QueryStatus\".", hr, errorMessage, errorBufferLen); + return false; + } + + VSS_SNAPSHOT_PROP props; + if (FAILED(hr = backupComp->GetSnapshotProperties(SnapShotId, &props))) + { + writeErrorMsg(L"Error calling \"GetSnapshotProperties\".", hr, errorMessage, errorBufferLen); + return false; + } + + //finally: write volume name of newly created shadow copy + copyString(props.m_pwszSnapshotDeviceObject, shadowVolName, shadowBufferLen); + + VssFreeSnapshotProperties(&props); + + *handle = backupComp.release(); + + return true; +} + + +void shadow::releaseShadowCopy(ShadowHandle handle) +{ + if (handle) + handle->Release(); +} |