2 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
4 // Copyright transferred from MATRIX-Computer GmbH to
5 // Kern Sibbald by express permission.
7 // Copyright (C) 2005-2006 Kern Sibbald
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // version 2 as amended with additional clauses defined in the
12 // file LICENSE in the main source directory.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // the file LICENSE for additional details.
20 // Author : Thorsten Engel
21 // Created On : Fri May 06 21:44:00 2005
41 #if !defined(ENABLE_NLS)
42 #define setlocale(p, d)
46 // Used for safe string manipulation
50 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
51 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
54 class IXMLDOMDocument;
58 #pragma message("compile VSS for Windows XP")
59 #define VSSClientGeneric VSSClientXP
61 #include "inc/WinXP/vss.h"
62 #include "inc/WinXP/vswriter.h"
63 #include "inc/WinXP/vsbackup.h"
66 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
67 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
69 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
70 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
72 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
76 #pragma message("compile VSS for Windows 2003")
77 #define VSSClientGeneric VSSClient2003
79 #include "inc/Win2003/vss.h"
80 #include "inc/Win2003/vswriter.h"
81 #include "inc/Win2003/vsbackup.h"
84 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
85 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
87 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
88 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
90 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
97 * some helper functions
102 // Append a backslash to the current string
103 inline wstring AppendBackslash(wstring str)
105 if (str.length() == 0)
106 return wstring(L"\\");
107 if (str[str.length() - 1] == L'\\')
109 return str.append(L"\\");
112 // Get the unique volume name for the given path
113 inline wstring GetUniqueVolumeNameForPath(wstring path)
115 if (path.length() <= 0) {
119 // Add the backslash termination, if needed
120 path = AppendBackslash(path);
122 // Get the root path of the volume
123 wchar_t volumeRootPath[MAX_PATH];
124 wchar_t volumeName[MAX_PATH];
125 wchar_t volumeUniqueName[MAX_PATH];
127 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
130 // Get the volume name alias (might be different from the unique volume name in rare cases)
131 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
134 // Get the unique volume name
135 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
138 return volumeUniqueName;
142 // Helper macro for quick treatment of case statements for error codes
143 #define GEN_MERGE(A, B) A##B
144 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
146 #define CHECK_CASE_FOR_CONSTANT(value) \
147 case value: return (GEN_MAKE_W(#value));
150 // Convert a writer status into a string
151 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
153 switch (eWriterStatus) {
154 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
155 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
156 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
157 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
158 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
159 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
160 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
161 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
162 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
163 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
164 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
165 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
166 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
167 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
170 return L"Error or Undefined";
176 VSSClientGeneric::VSSClientGeneric()
178 m_hLib = LoadLibraryA("VSSAPI.DLL");
180 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
181 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
183 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
184 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
191 VSSClientGeneric::~VSSClientGeneric()
197 // Initialize the COM infrastructure and the internal pointers
198 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
200 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
207 if (!m_bCoInitializeCalled) {
208 if (FAILED(CoInitialize(NULL))) {
209 errno = b_errno_win32;
212 m_bCoInitializeCalled = true;
215 // Initialize COM security
216 if (!m_bCoInitializeSecurityCalled) {
218 CoInitializeSecurity(
219 NULL, // Allow *all* VSS writers to communicate back!
220 -1, // Default COM authentication service
221 NULL, // Default COM authorization service
222 NULL, // reserved parameter
223 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
224 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
225 NULL, // Default COM authentication settings
226 EOAC_NONE, // No special options
227 NULL // Reserved parameter
231 errno = b_errno_win32;
234 m_bCoInitializeSecurityCalled = true;
237 // Release the IVssBackupComponents interface
239 m_pVssObject->Release();
243 // Create the internal backup components object
244 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
246 errno = b_errno_win32;
251 if (dwContext != VSS_CTX_BACKUP) {
252 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
254 errno = b_errno_win32;
260 if (!bDuringRestore) {
261 // 1. InitializeForBackup
262 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
264 errno = b_errno_win32;
269 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
271 errno = b_errno_win32;
275 CComPtr<IVssAsync> pAsync1;
276 // 3. GatherWriterMetaData
277 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
279 errno = b_errno_win32;
282 // Waits for the async operation to finish and checks the result
283 WaitAndCheckForAsyncOperation(pAsync1.p);
287 // We are during restore now?
288 m_bDuringRestore = bDuringRestore;
291 m_dwContext = dwContext;
297 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
299 // Wait until the async operation finishes
300 // unfortunately we can't use a timeout here yet.
301 // the interface would allow it on W2k3,
302 // but it is not implemented yet....
306 // Check the result of the asynchronous operation
307 HRESULT hrReturned = S_OK;
309 int timeout = 600; // 10 minutes....
313 if (hrReturned != S_OK)
317 hr = pAsync->QueryStatus(&hrReturned, NULL);
321 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
323 if (hrReturned == VSS_S_ASYNC_FINISHED)
328 // Check if the async operation succeeded...
329 if(hrReturned != VSS_S_ASYNC_FINISHED) {
330 wchar_t *pwszBuffer = NULL;
331 DWORD dwRet = ::FormatMessageW(
332 FORMAT_MESSAGE_ALLOCATE_BUFFER
333 | FORMAT_MESSAGE_FROM_SYSTEM
334 | FORMAT_MESSAGE_IGNORE_INSERTS,
336 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
337 (LPWSTR)&pwszBuffer, 0, NULL);
340 LocalFree(pwszBuffer);
342 errno = b_errno_win32;
349 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
351 /* szDriveLetters contains all drive letters in uppercase */
352 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
353 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
355 if (!m_pVssObject || m_bBackupIsInitialized) {
360 m_uidCurrentSnapshotSet = GUID_NULL;
362 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
364 /* startSnapshotSet */
366 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
368 /* AddToSnapshotSet */
376 CComPtr<IVssAsync> pAsync1;
377 CComPtr<IVssAsync> pAsync2;
380 for (size_t i=0; i < strlen (szDriveLetters); i++) {
381 szDrive[0] = szDriveLetters[i];
382 volume = GetUniqueVolumeNameForPath(szDrive);
383 // store uniquevolumname
384 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
385 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
388 szDriveLetters[i] = tolower (szDriveLetters[i]);
392 /* PrepareForBackup */
393 if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {
397 // Waits for the async operation to finish and checks the result
398 WaitAndCheckForAsyncOperation(pAsync1.p);
400 /* get latest info about writer status */
401 if (!CheckWriterStatus()) {
406 if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {
410 // Waits for the async operation to finish and checks the result
411 WaitAndCheckForAsyncOperation(pAsync2.p);
413 /* query snapshot info */
414 QuerySnapshotSet(m_uidCurrentSnapshotSet);
416 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
418 m_bBackupIsInitialized = true;
423 BOOL VSSClientGeneric::CloseBackup()
429 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
430 CComPtr<IVssAsync> pAsync;
432 SetVSSPathConvert(NULL, NULL);
434 m_bBackupIsInitialized = false;
436 if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
437 // Waits for the async operation to finish and checks the result
438 WaitAndCheckForAsyncOperation(pAsync.p);
441 errno = b_errno_win32;
445 /* get latest info about writer status */
448 if (m_uidCurrentSnapshotSet != GUID_NULL) {
449 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
452 pVss->DeleteSnapshots(
453 m_uidCurrentSnapshotSet,
454 VSS_OBJECT_SNAPSHOT_SET,
457 &idNonDeletedSnapshotID);
459 m_uidCurrentSnapshotSet = GUID_NULL;
466 // Call CoUninitialize if the CoInitialize was performed sucesfully
467 if (m_bCoInitializeCalled) {
469 m_bCoInitializeCalled = false;
475 // Query all the shadow copies in the given set
476 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
478 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
483 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
485 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
490 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
492 // Get list all shadow copies.
493 CComPtr<IVssEnumObject> pIEnumSnapshots;
494 HRESULT hr = pVss->Query( GUID_NULL,
497 (IVssEnumObject**)(&pIEnumSnapshots) );
499 // If there are no shadow copies, just return
501 errno = b_errno_win32;
505 // Enumerate all shadow copies.
506 VSS_OBJECT_PROP Prop;
507 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
510 // Get the next element
512 hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
514 // We reached the end of list
518 // Print the shadow copy (if not filtered out)
519 if (Snap.m_SnapshotSetId == snapshotSetID) {
520 for (char ch='A'-'A';ch<='Z'-'A';ch++) {
521 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
522 wcsncpy (m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
527 p_VssFreeSnapshotProperties(&Snap);
532 // Check the status for all selected writers
533 BOOL VSSClientGeneric::CheckWriterStatus()
536 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
538 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
541 // Gather writer status to detect potential errors
542 CComPtr<IVssAsync> pAsync;
544 HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
546 errno = b_errno_win32;
550 // Waits for the async operation to finish and checks the result
551 WaitAndCheckForAsyncOperation(pAsync.p);
553 unsigned cWriters = 0;
555 hr = pVss->GetWriterStatusCount(&cWriters);
557 errno = b_errno_win32;
563 // Enumerate each writer
564 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
565 VSS_ID idInstance = GUID_NULL;
566 VSS_ID idWriter= GUID_NULL;
567 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
568 CComBSTR bstrWriterName;
569 HRESULT hrWriterFailure = S_OK;
572 hr = pVss->GetWriterStatus(iWriter,
583 switch(eWriterStatus) {
584 case VSS_WS_FAILED_AT_IDENTIFY:
585 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
586 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
587 case VSS_WS_FAILED_AT_FREEZE:
588 case VSS_WS_FAILED_AT_THAW:
589 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
590 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
591 case VSS_WS_FAILED_AT_PRE_RESTORE:
592 case VSS_WS_FAILED_AT_POST_RESTORE:
594 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
605 /* store text info */
609 wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
611 strcat(str, "\", State: 0x");
612 itoa(eWriterStatus, szBuf, sizeof(szBuf));
615 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
619 AppendWriterInfo(nState, (const char *)str);
622 hr = pVss->FreeWriterStatus();
625 errno = b_errno_win32;
633 #endif /* WIN32_VSS */