2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2007 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 John Walker.
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;
121 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
128 * some helper functions
133 // Append a backslash to the current string
134 inline wstring AppendBackslash(wstring str)
136 if (str.length() == 0)
137 return wstring(L"\\");
138 if (str[str.length() - 1] == L'\\')
140 return str.append(L"\\");
143 // Get the unique volume name for the given path
144 inline wstring GetUniqueVolumeNameForPath(wstring path)
146 if (path.length() <= 0) {
150 // Add the backslash termination, if needed
151 path = AppendBackslash(path);
153 // Get the root path of the volume
154 wchar_t volumeRootPath[MAX_PATH];
155 wchar_t volumeName[MAX_PATH];
156 wchar_t volumeUniqueName[MAX_PATH];
158 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
161 // Get the volume name alias (might be different from the unique volume name in rare cases)
162 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
165 // Get the unique volume name
166 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
169 return volumeUniqueName;
173 // Helper macro for quick treatment of case statements for error codes
174 #define GEN_MERGE(A, B) A##B
175 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
177 #define CHECK_CASE_FOR_CONSTANT(value) \
178 case value: return (GEN_MAKE_W(#value));
181 // Convert a writer status into a string
182 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
184 switch (eWriterStatus) {
185 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
186 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
187 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
188 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
189 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
190 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
191 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
192 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
193 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
194 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
195 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
196 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
197 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
198 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
201 return L"Error or Undefined";
207 VSSClientGeneric::VSSClientGeneric()
209 m_hLib = LoadLibraryA("VSSAPI.DLL");
211 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
212 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
214 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
215 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
222 VSSClientGeneric::~VSSClientGeneric()
228 // Initialize the COM infrastructure and the internal pointers
229 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
231 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
232 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
239 if (!m_bCoInitializeCalled) {
240 hr = CoInitialize(NULL);
242 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
243 errno = b_errno_win32;
246 m_bCoInitializeCalled = true;
249 // Initialize COM security
250 if (!m_bCoInitializeSecurityCalled) {
252 CoInitializeSecurity(
253 NULL, // Allow *all* VSS writers to communicate back!
254 -1, // Default COM authentication service
255 NULL, // Default COM authorization service
256 NULL, // reserved parameter
257 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
258 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
259 NULL, // Default COM authentication settings
260 EOAC_NONE, // No special options
261 NULL // Reserved parameter
265 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
266 errno = b_errno_win32;
269 m_bCoInitializeSecurityCalled = true;
272 // Release the IVssBackupComponents interface
274 m_pVssObject->Release();
278 // Create the internal backup components object
279 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
281 Dmsg1(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X\n", hr);
282 errno = b_errno_win32;
286 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
287 if (dwContext != VSS_CTX_BACKUP) {
288 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
290 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
291 errno = b_errno_win32;
297 if (!bDuringRestore) {
298 // 1. InitializeForBackup
299 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
301 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
302 errno = b_errno_win32;
307 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
309 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
310 errno = b_errno_win32;
314 CComPtr<IVssAsync> pAsync1;
315 // 3. GatherWriterMetaData
316 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
318 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
319 errno = b_errno_win32;
322 // Waits for the async operation to finish and checks the result
323 WaitAndCheckForAsyncOperation(pAsync1.p);
326 // We are during restore now?
327 m_bDuringRestore = bDuringRestore;
330 m_dwContext = dwContext;
336 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
338 // Wait until the async operation finishes
339 // unfortunately we can't use a timeout here yet.
340 // the interface would allow it on W2k3,
341 // but it is not implemented yet....
345 // Check the result of the asynchronous operation
346 HRESULT hrReturned = S_OK;
348 int timeout = 600; // 10 minutes....
352 if (hrReturned != S_OK)
356 hr = pAsync->QueryStatus(&hrReturned, NULL);
360 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
362 if (hrReturned == VSS_S_ASYNC_FINISHED)
367 // Check if the async operation succeeded...
368 if(hrReturned != VSS_S_ASYNC_FINISHED) {
369 wchar_t *pwszBuffer = NULL;
370 /* I don't see the usefulness of the following -- KES */
371 DWORD dwRet = ::FormatMessageW(
372 FORMAT_MESSAGE_ALLOCATE_BUFFER
373 | FORMAT_MESSAGE_FROM_SYSTEM
374 | FORMAT_MESSAGE_IGNORE_INSERTS,
376 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
377 (LPWSTR)&pwszBuffer, 0, NULL);
380 LocalFree(pwszBuffer);
382 errno = b_errno_win32;
389 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
391 /* szDriveLetters contains all drive letters in uppercase */
392 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
393 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
395 if (!m_pVssObject || m_bBackupIsInitialized) {
400 m_uidCurrentSnapshotSet = GUID_NULL;
402 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
404 /* startSnapshotSet */
406 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
408 /* AddToSnapshotSet */
416 CComPtr<IVssAsync> pAsync1;
417 CComPtr<IVssAsync> pAsync2;
420 for (size_t i=0; i < strlen (szDriveLetters); i++) {
421 szDrive[0] = szDriveLetters[i];
422 volume = GetUniqueVolumeNameForPath(szDrive);
423 // store uniquevolumname
424 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
425 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
427 szDriveLetters[i] = tolower (szDriveLetters[i]);
431 /* PrepareForBackup */
432 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
433 errno = b_errno_win32;
437 // Waits for the async operation to finish and checks the result
438 WaitAndCheckForAsyncOperation(pAsync1.p);
440 /* get latest info about writer status */
441 if (!CheckWriterStatus()) {
442 errno = b_errno_win32;
447 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
448 errno = b_errno_win32;
452 // Waits for the async operation to finish and checks the result
453 WaitAndCheckForAsyncOperation(pAsync2.p);
455 /* query snapshot info */
456 QuerySnapshotSet(m_uidCurrentSnapshotSet);
458 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
460 m_bBackupIsInitialized = true;
465 BOOL VSSClientGeneric::CloseBackup()
471 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
472 CComPtr<IVssAsync> pAsync;
474 SetVSSPathConvert(NULL, NULL);
476 m_bBackupIsInitialized = false;
478 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
479 // Waits for the async operation to finish and checks the result
480 WaitAndCheckForAsyncOperation(pAsync.p);
483 errno = b_errno_win32;
487 /* get latest info about writer status */
490 if (m_uidCurrentSnapshotSet != GUID_NULL) {
491 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
494 pVss->DeleteSnapshots(
495 m_uidCurrentSnapshotSet,
496 VSS_OBJECT_SNAPSHOT_SET,
499 &idNonDeletedSnapshotID);
501 m_uidCurrentSnapshotSet = GUID_NULL;
508 // Call CoUninitialize if the CoInitialize was performed sucesfully
509 if (m_bCoInitializeCalled) {
511 m_bCoInitializeCalled = false;
517 // Query all the shadow copies in the given set
518 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
520 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
525 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
527 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
532 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
534 // Get list all shadow copies.
535 CComPtr<IVssEnumObject> pIEnumSnapshots;
536 HRESULT hr = pVss->Query( GUID_NULL,
539 (IVssEnumObject**)(&pIEnumSnapshots) );
541 // If there are no shadow copies, just return
543 errno = b_errno_win32;
547 // Enumerate all shadow copies.
548 VSS_OBJECT_PROP Prop;
549 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
552 // Get the next element
554 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
556 // We reached the end of list
560 // Print the shadow copy (if not filtered out)
561 if (Snap.m_SnapshotSetId == snapshotSetID) {
562 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
563 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
564 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
569 p_VssFreeSnapshotProperties(&Snap);
574 // Check the status for all selected writers
575 BOOL VSSClientGeneric::CheckWriterStatus()
578 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
580 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
583 // Gather writer status to detect potential errors
584 CComPtr<IVssAsync> pAsync;
586 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
588 errno = b_errno_win32;
592 // Waits for the async operation to finish and checks the result
593 WaitAndCheckForAsyncOperation(pAsync.p);
595 unsigned cWriters = 0;
597 hr = pVss->GetWriterStatusCount(&cWriters);
599 errno = b_errno_win32;
605 // Enumerate each writer
606 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
607 VSS_ID idInstance = GUID_NULL;
608 VSS_ID idWriter= GUID_NULL;
609 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
610 CComBSTR bstrWriterName;
611 HRESULT hrWriterFailure = S_OK;
614 hr = pVss->GetWriterStatus(iWriter,
625 switch(eWriterStatus) {
626 case VSS_WS_FAILED_AT_IDENTIFY:
627 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
628 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
629 case VSS_WS_FAILED_AT_FREEZE:
630 case VSS_WS_FAILED_AT_THAW:
631 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
632 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
633 case VSS_WS_FAILED_AT_PRE_RESTORE:
634 case VSS_WS_FAILED_AT_POST_RESTORE:
635 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
636 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
647 /* store text info */
650 bstrncpy(str, "\"", sizeof(str));
651 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
652 bstrncat(str, szBuf, sizeof(str));
653 bstrncat(str, "\", State: 0x", sizeof(str));
654 itoa(eWriterStatus, szBuf, sizeof(szBuf));
655 bstrncat(str, szBuf, sizeof(str));
656 bstrncat(str, " (", sizeof(str));
657 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
658 bstrncat(str, szBuf, sizeof(str));
659 bstrncat(str, ")", sizeof(str));
661 AppendWriterInfo(nState, (const char *)str);
664 hr = pVss->FreeWriterStatus();
667 errno = b_errno_win32;
675 #endif /* WIN32_VSS */