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;
127 * some helper functions
132 // Append a backslash to the current string
133 inline wstring AppendBackslash(wstring str)
135 if (str.length() == 0)
136 return wstring(L"\\");
137 if (str[str.length() - 1] == L'\\')
139 return str.append(L"\\");
142 // Get the unique volume name for the given path
143 inline wstring GetUniqueVolumeNameForPath(wstring path)
145 if (path.length() <= 0) {
149 // Add the backslash termination, if needed
150 path = AppendBackslash(path);
152 // Get the root path of the volume
153 wchar_t volumeRootPath[MAX_PATH];
154 wchar_t volumeName[MAX_PATH];
155 wchar_t volumeUniqueName[MAX_PATH];
157 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
160 // Get the volume name alias (might be different from the unique volume name in rare cases)
161 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
164 // Get the unique volume name
165 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
168 return volumeUniqueName;
172 // Helper macro for quick treatment of case statements for error codes
173 #define GEN_MERGE(A, B) A##B
174 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
176 #define CHECK_CASE_FOR_CONSTANT(value) \
177 case value: return (GEN_MAKE_W(#value));
180 // Convert a writer status into a string
181 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
183 switch (eWriterStatus) {
184 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
185 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
186 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
187 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
188 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
189 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
190 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
191 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
192 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
193 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
194 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
195 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
196 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
197 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
200 return L"Error or Undefined";
206 /* 32 bit entrypoint name */
207 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
208 /* 64 bit entrypoint name */
209 #define VSSVBACK64_ENTRY "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
212 VSSClientGeneric::VSSClientGeneric()
214 m_hLib = LoadLibraryA("VSSAPI.DLL");
216 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
217 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
218 /* If we don't find it try the 64 bit entry point */
219 if (!p_CreateVssBackupComponents) {
220 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
221 GetProcAddress(m_hLib, VSSVBACK64_ENTRY);
223 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
224 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
231 VSSClientGeneric::~VSSClientGeneric()
237 // Initialize the COM infrastructure and the internal pointers
238 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
240 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
241 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
248 if (!m_bCoInitializeCalled) {
249 hr = CoInitialize(NULL);
251 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
252 errno = b_errno_win32;
255 m_bCoInitializeCalled = true;
258 // Initialize COM security
259 if (!m_bCoInitializeSecurityCalled) {
261 CoInitializeSecurity(
262 NULL, // Allow *all* VSS writers to communicate back!
263 -1, // Default COM authentication service
264 NULL, // Default COM authorization service
265 NULL, // reserved parameter
266 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
267 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
268 NULL, // Default COM authentication settings
269 EOAC_NONE, // No special options
270 NULL // Reserved parameter
274 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
275 errno = b_errno_win32;
278 m_bCoInitializeSecurityCalled = true;
281 // Release the IVssBackupComponents interface
283 m_pVssObject->Release();
287 // Create the internal backup components object
288 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
290 Dmsg1(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X\n", hr);
291 errno = b_errno_win32;
295 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
296 if (dwContext != VSS_CTX_BACKUP) {
297 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
299 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
300 errno = b_errno_win32;
306 if (!bDuringRestore) {
307 // 1. InitializeForBackup
308 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
310 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
311 errno = b_errno_win32;
316 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
318 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
319 errno = b_errno_win32;
323 CComPtr<IVssAsync> pAsync1;
324 // 3. GatherWriterMetaData
325 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
327 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
328 errno = b_errno_win32;
331 // Waits for the async operation to finish and checks the result
332 WaitAndCheckForAsyncOperation(pAsync1.p);
335 // We are during restore now?
336 m_bDuringRestore = bDuringRestore;
339 m_dwContext = dwContext;
345 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
347 // Wait until the async operation finishes
348 // unfortunately we can't use a timeout here yet.
349 // the interface would allow it on W2k3,
350 // but it is not implemented yet....
354 // Check the result of the asynchronous operation
355 HRESULT hrReturned = S_OK;
357 int timeout = 600; // 10 minutes....
361 if (hrReturned != S_OK)
365 hr = pAsync->QueryStatus(&hrReturned, NULL);
369 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
371 if (hrReturned == VSS_S_ASYNC_FINISHED)
376 // Check if the async operation succeeded...
377 if(hrReturned != VSS_S_ASYNC_FINISHED) {
378 wchar_t *pwszBuffer = NULL;
379 /* I don't see the usefulness of the following -- KES */
381 FORMAT_MESSAGE_ALLOCATE_BUFFER
382 | FORMAT_MESSAGE_FROM_SYSTEM
383 | FORMAT_MESSAGE_IGNORE_INSERTS,
385 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
386 (LPWSTR)&pwszBuffer, 0, NULL);
388 LocalFree(pwszBuffer);
389 errno = b_errno_win32;
396 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
398 /* szDriveLetters contains all drive letters in uppercase */
399 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
400 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
402 if (!m_pVssObject || m_bBackupIsInitialized) {
407 m_uidCurrentSnapshotSet = GUID_NULL;
409 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
411 /* startSnapshotSet */
413 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
415 /* AddToSnapshotSet */
423 CComPtr<IVssAsync> pAsync1;
424 CComPtr<IVssAsync> pAsync2;
427 for (size_t i=0; i < strlen (szDriveLetters); i++) {
428 szDrive[0] = szDriveLetters[i];
429 volume = GetUniqueVolumeNameForPath(szDrive);
430 // store uniquevolumname
431 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
432 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
434 szDriveLetters[i] = tolower (szDriveLetters[i]);
438 /* PrepareForBackup */
439 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
440 errno = b_errno_win32;
444 // Waits for the async operation to finish and checks the result
445 WaitAndCheckForAsyncOperation(pAsync1.p);
447 /* get latest info about writer status */
448 if (!CheckWriterStatus()) {
449 errno = b_errno_win32;
454 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
455 errno = b_errno_win32;
459 // Waits for the async operation to finish and checks the result
460 WaitAndCheckForAsyncOperation(pAsync2.p);
462 /* query snapshot info */
463 QuerySnapshotSet(m_uidCurrentSnapshotSet);
465 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
467 m_bBackupIsInitialized = true;
472 BOOL VSSClientGeneric::CloseBackup()
478 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
479 CComPtr<IVssAsync> pAsync;
481 SetVSSPathConvert(NULL, NULL);
483 m_bBackupIsInitialized = false;
485 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
486 // Waits for the async operation to finish and checks the result
487 WaitAndCheckForAsyncOperation(pAsync.p);
490 errno = b_errno_win32;
494 /* get latest info about writer status */
497 if (m_uidCurrentSnapshotSet != GUID_NULL) {
498 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
501 pVss->DeleteSnapshots(
502 m_uidCurrentSnapshotSet,
503 VSS_OBJECT_SNAPSHOT_SET,
506 &idNonDeletedSnapshotID);
508 m_uidCurrentSnapshotSet = GUID_NULL;
515 // Call CoUninitialize if the CoInitialize was performed sucesfully
516 if (m_bCoInitializeCalled) {
518 m_bCoInitializeCalled = false;
524 // Query all the shadow copies in the given set
525 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
527 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
532 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
534 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
539 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
541 // Get list all shadow copies.
542 CComPtr<IVssEnumObject> pIEnumSnapshots;
543 HRESULT hr = pVss->Query( GUID_NULL,
546 (IVssEnumObject**)(&pIEnumSnapshots) );
548 // If there are no shadow copies, just return
550 errno = b_errno_win32;
554 // Enumerate all shadow copies.
555 VSS_OBJECT_PROP Prop;
556 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
559 // Get the next element
561 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
563 // We reached the end of list
567 // Print the shadow copy (if not filtered out)
568 if (Snap.m_SnapshotSetId == snapshotSetID) {
569 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
570 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
571 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
576 p_VssFreeSnapshotProperties(&Snap);
581 // Check the status for all selected writers
582 BOOL VSSClientGeneric::CheckWriterStatus()
585 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
587 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
590 // Gather writer status to detect potential errors
591 CComPtr<IVssAsync> pAsync;
593 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
595 errno = b_errno_win32;
599 // Waits for the async operation to finish and checks the result
600 WaitAndCheckForAsyncOperation(pAsync.p);
602 unsigned cWriters = 0;
604 hr = pVss->GetWriterStatusCount(&cWriters);
606 errno = b_errno_win32;
612 // Enumerate each writer
613 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
614 VSS_ID idInstance = GUID_NULL;
615 VSS_ID idWriter= GUID_NULL;
616 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
617 CComBSTR bstrWriterName;
618 HRESULT hrWriterFailure = S_OK;
621 hr = pVss->GetWriterStatus(iWriter,
632 switch(eWriterStatus) {
633 case VSS_WS_FAILED_AT_IDENTIFY:
634 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
635 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
636 case VSS_WS_FAILED_AT_FREEZE:
637 case VSS_WS_FAILED_AT_THAW:
638 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
639 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
640 case VSS_WS_FAILED_AT_PRE_RESTORE:
641 case VSS_WS_FAILED_AT_POST_RESTORE:
642 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
643 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
654 /* store text info */
657 bstrncpy(str, "\"", sizeof(str));
658 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
659 bstrncat(str, szBuf, sizeof(str));
660 bstrncat(str, "\", State: 0x", sizeof(str));
661 itoa(eWriterStatus, szBuf, sizeof(szBuf));
662 bstrncat(str, szBuf, sizeof(str));
663 bstrncat(str, " (", sizeof(str));
664 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
665 bstrncat(str, szBuf, sizeof(str));
666 bstrncat(str, ")", sizeof(str));
668 AppendWriterInfo(nState, (const char *)str);
671 hr = pVss->FreeWriterStatus();
674 errno = b_errno_win32;
682 #endif /* WIN32_VSS */