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 */
88 #define VSSClientGeneric VSSClientXP
90 #include "inc/WinXP/vss.h"
91 #include "inc/WinXP/vswriter.h"
92 #include "inc/WinXP/vsbackup.h"
97 #define VSSClientGeneric VSSClient2003
99 #include "inc/Win2003/vss.h"
100 #include "inc/Win2003/vswriter.h"
101 #include "inc/Win2003/vsbackup.h"
105 #define VSSClientGeneric VSSClientVista
107 #include "inc/Win2003/vss.h"
108 #include "inc/Win2003/vswriter.h"
109 #include "inc/Win2003/vsbackup.h"
113 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
114 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
116 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
117 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
125 * some helper functions
130 // Append a backslash to the current string
131 inline wstring AppendBackslash(wstring str)
133 if (str.length() == 0)
134 return wstring(L"\\");
135 if (str[str.length() - 1] == L'\\')
137 return str.append(L"\\");
140 // Get the unique volume name for the given path
141 inline wstring GetUniqueVolumeNameForPath(wstring path)
143 if (path.length() <= 0) {
147 // Add the backslash termination, if needed
148 path = AppendBackslash(path);
150 // Get the root path of the volume
151 wchar_t volumeRootPath[MAX_PATH];
152 wchar_t volumeName[MAX_PATH];
153 wchar_t volumeUniqueName[MAX_PATH];
155 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
158 // Get the volume name alias (might be different from the unique volume name in rare cases)
159 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
162 // Get the unique volume name
163 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
166 return volumeUniqueName;
170 // Helper macro for quick treatment of case statements for error codes
171 #define GEN_MERGE(A, B) A##B
172 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
174 #define CHECK_CASE_FOR_CONSTANT(value) \
175 case value: return (GEN_MAKE_W(#value));
178 // Convert a writer status into a string
179 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
181 switch (eWriterStatus) {
182 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
183 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
184 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
185 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
186 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
187 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
188 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
189 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
190 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
191 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
192 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
193 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
194 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
195 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
198 return L"Error or Undefined";
205 /* 64 bit entrypoint name */
206 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
208 /* 32 bit entrypoint name */
209 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
212 VSSClientGeneric::VSSClientGeneric()
214 m_hLib = LoadLibraryA("VSSAPI.DLL");
216 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
217 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, bool (*VssInitCallback)(JCR *, int))
235 CComPtr<IVssAsync> pAsync1;
237 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
238 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
245 if (!m_bCoInitializeCalled) {
246 hr = CoInitialize(NULL);
248 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
249 errno = b_errno_win32;
252 m_bCoInitializeCalled = true;
255 // Initialize COM security
256 if (!m_bCoInitializeSecurityCalled) {
258 CoInitializeSecurity(
259 NULL, // Allow *all* VSS writers to communicate back!
260 -1, // Default COM authentication service
261 NULL, // Default COM authorization service
262 NULL, // reserved parameter
263 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
264 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
265 NULL, // Default COM authentication settings
266 EOAC_NONE, // No special options
267 NULL // Reserved parameter
271 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
272 errno = b_errno_win32;
275 m_bCoInitializeSecurityCalled = true;
278 // Release the IVssBackupComponents interface
280 m_pVssObject->Release();
284 // Create the internal backup components object
285 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
288 Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
289 hr, be.bstrerror(b_errno_win32));
290 errno = b_errno_win32;
294 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
295 if (dwContext != VSS_CTX_BACKUP) {
296 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
298 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
299 errno = b_errno_win32;
305 if (!bDuringRestore) {
306 // 1. InitializeForBackup
307 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
309 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
310 errno = b_errno_win32;
315 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
317 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
318 errno = b_errno_win32;
322 // 3. GatherWriterMetaData
323 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
325 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
326 errno = b_errno_win32;
329 // Waits for the async operation to finish and checks the result
330 WaitAndCheckForAsyncOperation(pAsync1.p);
334 * Initialize for restore
342 /* obviously this is just temporary - the xml should come from somewhere like the catalog */
343 fd = open("C:\\james.xml", O_RDONLY);
344 Dmsg1(0, "fd = %d\n", fd);
346 Dmsg1(0, "size = %d\n", stat.st_size);
347 xml = new WCHAR[stat.st_size / sizeof(WCHAR) + 1];
348 read(fd, xml, stat.st_size);
350 xml[stat.st_size / sizeof(WCHAR)] = 0;
352 // 1. InitializeForRestore
353 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForRestore(xml);
355 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForRestore returned 0x%08X\n", hr);
356 errno = b_errno_win32;
359 VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_INIT);
361 // 2. GatherWriterMetaData
362 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
364 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
365 errno = b_errno_win32;
368 WaitAndCheckForAsyncOperation(pAsync1.p);
369 VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_GATHER);
372 hr = ((IVssBackupComponents*) m_pVssObject)->PreRestore(&pAsync1.p);
374 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->PreRestore returned 0x%08X\n", hr);
375 errno = b_errno_win32;
378 WaitAndCheckForAsyncOperation(pAsync1.p);
379 /* get latest info about writer status */
380 if (!CheckWriterStatus()) {
381 Dmsg0(0, "VSSClientGeneric::InitializePostPlugin: Failed to CheckWriterstatus\n");
382 errno = b_errno_win32;
387 // We are during restore now?
388 m_bDuringRestore = bDuringRestore;
391 m_dwContext = dwContext;
396 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
398 // Wait until the async operation finishes
399 // unfortunately we can't use a timeout here yet.
400 // the interface would allow it on W2k3,
401 // but it is not implemented yet....
405 // Check the result of the asynchronous operation
406 HRESULT hrReturned = S_OK;
408 int timeout = 600; // 10 minutes....
412 if (hrReturned != S_OK)
416 hr = pAsync->QueryStatus(&hrReturned, NULL);
420 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
422 if (hrReturned == VSS_S_ASYNC_FINISHED)
427 // Check if the async operation succeeded...
428 if(hrReturned != VSS_S_ASYNC_FINISHED) {
429 wchar_t *pwszBuffer = NULL;
430 /* I don't see the usefulness of the following -- KES */
432 FORMAT_MESSAGE_ALLOCATE_BUFFER
433 | FORMAT_MESSAGE_FROM_SYSTEM
434 | FORMAT_MESSAGE_IGNORE_INSERTS,
436 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
437 (LPWSTR)&pwszBuffer, 0, NULL);
439 LocalFree(pwszBuffer);
440 errno = b_errno_win32;
447 bool VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
449 /* szDriveLetters contains all drive letters in uppercase */
450 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
451 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
453 if (!m_pVssObject || m_bBackupIsInitialized) {
458 m_uidCurrentSnapshotSet = GUID_NULL;
460 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
462 /* startSnapshotSet */
464 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
466 /* AddToSnapshotSet */
474 CComPtr<IVssAsync> pAsync1;
475 CComPtr<IVssAsync> pAsync2;
478 for (size_t i=0; i < strlen (szDriveLetters); i++) {
479 szDrive[0] = szDriveLetters[i];
480 volume = GetUniqueVolumeNameForPath(szDrive);
481 // store uniquevolumname
482 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
483 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
485 szDriveLetters[i] = tolower (szDriveLetters[i]);
489 /* PrepareForBackup */
490 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
491 errno = b_errno_win32;
495 // Waits for the async operation to finish and checks the result
496 WaitAndCheckForAsyncOperation(pAsync1.p);
498 /* get latest info about writer status */
499 if (!CheckWriterStatus()) {
500 errno = b_errno_win32;
505 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
506 errno = b_errno_win32;
510 // Waits for the async operation to finish and checks the result
511 WaitAndCheckForAsyncOperation(pAsync2.p);
513 /* query snapshot info */
514 QuerySnapshotSet(m_uidCurrentSnapshotSet);
516 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
518 m_bBackupIsInitialized = true;
523 bool VSSClientGeneric::CloseBackup()
529 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
530 CComPtr<IVssAsync> pAsync;
532 SetVSSPathConvert(NULL, NULL);
534 m_bBackupIsInitialized = false;
541 hr = pVss->SaveAsXML(&xml);
542 fd = open("C:\\james.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
543 write(fd, xml, wcslen(xml) * sizeof(WCHAR));
546 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
547 // Waits for the async operation to finish and checks the result
548 WaitAndCheckForAsyncOperation(pAsync.p);
551 errno = b_errno_win32;
555 /* get latest info about writer status */
558 if (m_uidCurrentSnapshotSet != GUID_NULL) {
559 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
562 pVss->DeleteSnapshots(
563 m_uidCurrentSnapshotSet,
564 VSS_OBJECT_SNAPSHOT_SET,
567 &idNonDeletedSnapshotID);
569 m_uidCurrentSnapshotSet = GUID_NULL;
576 // Call CoUninitialize if the CoInitialize was performed sucesfully
577 if (m_bCoInitializeCalled) {
579 m_bCoInitializeCalled = false;
585 bool VSSClientGeneric::CloseRestore()
588 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
589 CComPtr<IVssAsync> pAsync;
596 if (SUCCEEDED(hr = pVss->PostRestore(&pAsync.p))) {
597 // Waits for the async operation to finish and checks the result
598 WaitAndCheckForAsyncOperation(pAsync.p);
599 /* get latest info about writer status */
600 if (!CheckWriterStatus()) {
601 errno = b_errno_win32;
605 errno = b_errno_win32;
611 // Query all the shadow copies in the given set
612 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
614 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
619 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
621 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
626 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
628 // Get list all shadow copies.
629 CComPtr<IVssEnumObject> pIEnumSnapshots;
630 HRESULT hr = pVss->Query( GUID_NULL,
633 (IVssEnumObject**)(&pIEnumSnapshots) );
635 // If there are no shadow copies, just return
637 errno = b_errno_win32;
641 // Enumerate all shadow copies.
642 VSS_OBJECT_PROP Prop;
643 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
646 // Get the next element
648 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
650 // We reached the end of list
654 // Print the shadow copy (if not filtered out)
655 if (Snap.m_SnapshotSetId == snapshotSetID) {
656 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
657 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
658 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
663 p_VssFreeSnapshotProperties(&Snap);
668 // Check the status for all selected writers
669 bool VSSClientGeneric::CheckWriterStatus()
672 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
674 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
677 // Gather writer status to detect potential errors
678 CComPtr<IVssAsync> pAsync;
680 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
682 errno = b_errno_win32;
686 // Waits for the async operation to finish and checks the result
687 WaitAndCheckForAsyncOperation(pAsync.p);
689 unsigned cWriters = 0;
691 hr = pVss->GetWriterStatusCount(&cWriters);
693 errno = b_errno_win32;
699 // Enumerate each writer
700 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
701 VSS_ID idInstance = GUID_NULL;
702 VSS_ID idWriter= GUID_NULL;
703 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
704 CComBSTR bstrWriterName;
705 HRESULT hrWriterFailure = S_OK;
708 hr = pVss->GetWriterStatus(iWriter,
719 switch(eWriterStatus) {
720 case VSS_WS_FAILED_AT_IDENTIFY:
721 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
722 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
723 case VSS_WS_FAILED_AT_FREEZE:
724 case VSS_WS_FAILED_AT_THAW:
725 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
726 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
727 case VSS_WS_FAILED_AT_PRE_RESTORE:
728 case VSS_WS_FAILED_AT_POST_RESTORE:
729 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
730 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
741 /* store text info */
744 bstrncpy(str, "\"", sizeof(str));
745 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
746 bstrncat(str, szBuf, sizeof(str));
747 bstrncat(str, "\", State: 0x", sizeof(str));
748 itoa(eWriterStatus, szBuf, sizeof(szBuf));
749 bstrncat(str, szBuf, sizeof(str));
750 bstrncat(str, " (", sizeof(str));
751 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
752 bstrncat(str, szBuf, sizeof(str));
753 bstrncat(str, ")", sizeof(str));
755 AppendWriterInfo(nState, (const char *)str);
758 hr = pVss->FreeWriterStatus();
761 errno = b_errno_win32;
769 #endif /* WIN32_VSS */