summaryrefslogtreecommitdiff
path: root/lib/ShadowCopy/shadow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ShadowCopy/shadow.cpp')
-rw-r--r--lib/ShadowCopy/shadow.cpp187
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();
+}
bgstack15