2 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
4 // Copyright transferred from MATRIX-Computer GmbH to
5 // Kern Sibbald by express permission.
7 // Author : Thorsten Engel
8 // Created On : Fri May 06 21:44:00 2005
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
55 #if !defined(ENABLE_NLS)
56 #define setlocale(p, d)
60 // Used for safe string manipulation
64 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
65 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
68 class IXMLDOMDocument;
72 #pragma message("compile VSS for Windows XP")
73 #define VSSClientGeneric VSSClientXP
75 #include "inc/WinXP/vss.h"
76 #include "inc/WinXP/vswriter.h"
77 #include "inc/WinXP/vsbackup.h"
80 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
81 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
83 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
84 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
86 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
90 #pragma message("compile VSS for Windows 2003")
91 #define VSSClientGeneric VSSClient2003
93 #include "inc/Win2003/vss.h"
94 #include "inc/Win2003/vswriter.h"
95 #include "inc/Win2003/vsbackup.h"
98 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
99 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
101 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
102 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
104 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
111 * some helper functions
116 // Append a backslash to the current string
117 inline wstring AppendBackslash(wstring str)
119 if (str.length() == 0)
120 return wstring(L"\\");
121 if (str[str.length() - 1] == L'\\')
123 return str.append(L"\\");
126 // Get the unique volume name for the given path
127 inline wstring GetUniqueVolumeNameForPath(wstring path)
129 if (path.length() <= 0) {
133 // Add the backslash termination, if needed
134 path = AppendBackslash(path);
136 // Get the root path of the volume
137 wchar_t volumeRootPath[MAX_PATH];
138 wchar_t volumeName[MAX_PATH];
139 wchar_t volumeUniqueName[MAX_PATH];
141 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
144 // Get the volume name alias (might be different from the unique volume name in rare cases)
145 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
148 // Get the unique volume name
149 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
152 return volumeUniqueName;
156 // Helper macro for quick treatment of case statements for error codes
157 #define GEN_MERGE(A, B) A##B
158 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
160 #define CHECK_CASE_FOR_CONSTANT(value) \
161 case value: return (GEN_MAKE_W(#value));
164 // Convert a writer status into a string
165 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
167 switch (eWriterStatus) {
168 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
169 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
170 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
171 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
172 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
173 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
174 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
175 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
176 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
177 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
178 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
179 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
180 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
181 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
184 return L"Error or Undefined";
190 VSSClientGeneric::VSSClientGeneric()
192 m_hLib = LoadLibraryA("VSSAPI.DLL");
194 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
195 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
197 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
198 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
205 VSSClientGeneric::~VSSClientGeneric()
211 // Initialize the COM infrastructure and the internal pointers
212 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
214 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
215 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
222 if (!m_bCoInitializeCalled) {
223 hr = CoInitialize(NULL);
225 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
226 errno = b_errno_win32;
229 m_bCoInitializeCalled = true;
232 // Initialize COM security
233 if (!m_bCoInitializeSecurityCalled) {
235 CoInitializeSecurity(
236 NULL, // Allow *all* VSS writers to communicate back!
237 -1, // Default COM authentication service
238 NULL, // Default COM authorization service
239 NULL, // reserved parameter
240 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
241 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
242 NULL, // Default COM authentication settings
243 EOAC_NONE, // No special options
244 NULL // Reserved parameter
248 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
249 errno = b_errno_win32;
252 m_bCoInitializeSecurityCalled = true;
255 // Release the IVssBackupComponents interface
257 m_pVssObject->Release();
261 // Create the internal backup components object
262 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
264 Dmsg1(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X\n", hr);
265 errno = b_errno_win32;
270 if (dwContext != VSS_CTX_BACKUP) {
271 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
273 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
274 errno = b_errno_win32;
280 if (!bDuringRestore) {
281 // 1. InitializeForBackup
282 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
284 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
285 errno = b_errno_win32;
290 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
292 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
293 errno = b_errno_win32;
297 CComPtr<IVssAsync> pAsync1;
298 // 3. GatherWriterMetaData
299 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
301 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
302 errno = b_errno_win32;
305 // Waits for the async operation to finish and checks the result
306 WaitAndCheckForAsyncOperation(pAsync1.p);
309 // We are during restore now?
310 m_bDuringRestore = bDuringRestore;
313 m_dwContext = dwContext;
319 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
321 // Wait until the async operation finishes
322 // unfortunately we can't use a timeout here yet.
323 // the interface would allow it on W2k3,
324 // but it is not implemented yet....
328 // Check the result of the asynchronous operation
329 HRESULT hrReturned = S_OK;
331 int timeout = 600; // 10 minutes....
335 if (hrReturned != S_OK)
339 hr = pAsync->QueryStatus(&hrReturned, NULL);
343 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
345 if (hrReturned == VSS_S_ASYNC_FINISHED)
350 // Check if the async operation succeeded...
351 if(hrReturned != VSS_S_ASYNC_FINISHED) {
352 wchar_t *pwszBuffer = NULL;
353 DWORD dwRet = ::FormatMessageW(
354 FORMAT_MESSAGE_ALLOCATE_BUFFER
355 | FORMAT_MESSAGE_FROM_SYSTEM
356 | FORMAT_MESSAGE_IGNORE_INSERTS,
358 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
359 (LPWSTR)&pwszBuffer, 0, NULL);
362 LocalFree(pwszBuffer);
364 errno = b_errno_win32;
371 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
373 /* szDriveLetters contains all drive letters in uppercase */
374 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
375 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
377 if (!m_pVssObject || m_bBackupIsInitialized) {
382 m_uidCurrentSnapshotSet = GUID_NULL;
384 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
386 /* startSnapshotSet */
388 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
390 /* AddToSnapshotSet */
398 CComPtr<IVssAsync> pAsync1;
399 CComPtr<IVssAsync> pAsync2;
402 for (size_t i=0; i < strlen (szDriveLetters); i++) {
403 szDrive[0] = szDriveLetters[i];
404 volume = GetUniqueVolumeNameForPath(szDrive);
405 // store uniquevolumname
406 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
407 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
409 szDriveLetters[i] = tolower (szDriveLetters[i]);
413 /* PrepareForBackup */
414 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
415 errno = b_errno_win32;
419 // Waits for the async operation to finish and checks the result
420 WaitAndCheckForAsyncOperation(pAsync1.p);
422 /* get latest info about writer status */
423 if (!CheckWriterStatus()) {
424 errno = b_errno_win32;
429 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
430 errno = b_errno_win32;
434 // Waits for the async operation to finish and checks the result
435 WaitAndCheckForAsyncOperation(pAsync2.p);
437 /* query snapshot info */
438 QuerySnapshotSet(m_uidCurrentSnapshotSet);
440 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
442 m_bBackupIsInitialized = true;
447 BOOL VSSClientGeneric::CloseBackup()
453 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
454 CComPtr<IVssAsync> pAsync;
456 SetVSSPathConvert(NULL, NULL);
458 m_bBackupIsInitialized = false;
460 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
461 // Waits for the async operation to finish and checks the result
462 WaitAndCheckForAsyncOperation(pAsync.p);
465 errno = b_errno_win32;
469 /* get latest info about writer status */
472 if (m_uidCurrentSnapshotSet != GUID_NULL) {
473 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
476 pVss->DeleteSnapshots(
477 m_uidCurrentSnapshotSet,
478 VSS_OBJECT_SNAPSHOT_SET,
481 &idNonDeletedSnapshotID);
483 m_uidCurrentSnapshotSet = GUID_NULL;
490 // Call CoUninitialize if the CoInitialize was performed sucesfully
491 if (m_bCoInitializeCalled) {
493 m_bCoInitializeCalled = false;
499 // Query all the shadow copies in the given set
500 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
502 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
507 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
509 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
514 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
516 // Get list all shadow copies.
517 CComPtr<IVssEnumObject> pIEnumSnapshots;
518 HRESULT hr = pVss->Query( GUID_NULL,
521 (IVssEnumObject**)(&pIEnumSnapshots) );
523 // If there are no shadow copies, just return
525 errno = b_errno_win32;
529 // Enumerate all shadow copies.
530 VSS_OBJECT_PROP Prop;
531 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
534 // Get the next element
536 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
538 // We reached the end of list
542 // Print the shadow copy (if not filtered out)
543 if (Snap.m_SnapshotSetId == snapshotSetID) {
544 for (int ch='A'-'A';ch<='Z'-'A';ch++) {
545 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
546 wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
551 p_VssFreeSnapshotProperties(&Snap);
556 // Check the status for all selected writers
557 BOOL VSSClientGeneric::CheckWriterStatus()
560 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
562 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
565 // Gather writer status to detect potential errors
566 CComPtr<IVssAsync> pAsync;
568 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
570 errno = b_errno_win32;
574 // Waits for the async operation to finish and checks the result
575 WaitAndCheckForAsyncOperation(pAsync.p);
577 unsigned cWriters = 0;
579 hr = pVss->GetWriterStatusCount(&cWriters);
581 errno = b_errno_win32;
587 // Enumerate each writer
588 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
589 VSS_ID idInstance = GUID_NULL;
590 VSS_ID idWriter= GUID_NULL;
591 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
592 CComBSTR bstrWriterName;
593 HRESULT hrWriterFailure = S_OK;
596 hr = pVss->GetWriterStatus(iWriter,
607 switch(eWriterStatus) {
608 case VSS_WS_FAILED_AT_IDENTIFY:
609 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
610 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
611 case VSS_WS_FAILED_AT_FREEZE:
612 case VSS_WS_FAILED_AT_THAW:
613 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
614 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
615 case VSS_WS_FAILED_AT_PRE_RESTORE:
616 case VSS_WS_FAILED_AT_POST_RESTORE:
618 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
629 /* store text info */
632 bstrncpy(str, "\"", sizeof(str));
633 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
634 bstrncat(str, szBuf, sizeof(str));
635 bstrncat(str, "\", State: 0x", sizeof(str));
636 itoa(eWriterStatus, szBuf, sizeof(szBuf));
637 bstrncat(str, szBuf, sizeof(str));
638 bstrncat(str, " (", sizeof(str));
639 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
640 bstrncat(str, szBuf, sizeof(str));
641 bstrncat(str, ")", sizeof(str));
643 AppendWriterInfo(nState, (const char *)str);
646 hr = pVss->FreeWriterStatus();
649 errno = b_errno_win32;
657 #endif /* WIN32_VSS */