2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
31 // Copyright transferred from MATRIX-Computer GmbH to
32 // Kern Sibbald by express permission.
34 // Author : Thorsten Engel
35 // Created On : Fri May 06 21:44:00 2005
56 * Kludges to get Vista code to compile.
61 #define __RPC_unique_pointer
63 #define __RPC__out_ecount_part(x, y)
64 #define __RPC__deref_inout_opt
67 #if !defined(ENABLE_NLS)
68 #define setlocale(p, d)
72 // Used for safe string manipulation
76 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
77 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
80 class IXMLDOMDocument;
83 /* Reduce compiler warnings from Windows vss code */
87 #define VSSClientGeneric VSSClientXP
89 #include "inc/WinXP/vss.h"
90 #include "inc/WinXP/vswriter.h"
91 #include "inc/WinXP/vsbackup.h"
96 #define VSSClientGeneric VSSClient2003
98 #include "inc/Win2003/vss.h"
99 #include "inc/Win2003/vswriter.h"
100 #include "inc/Win2003/vsbackup.h"
104 #define VSSClientGeneric VSSClientVista
106 #include "inc/Win2003/vss.h"
107 #include "inc/Win2003/vswriter.h"
108 #include "inc/Win2003/vsbackup.h"
112 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
113 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
115 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
116 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
124 * some helper functions
129 // Append a backslash to the current string
130 inline wstring AppendBackslash(wstring str)
132 if (str.length() == 0)
133 return wstring(L"\\");
134 if (str[str.length() - 1] == L'\\')
136 return str.append(L"\\");
139 // Get the unique volume name for the given path
140 inline wstring GetUniqueVolumeNameForPath(wstring path)
142 if (path.length() <= 0) {
146 // Add the backslash termination, if needed
147 path = AppendBackslash(path);
149 // Get the root path of the volume
150 wchar_t volumeRootPath[MAX_PATH];
151 wchar_t volumeName[MAX_PATH];
152 wchar_t volumeUniqueName[MAX_PATH];
154 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
157 // Get the volume name alias (might be different from the unique volume name in rare cases)
158 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
161 // Get the unique volume name
162 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
165 return volumeUniqueName;
169 // Helper macro for quick treatment of case statements for error codes
170 #define GEN_MERGE(A, B) A##B
171 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
173 #define CHECK_CASE_FOR_CONSTANT(value) \
174 case value: return (GEN_MAKE_W(#value));
177 // Convert a writer status into a string
178 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
180 switch (eWriterStatus) {
181 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
182 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
183 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
184 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
185 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
186 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
187 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
188 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
189 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
190 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
191 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
192 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
193 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
194 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
197 return L"Error or Undefined";
204 /* 64 bit entrypoint name */
205 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
207 /* 32 bit entrypoint name */
208 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
211 VSSClientGeneric::VSSClientGeneric()
213 m_hLib = LoadLibraryA("VSSAPI.DLL");
215 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
216 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
217 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
218 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
225 VSSClientGeneric::~VSSClientGeneric()
231 // Initialize the COM infrastructure and the internal pointers
232 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
234 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
235 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
242 if (!m_bCoInitializeCalled) {
243 hr = CoInitialize(NULL);
245 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
246 errno = b_errno_win32;
249 m_bCoInitializeCalled = true;
252 // Initialize COM security
253 if (!m_bCoInitializeSecurityCalled) {
255 CoInitializeSecurity(
256 NULL, // Allow *all* VSS writers to communicate back!
257 -1, // Default COM authentication service
258 NULL, // Default COM authorization service
259 NULL, // reserved parameter
260 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
261 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
262 NULL, // Default COM authentication settings
263 EOAC_NONE, // No special options
264 NULL // Reserved parameter
268 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
269 errno = b_errno_win32;
272 m_bCoInitializeSecurityCalled = true;
275 // Release the IVssBackupComponents interface
277 m_pVssObject->Release();
281 // Create the internal backup components object
282 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
285 Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
286 hr, be.bstrerror(b_errno_win32));
287 errno = b_errno_win32;
291 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
292 if (dwContext != VSS_CTX_BACKUP) {
293 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
295 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
296 errno = b_errno_win32;
302 if (!bDuringRestore) {
303 // 1. InitializeForBackup
304 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
306 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
307 errno = b_errno_win32;
312 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
314 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
315 errno = b_errno_win32;
319 CComPtr<IVssAsync> pAsync1;
320 // 3. GatherWriterMetaData
321 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
323 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
324 errno = b_errno_win32;
327 // Waits for the async operation to finish and checks the result
328 WaitAndCheckForAsyncOperation(pAsync1.p);
331 // We are during restore now?
332 m_bDuringRestore = bDuringRestore;
335 m_dwContext = dwContext;
341 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
343 // Wait until the async operation finishes
344 // unfortunately we can't use a timeout here yet.
345 // the interface would allow it on W2k3,
346 // but it is not implemented yet....
350 // Check the result of the asynchronous operation
351 HRESULT hrReturned = S_OK;
353 int timeout = 600; // 10 minutes....
357 if (hrReturned != S_OK)
361 hr = pAsync->QueryStatus(&hrReturned, NULL);
365 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
367 if (hrReturned == VSS_S_ASYNC_FINISHED)
372 // Check if the async operation succeeded...
373 if(hrReturned != VSS_S_ASYNC_FINISHED) {
374 wchar_t *pwszBuffer = NULL;
375 /* I don't see the usefulness of the following -- KES */
377 FORMAT_MESSAGE_ALLOCATE_BUFFER
378 | FORMAT_MESSAGE_FROM_SYSTEM
379 | FORMAT_MESSAGE_IGNORE_INSERTS,
381 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
382 (LPWSTR)&pwszBuffer, 0, NULL);
384 LocalFree(pwszBuffer);
385 errno = b_errno_win32;
392 bool VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
394 /* szDriveLetters contains all drive letters in uppercase */
395 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
396 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
398 if (!m_pVssObject || m_bBackupIsInitialized) {
403 m_uidCurrentSnapshotSet = GUID_NULL;
405 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
407 /* startSnapshotSet */
409 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
411 /* AddToSnapshotSet */
419 CComPtr<IVssAsync> pAsync1;
420 CComPtr<IVssAsync> pAsync2;
423 for (size_t i=0; i < strlen (szDriveLetters); i++) {
424 szDrive[0] = szDriveLetters[i];
425 volume = GetUniqueVolumeNameForPath(szDrive);
426 // store uniquevolumname
427 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
428 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
430 szDriveLetters[i] = tolower (szDriveLetters[i]);
434 /* PrepareForBackup */
435 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
436 errno = b_errno_win32;
440 // Waits for the async operation to finish and checks the result
441 WaitAndCheckForAsyncOperation(pAsync1.p);
443 /* get latest info about writer status */
444 if (!CheckWriterStatus()) {
445 errno = b_errno_win32;
450 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
451 errno = b_errno_win32;
455 // Waits for the async operation to finish and checks the result
456 WaitAndCheckForAsyncOperation(pAsync2.p);
458 /* query snapshot info */
459 QuerySnapshotSet(m_uidCurrentSnapshotSet);
461 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
463 m_bBackupIsInitialized = true;
468 bool VSSClientGeneric::CloseBackup()
474 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
475 CComPtr<IVssAsync> pAsync;
477 SetVSSPathConvert(NULL, NULL);
479 m_bBackupIsInitialized = false;
481 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
482 // Waits for the async operation to finish and checks the result
483 WaitAndCheckForAsyncOperation(pAsync.p);
486 errno = b_errno_win32;
490 /* get latest info about writer status */
493 if (m_uidCurrentSnapshotSet != GUID_NULL) {
494 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
497 pVss->DeleteSnapshots(
498 m_uidCurrentSnapshotSet,
499 VSS_OBJECT_SNAPSHOT_SET,
502 &idNonDeletedSnapshotID);
504 m_uidCurrentSnapshotSet = GUID_NULL;
511 // Call CoUninitialize if the CoInitialize was performed sucesfully
512 if (m_bCoInitializeCalled) {
514 m_bCoInitializeCalled = false;
520 // Query all the shadow copies in the given set
521 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
523 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
528 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
530 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
535 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
537 // Get list all shadow copies.
538 CComPtr<IVssEnumObject> pIEnumSnapshots;
539 HRESULT hr = pVss->Query( GUID_NULL,
542 (IVssEnumObject**)(&pIEnumSnapshots) );
544 // If there are no shadow copies, just return
546 errno = b_errno_win32;
550 // Enumerate all shadow copies.
551 VSS_OBJECT_PROP Prop;
552 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
555 // Get the next element
557 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
559 // We reached the end of list
563 // Print the shadow copy (if not filtered out)
564 if (Snap.m_SnapshotSetId == snapshotSetID) {
565 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
566 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
567 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
572 p_VssFreeSnapshotProperties(&Snap);
577 // Check the status for all selected writers
578 bool VSSClientGeneric::CheckWriterStatus()
581 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
583 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
586 // Gather writer status to detect potential errors
587 CComPtr<IVssAsync> pAsync;
589 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
591 errno = b_errno_win32;
595 // Waits for the async operation to finish and checks the result
596 WaitAndCheckForAsyncOperation(pAsync.p);
598 unsigned cWriters = 0;
600 hr = pVss->GetWriterStatusCount(&cWriters);
602 errno = b_errno_win32;
608 // Enumerate each writer
609 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
610 VSS_ID idInstance = GUID_NULL;
611 VSS_ID idWriter= GUID_NULL;
612 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
613 CComBSTR bstrWriterName;
614 HRESULT hrWriterFailure = S_OK;
617 hr = pVss->GetWriterStatus(iWriter,
628 switch(eWriterStatus) {
629 case VSS_WS_FAILED_AT_IDENTIFY:
630 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
631 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
632 case VSS_WS_FAILED_AT_FREEZE:
633 case VSS_WS_FAILED_AT_THAW:
634 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
635 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
636 case VSS_WS_FAILED_AT_PRE_RESTORE:
637 case VSS_WS_FAILED_AT_POST_RESTORE:
638 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
639 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
650 /* store text info */
653 bstrncpy(str, "\"", sizeof(str));
654 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
655 bstrncat(str, szBuf, sizeof(str));
656 bstrncat(str, "\", State: 0x", sizeof(str));
657 itoa(eWriterStatus, szBuf, sizeof(szBuf));
658 bstrncat(str, szBuf, sizeof(str));
659 bstrncat(str, " (", sizeof(str));
660 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
661 bstrncat(str, szBuf, sizeof(str));
662 bstrncat(str, ")", sizeof(str));
664 AppendWriterInfo(nState, (const char *)str);
667 hr = pVss->FreeWriterStatus();
670 errno = b_errno_win32;
678 #endif /* WIN32_VSS */