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 three of the GNU Affero 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 Affero 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
57 * Kludges to get Vista code to compile.
62 #define __RPC_unique_pointer
64 #define __RPC__out_ecount_part(x, y)
65 #define __RPC__deref_inout_opt
68 #if !defined(ENABLE_NLS)
69 #define setlocale(p, d)
73 // Used for safe string manipulation
77 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
78 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
81 class IXMLDOMDocument;
84 /* Reduce compiler warnings from Windows vss code */
89 #define VSSClientGeneric VSSClientXP
91 #include "inc/WinXP/vss.h"
92 #include "inc/WinXP/vswriter.h"
93 #include "inc/WinXP/vsbackup.h"
98 #define VSSClientGeneric VSSClient2003
100 #include "inc/Win2003/vss.h"
101 #include "inc/Win2003/vswriter.h"
102 #include "inc/Win2003/vsbackup.h"
106 #define VSSClientGeneric VSSClientVista
108 #include "inc/Win2003/vss.h"
109 #include "inc/Win2003/vswriter.h"
110 #include "inc/Win2003/vsbackup.h"
114 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
115 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
117 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
118 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
126 * some helper functions
131 // Append a backslash to the current string
132 inline wstring AppendBackslash(wstring str)
134 if (str.length() == 0)
135 return wstring(L"\\");
136 if (str[str.length() - 1] == L'\\')
138 return str.append(L"\\");
141 // Get the unique volume name for the given path
142 inline wstring GetUniqueVolumeNameForPath(wstring path)
144 if (path.length() <= 0) {
148 // Add the backslash termination, if needed
149 path = AppendBackslash(path);
151 // Get the root path of the volume
152 wchar_t volumeRootPath[MAX_PATH];
153 wchar_t volumeName[MAX_PATH];
154 wchar_t volumeUniqueName[MAX_PATH];
156 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
159 // Get the volume name alias (might be different from the unique volume name in rare cases)
160 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
163 // Get the unique volume name
164 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
167 return volumeUniqueName;
171 // Helper macro for quick treatment of case statements for error codes
172 #define GEN_MERGE(A, B) A##B
173 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
175 #define CHECK_CASE_FOR_CONSTANT(value) \
176 case value: return (GEN_MAKE_W(#value));
179 // Convert a writer status into a string
180 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
182 switch (eWriterStatus) {
183 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
184 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
185 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
186 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
187 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
188 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
189 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
190 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
191 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
192 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
193 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
194 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
195 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
196 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
199 return L"Error or Undefined";
206 /* 64 bit entrypoint name */
207 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
209 /* 32 bit entrypoint name */
210 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
213 VSSClientGeneric::VSSClientGeneric()
215 m_hLib = LoadLibraryA("VSSAPI.DLL");
217 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
218 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
219 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
220 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
227 VSSClientGeneric::~VSSClientGeneric()
233 // Initialize the COM infrastructure and the internal pointers
234 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore, bool (*VssInitCallback)(JCR *, int))
236 CComPtr<IVssAsync> pAsync1;
237 VSS_BACKUP_TYPE backup_type;
239 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
240 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
247 if (!m_bCoInitializeCalled) {
248 hr = CoInitialize(NULL);
250 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
251 errno = b_errno_win32;
254 m_bCoInitializeCalled = true;
257 // Initialize COM security
258 if (!m_bCoInitializeSecurityCalled) {
260 CoInitializeSecurity(
261 NULL, // Allow *all* VSS writers to communicate back!
262 -1, // Default COM authentication service
263 NULL, // Default COM authorization service
264 NULL, // reserved parameter
265 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
266 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
267 NULL, // Default COM authentication settings
268 EOAC_NONE, // No special options
269 NULL // Reserved parameter
273 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
274 errno = b_errno_win32;
277 m_bCoInitializeSecurityCalled = true;
280 // Release the IVssBackupComponents interface
282 m_pVssObject->Release();
286 // Create the internal backup components object
287 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
290 Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
291 hr, be.bstrerror(b_errno_win32));
292 errno = b_errno_win32;
296 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
297 if (dwContext != VSS_CTX_BACKUP) {
298 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
300 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
301 errno = b_errno_win32;
307 if (!bDuringRestore) {
308 // 1. InitializeForBackup
309 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
311 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
312 errno = b_errno_win32;
317 switch (m_jcr->getJobLevel())
320 backup_type = VSS_BT_FULL;
323 backup_type = VSS_BT_DIFFERENTIAL;
326 backup_type = VSS_BT_INCREMENTAL;
329 Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n", m_jcr->getJobLevel());
330 backup_type = VSS_BT_FULL;
333 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, backup_type, false);
335 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
336 errno = b_errno_win32;
340 // 3. GatherWriterMetaData
341 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
343 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
344 errno = b_errno_win32;
347 // Waits for the async operation to finish and checks the result
348 WaitAndCheckForAsyncOperation(pAsync1.p);
352 * Initialize for restore
361 /* obviously this is just temporary - the xml should come from somewhere like the catalog */
362 fd = open("C:\\james.xml", O_RDONLY);
363 Dmsg1(0, "fd = %d\n", fd);
365 Dmsg1(0, "size = %d\n", stat.st_size);
366 xml = new WCHAR[stat.st_size / sizeof(WCHAR) + 1];
367 read(fd, xml, stat.st_size);
369 xml[stat.st_size / sizeof(WCHAR)] = 0;
372 // 1. InitializeForRestore
373 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForRestore(m_metadata);
375 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForRestore returned 0x%08X\n", hr);
376 errno = b_errno_win32;
379 VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_INIT);
381 // 2. GatherWriterMetaData
382 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
384 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
385 errno = b_errno_win32;
388 WaitAndCheckForAsyncOperation(pAsync1.p);
389 VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_GATHER);
392 hr = ((IVssBackupComponents*) m_pVssObject)->PreRestore(&pAsync1.p);
394 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->PreRestore returned 0x%08X\n", hr);
395 errno = b_errno_win32;
398 WaitAndCheckForAsyncOperation(pAsync1.p);
399 /* get latest info about writer status */
400 if (!CheckWriterStatus()) {
401 Dmsg0(0, "VSSClientGeneric::InitializePostPlugin: Failed to CheckWriterstatus\n");
402 errno = b_errno_win32;
407 // We are during restore now?
408 m_bDuringRestore = bDuringRestore;
411 m_dwContext = dwContext;
416 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
418 // Wait until the async operation finishes
419 // unfortunately we can't use a timeout here yet.
420 // the interface would allow it on W2k3,
421 // but it is not implemented yet....
425 // Check the result of the asynchronous operation
426 HRESULT hrReturned = S_OK;
428 int timeout = 600; // 10 minutes....
432 if (hrReturned != S_OK)
436 hr = pAsync->QueryStatus(&hrReturned, NULL);
440 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
442 if (hrReturned == VSS_S_ASYNC_FINISHED)
447 // Check if the async operation succeeded...
448 if(hrReturned != VSS_S_ASYNC_FINISHED) {
449 wchar_t *pwszBuffer = NULL;
450 /* I don't see the usefulness of the following -- KES */
452 FORMAT_MESSAGE_ALLOCATE_BUFFER
453 | FORMAT_MESSAGE_FROM_SYSTEM
454 | FORMAT_MESSAGE_IGNORE_INSERTS,
456 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
457 (LPWSTR)&pwszBuffer, 0, NULL);
459 LocalFree(pwszBuffer);
460 errno = b_errno_win32;
467 bool VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
469 /* szDriveLetters contains all drive letters in uppercase */
470 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
471 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
473 if (!m_pVssObject || m_bBackupIsInitialized) {
478 m_uidCurrentSnapshotSet = GUID_NULL;
480 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
482 /* startSnapshotSet */
484 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
486 /* AddToSnapshotSet */
494 CComPtr<IVssAsync> pAsync1;
495 CComPtr<IVssAsync> pAsync2;
498 for (size_t i=0; i < strlen (szDriveLetters); i++) {
499 szDrive[0] = szDriveLetters[i];
500 volume = GetUniqueVolumeNameForPath(szDrive);
501 // store uniquevolumname
502 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
503 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
505 szDriveLetters[i] = tolower (szDriveLetters[i]);
509 /* PrepareForBackup */
510 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
511 errno = b_errno_win32;
515 // Waits for the async operation to finish and checks the result
516 WaitAndCheckForAsyncOperation(pAsync1.p);
518 /* get latest info about writer status */
519 if (!CheckWriterStatus()) {
520 errno = b_errno_win32;
525 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
526 errno = b_errno_win32;
530 // Waits for the async operation to finish and checks the result
531 WaitAndCheckForAsyncOperation(pAsync2.p);
533 /* query snapshot info */
534 QuerySnapshotSet(m_uidCurrentSnapshotSet);
536 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
538 m_bBackupIsInitialized = true;
543 bool VSSClientGeneric::CloseBackup()
552 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
553 CComPtr<IVssAsync> pAsync;
555 SetVSSPathConvert(NULL, NULL);
557 m_bBackupIsInitialized = false;
559 hr = pVss->SaveAsXML(&xml);
560 if (hr == ERROR_SUCCESS)
570 hr = pVss->SaveAsXML(&xml);
571 fd = open("C:\\james.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
572 write(fd, xml, wcslen(xml) * sizeof(WCHAR));
576 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
577 // Waits for the async operation to finish and checks the result
578 WaitAndCheckForAsyncOperation(pAsync.p);
581 errno = b_errno_win32;
585 /* get latest info about writer status */
588 if (m_uidCurrentSnapshotSet != GUID_NULL) {
589 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
592 pVss->DeleteSnapshots(
593 m_uidCurrentSnapshotSet,
594 VSS_OBJECT_SNAPSHOT_SET,
597 &idNonDeletedSnapshotID);
599 m_uidCurrentSnapshotSet = GUID_NULL;
606 // Call CoUninitialize if the CoInitialize was performed sucesfully
607 if (m_bCoInitializeCalled) {
609 m_bCoInitializeCalled = false;
615 WCHAR *VSSClientGeneric::GetMetadata()
620 bool VSSClientGeneric::CloseRestore()
623 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
624 CComPtr<IVssAsync> pAsync;
631 if (SUCCEEDED(hr = pVss->PostRestore(&pAsync.p))) {
632 // Waits for the async operation to finish and checks the result
633 WaitAndCheckForAsyncOperation(pAsync.p);
634 /* get latest info about writer status */
635 if (!CheckWriterStatus()) {
636 errno = b_errno_win32;
640 errno = b_errno_win32;
646 // Query all the shadow copies in the given set
647 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
649 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
654 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
656 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
661 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
663 // Get list all shadow copies.
664 CComPtr<IVssEnumObject> pIEnumSnapshots;
665 HRESULT hr = pVss->Query( GUID_NULL,
668 (IVssEnumObject**)(&pIEnumSnapshots) );
670 // If there are no shadow copies, just return
672 errno = b_errno_win32;
676 // Enumerate all shadow copies.
677 VSS_OBJECT_PROP Prop;
678 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
681 // Get the next element
683 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
685 // We reached the end of list
689 // Print the shadow copy (if not filtered out)
690 if (Snap.m_SnapshotSetId == snapshotSetID) {
691 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
692 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
693 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
698 p_VssFreeSnapshotProperties(&Snap);
703 // Check the status for all selected writers
704 bool VSSClientGeneric::CheckWriterStatus()
707 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
709 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
712 // Gather writer status to detect potential errors
713 CComPtr<IVssAsync> pAsync;
715 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
717 errno = b_errno_win32;
721 // Waits for the async operation to finish and checks the result
722 WaitAndCheckForAsyncOperation(pAsync.p);
724 unsigned cWriters = 0;
726 hr = pVss->GetWriterStatusCount(&cWriters);
728 errno = b_errno_win32;
734 // Enumerate each writer
735 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
736 VSS_ID idInstance = GUID_NULL;
737 VSS_ID idWriter= GUID_NULL;
738 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
739 CComBSTR bstrWriterName;
740 HRESULT hrWriterFailure = S_OK;
743 hr = pVss->GetWriterStatus(iWriter,
754 switch(eWriterStatus) {
755 case VSS_WS_FAILED_AT_IDENTIFY:
756 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
757 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
758 case VSS_WS_FAILED_AT_FREEZE:
759 case VSS_WS_FAILED_AT_THAW:
760 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
761 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
762 case VSS_WS_FAILED_AT_PRE_RESTORE:
763 case VSS_WS_FAILED_AT_POST_RESTORE:
764 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
765 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
776 /* store text info */
779 bstrncpy(str, "\"", sizeof(str));
780 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
781 bstrncat(str, szBuf, sizeof(str));
782 bstrncat(str, "\", State: 0x", sizeof(str));
783 itoa(eWriterStatus, szBuf, sizeof(szBuf));
784 bstrncat(str, szBuf, sizeof(str));
785 bstrncat(str, " (", sizeof(str));
786 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
787 bstrncat(str, szBuf, sizeof(str));
788 bstrncat(str, ")", sizeof(str));
790 AppendWriterInfo(nState, (const char *)str);
793 hr = pVss->FreeWriterStatus();
796 errno = b_errno_win32;
804 #endif /* WIN32_VSS */