2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2008 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 #pragma message("compile VSS for Windows XP")
88 #define VSSClientGeneric VSSClientXP
90 #include "inc/WinXP/vss.h"
91 #include "inc/WinXP/vswriter.h"
92 #include "inc/WinXP/vsbackup.h"
97 #pragma message("compile VSS for Windows 2003")
98 #define VSSClientGeneric VSSClient2003
100 #include "inc/Win2003/vss.h"
101 #include "inc/Win2003/vswriter.h"
102 #include "inc/Win2003/vsbackup.h"
106 #pragma message("compile VSS for Vista")
107 #define VSSClientGeneric VSSClientVista
109 #include "inc/Win2003/vss.h"
110 #include "inc/Win2003/vswriter.h"
111 #include "inc/Win2003/vsbackup.h"
115 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
116 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
118 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
119 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
122 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
124 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
132 * some helper functions
137 // Append a backslash to the current string
138 inline wstring AppendBackslash(wstring str)
140 if (str.length() == 0)
141 return wstring(L"\\");
142 if (str[str.length() - 1] == L'\\')
144 return str.append(L"\\");
147 // Get the unique volume name for the given path
148 inline wstring GetUniqueVolumeNameForPath(wstring path)
150 if (path.length() <= 0) {
154 // Add the backslash termination, if needed
155 path = AppendBackslash(path);
157 // Get the root path of the volume
158 wchar_t volumeRootPath[MAX_PATH];
159 wchar_t volumeName[MAX_PATH];
160 wchar_t volumeUniqueName[MAX_PATH];
162 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
165 // Get the volume name alias (might be different from the unique volume name in rare cases)
166 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
169 // Get the unique volume name
170 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
173 return volumeUniqueName;
177 // Helper macro for quick treatment of case statements for error codes
178 #define GEN_MERGE(A, B) A##B
179 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
181 #define CHECK_CASE_FOR_CONSTANT(value) \
182 case value: return (GEN_MAKE_W(#value));
185 // Convert a writer status into a string
186 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
188 switch (eWriterStatus) {
189 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
190 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
191 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
192 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
193 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
194 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
195 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
196 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
197 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
198 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
199 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
200 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
201 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
202 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
205 return L"Error or Undefined";
211 VSSClientGeneric::VSSClientGeneric()
213 m_hLib = LoadLibraryA("VSSAPI.DLL");
215 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
216 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
218 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
219 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
226 VSSClientGeneric::~VSSClientGeneric()
232 // Initialize the COM infrastructure and the internal pointers
233 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
235 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
236 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
243 if (!m_bCoInitializeCalled) {
244 hr = CoInitialize(NULL);
246 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
247 errno = b_errno_win32;
250 m_bCoInitializeCalled = true;
253 // Initialize COM security
254 if (!m_bCoInitializeSecurityCalled) {
256 CoInitializeSecurity(
257 NULL, // Allow *all* VSS writers to communicate back!
258 -1, // Default COM authentication service
259 NULL, // Default COM authorization service
260 NULL, // reserved parameter
261 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
262 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
263 NULL, // Default COM authentication settings
264 EOAC_NONE, // No special options
265 NULL // Reserved parameter
269 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
270 errno = b_errno_win32;
273 m_bCoInitializeSecurityCalled = true;
276 // Release the IVssBackupComponents interface
278 m_pVssObject->Release();
282 // Create the internal backup components object
283 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
285 Dmsg1(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X\n", hr);
286 errno = b_errno_win32;
290 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
291 if (dwContext != VSS_CTX_BACKUP) {
292 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
294 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
295 errno = b_errno_win32;
301 if (!bDuringRestore) {
302 // 1. InitializeForBackup
303 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
305 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
306 errno = b_errno_win32;
311 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
313 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
314 errno = b_errno_win32;
318 CComPtr<IVssAsync> pAsync1;
319 // 3. GatherWriterMetaData
320 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
322 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
323 errno = b_errno_win32;
326 // Waits for the async operation to finish and checks the result
327 WaitAndCheckForAsyncOperation(pAsync1.p);
330 // We are during restore now?
331 m_bDuringRestore = bDuringRestore;
334 m_dwContext = dwContext;
340 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
342 // Wait until the async operation finishes
343 // unfortunately we can't use a timeout here yet.
344 // the interface would allow it on W2k3,
345 // but it is not implemented yet....
349 // Check the result of the asynchronous operation
350 HRESULT hrReturned = S_OK;
352 int timeout = 600; // 10 minutes....
356 if (hrReturned != S_OK)
360 hr = pAsync->QueryStatus(&hrReturned, NULL);
364 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
366 if (hrReturned == VSS_S_ASYNC_FINISHED)
371 // Check if the async operation succeeded...
372 if(hrReturned != VSS_S_ASYNC_FINISHED) {
373 wchar_t *pwszBuffer = NULL;
374 /* I don't see the usefulness of the following -- KES */
376 FORMAT_MESSAGE_ALLOCATE_BUFFER
377 | FORMAT_MESSAGE_FROM_SYSTEM
378 | FORMAT_MESSAGE_IGNORE_INSERTS,
380 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
381 (LPWSTR)&pwszBuffer, 0, NULL);
383 LocalFree(pwszBuffer);
384 errno = b_errno_win32;
391 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
393 /* szDriveLetters contains all drive letters in uppercase */
394 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
395 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
397 if (!m_pVssObject || m_bBackupIsInitialized) {
402 m_uidCurrentSnapshotSet = GUID_NULL;
404 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
406 /* startSnapshotSet */
408 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
410 /* AddToSnapshotSet */
418 CComPtr<IVssAsync> pAsync1;
419 CComPtr<IVssAsync> pAsync2;
422 for (size_t i=0; i < strlen (szDriveLetters); i++) {
423 szDrive[0] = szDriveLetters[i];
424 volume = GetUniqueVolumeNameForPath(szDrive);
425 // store uniquevolumname
426 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
427 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
429 szDriveLetters[i] = tolower (szDriveLetters[i]);
433 /* PrepareForBackup */
434 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
435 errno = b_errno_win32;
439 // Waits for the async operation to finish and checks the result
440 WaitAndCheckForAsyncOperation(pAsync1.p);
442 /* get latest info about writer status */
443 if (!CheckWriterStatus()) {
444 errno = b_errno_win32;
449 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
450 errno = b_errno_win32;
454 // Waits for the async operation to finish and checks the result
455 WaitAndCheckForAsyncOperation(pAsync2.p);
457 /* query snapshot info */
458 QuerySnapshotSet(m_uidCurrentSnapshotSet);
460 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
462 m_bBackupIsInitialized = true;
467 BOOL VSSClientGeneric::CloseBackup()
473 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
474 CComPtr<IVssAsync> pAsync;
476 SetVSSPathConvert(NULL, NULL);
478 m_bBackupIsInitialized = false;
480 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
481 // Waits for the async operation to finish and checks the result
482 WaitAndCheckForAsyncOperation(pAsync.p);
485 errno = b_errno_win32;
489 /* get latest info about writer status */
492 if (m_uidCurrentSnapshotSet != GUID_NULL) {
493 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
496 pVss->DeleteSnapshots(
497 m_uidCurrentSnapshotSet,
498 VSS_OBJECT_SNAPSHOT_SET,
501 &idNonDeletedSnapshotID);
503 m_uidCurrentSnapshotSet = GUID_NULL;
510 // Call CoUninitialize if the CoInitialize was performed sucesfully
511 if (m_bCoInitializeCalled) {
513 m_bCoInitializeCalled = false;
519 // Query all the shadow copies in the given set
520 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
522 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
527 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
529 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
534 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
536 // Get list all shadow copies.
537 CComPtr<IVssEnumObject> pIEnumSnapshots;
538 HRESULT hr = pVss->Query( GUID_NULL,
541 (IVssEnumObject**)(&pIEnumSnapshots) );
543 // If there are no shadow copies, just return
545 errno = b_errno_win32;
549 // Enumerate all shadow copies.
550 VSS_OBJECT_PROP Prop;
551 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
554 // Get the next element
556 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
558 // We reached the end of list
562 // Print the shadow copy (if not filtered out)
563 if (Snap.m_SnapshotSetId == snapshotSetID) {
564 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
565 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
566 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
571 p_VssFreeSnapshotProperties(&Snap);
576 // Check the status for all selected writers
577 BOOL VSSClientGeneric::CheckWriterStatus()
580 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
582 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
585 // Gather writer status to detect potential errors
586 CComPtr<IVssAsync> pAsync;
588 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
590 errno = b_errno_win32;
594 // Waits for the async operation to finish and checks the result
595 WaitAndCheckForAsyncOperation(pAsync.p);
597 unsigned cWriters = 0;
599 hr = pVss->GetWriterStatusCount(&cWriters);
601 errno = b_errno_win32;
607 // Enumerate each writer
608 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
609 VSS_ID idInstance = GUID_NULL;
610 VSS_ID idWriter= GUID_NULL;
611 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
612 CComBSTR bstrWriterName;
613 HRESULT hrWriterFailure = S_OK;
616 hr = pVss->GetWriterStatus(iWriter,
627 switch(eWriterStatus) {
628 case VSS_WS_FAILED_AT_IDENTIFY:
629 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
630 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
631 case VSS_WS_FAILED_AT_FREEZE:
632 case VSS_WS_FAILED_AT_THAW:
633 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
634 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
635 case VSS_WS_FAILED_AT_PRE_RESTORE:
636 case VSS_WS_FAILED_AT_POST_RESTORE:
637 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
638 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
649 /* store text info */
652 bstrncpy(str, "\"", sizeof(str));
653 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
654 bstrncat(str, szBuf, sizeof(str));
655 bstrncat(str, "\", State: 0x", sizeof(str));
656 itoa(eWriterStatus, szBuf, sizeof(szBuf));
657 bstrncat(str, szBuf, sizeof(str));
658 bstrncat(str, " (", sizeof(str));
659 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
660 bstrncat(str, szBuf, sizeof(str));
661 bstrncat(str, ")", sizeof(str));
663 AppendWriterInfo(nState, (const char *)str);
666 hr = pVss->FreeWriterStatus();
669 errno = b_errno_win32;
677 #endif /* WIN32_VSS */