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
27 #include <sys/types.h>
59 #include <atlcomcli.h>
62 // Used for safe string manipulation
65 #include "../../lib/winapi.h"
68 #pragma message("compile VSS for Windows XP")
69 #define VSSClientGeneric VSSClientXP
70 // wait is not available under XP...
73 #include "vss/inc/WinXP/vss.h"
74 #include "vss/inc/WinXP/vswriter.h"
75 #include "vss/inc/WinXP/vsbackup.h"
78 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
79 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
81 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
82 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
84 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
88 #pragma message("compile VSS for Windows 2003")
89 #define VSSClientGeneric VSSClient2003
90 // wait x ms for a VSS asynchronous operation (-1 = infinite)
91 // unfortunately, it doesn't work, so do not set timeout
94 #include "vss/inc/Win2003/vss.h"
95 #include "vss/inc/Win2003/vswriter.h"
96 #include "vss/inc/Win2003/vsbackup.h"
99 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
100 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
102 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
103 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
105 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
112 * some helper functions
117 // Append a backslash to the current string
118 inline wstring AppendBackslash(wstring str)
120 if (str.length() == 0)
121 return wstring(L"\\");
122 if (str[str.length() - 1] == L'\\')
124 return str.append(L"\\");
127 // Get the unique volume name for the given path
128 inline wstring GetUniqueVolumeNameForPath(wstring path)
130 _ASSERTE(path.length() > 0);
132 // Add the backslash termination, if needed
133 path = AppendBackslash(path);
135 // Get the root path of the volume
136 WCHAR volumeRootPath[MAX_PATH];
137 WCHAR volumeName[MAX_PATH];
138 WCHAR volumeUniqueName[MAX_PATH];
140 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
143 // Get the volume name alias (might be different from the unique volume name in rare cases)
144 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
147 // Get the unique volume name
148 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
151 return volumeUniqueName;
155 // Helper macro for quick treatment of case statements for error codes
156 #define GEN_MERGE(A, B) A##B
157 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
159 #define CHECK_CASE_FOR_CONSTANT(value) \
160 case value: return wstring(GEN_MAKE_W(#value));
163 // Convert a writer status into a string
164 inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
166 switch (eWriterStatus) {
167 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
168 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
169 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
170 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
171 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
172 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
173 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
174 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
175 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
176 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
177 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
178 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
179 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
180 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
183 return wstring(L"Error or Undefined");
189 VSSClientGeneric::VSSClientGeneric()
191 m_hLib = LoadLibraryA("VSSAPI.DLL");
193 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
194 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
196 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
197 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
204 VSSClientGeneric::~VSSClientGeneric()
210 // Initialize the COM infrastructure and the internal pointers
211 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
213 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
220 if (!m_bCoInitializeCalled) {
221 if (FAILED(CoInitialize(NULL))) {
222 errno = b_errno_win32;
225 m_bCoInitializeCalled = true;
228 // Initialize COM security
229 if (!m_bCoInitializeSecurityCalled) {
231 CoInitializeSecurity(
232 NULL, // Allow *all* VSS writers to communicate back!
233 -1, // Default COM authentication service
234 NULL, // Default COM authorization service
235 NULL, // reserved parameter
236 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
237 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
238 NULL, // Default COM authentication settings
239 EOAC_NONE, // No special options
240 NULL // Reserved parameter
244 errno = b_errno_win32;
247 m_bCoInitializeSecurityCalled = true;
250 // Release the IVssBackupComponents interface
252 m_pVssObject->Release();
256 // Create the internal backup components object
257 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
259 errno = b_errno_win32;
264 if (dwContext != VSS_CTX_BACKUP) {
265 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
267 errno = b_errno_win32;
273 // We are during restore now?
274 m_bDuringRestore = bDuringRestore;
277 m_dwContext = dwContext;
283 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
285 // Wait until the async operation finishes
286 // unfortunately we can't use a timeout here yet.
287 // the interface would allow it on W2k3, but it is not implemented yet....
288 HRESULT hr = pAsync->Wait(VSS_TIMEOUT);
290 // Check the result of the asynchronous operation
291 HRESULT hrReturned = S_OK;
292 hr = pAsync->QueryStatus(&hrReturned, NULL);
294 // Check if the async operation succeeded...
295 if(FAILED(hrReturned)) {
296 PWCHAR pwszBuffer = NULL;
297 DWORD dwRet = ::FormatMessageW(
298 FORMAT_MESSAGE_ALLOCATE_BUFFER
299 | FORMAT_MESSAGE_FROM_SYSTEM
300 | FORMAT_MESSAGE_IGNORE_INSERTS,
302 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
303 (LPWSTR)&pwszBuffer, 0, NULL);
305 // No message found for this error. Just return <Unknown>
307 LocalFree(pwszBuffer);
312 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
314 /* szDriveLetters contains all drive letters in uppercase */
315 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
316 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
318 if (!m_pVssObject || m_bBackupIsInitialized) {
323 m_uidCurrentSnapshotSet = GUID_NULL;
325 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
327 // 1. InitializeForBackup
328 HRESULT hr = pVss->InitializeForBackup();
330 errno = b_errno_win32;
335 hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
337 errno = b_errno_win32;
341 CComPtr<IVssAsync> pAsync1;
342 CComPtr<IVssAsync> pAsync2;
343 CComPtr<IVssAsync> pAsync3;
346 // 3. GatherWriterMetaData
347 hr = pVss->GatherWriterMetadata(&pAsync3);
349 errno = b_errno_win32;
353 // Waits for the async operation to finish and checks the result
354 WaitAndCheckForAsyncOperation(pAsync3);
358 // 4. startSnapshotSet
360 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
362 // 4. AddToSnapshotSet
370 for (size_t i=0; i < strlen (szDriveLetters); i++) {
371 szDrive[0] = szDriveLetters[i];
372 volume = GetUniqueVolumeNameForPath(szDrive);
373 // store uniquevolumname
374 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
375 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
377 szDriveLetters[i] = tolower (szDriveLetters[i]);
380 // 5. PrepareForBackup
381 pVss->PrepareForBackup(&pAsync1);
383 // Waits for the async operation to finish and checks the result
384 WaitAndCheckForAsyncOperation(pAsync1);
387 pVss->DoSnapshotSet(&pAsync2);
389 // Waits for the async operation to finish and checks the result
390 WaitAndCheckForAsyncOperation(pAsync2);
392 /* query snapshot info */
393 QuerySnapshotSet(m_uidCurrentSnapshotSet);
395 m_bBackupIsInitialized = true;
400 BOOL VSSClientGeneric::CloseBackup()
406 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
407 CComPtr<IVssAsync> pAsync;
409 m_bBackupIsInitialized = false;
411 if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
412 // Waits for the async operation to finish and checks the result
413 WaitAndCheckForAsyncOperation(pAsync);
416 errno = b_errno_win32;
420 if (m_uidCurrentSnapshotSet != GUID_NULL) {
421 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
424 pVss->DeleteSnapshots(
425 m_uidCurrentSnapshotSet,
426 VSS_OBJECT_SNAPSHOT_SET,
429 &idNonDeletedSnapshotID);
431 m_uidCurrentSnapshotSet = GUID_NULL;
438 // Call CoUninitialize if the CoInitialize was performed sucesfully
439 if (m_bCoInitializeCalled) {
441 m_bCoInitializeCalled = false;
447 // Query all the shadow copies in the given set
448 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
450 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
455 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
457 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
462 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
464 // Get list all shadow copies.
465 CComPtr<IVssEnumObject> pIEnumSnapshots;
466 HRESULT hr = pVss->Query( GUID_NULL,
471 // If there are no shadow copies, just return
473 errno = b_errno_win32;
477 // Enumerate all shadow copies.
478 VSS_OBJECT_PROP Prop;
479 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
482 // Get the next element
484 hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
486 // We reached the end of list
490 // Print the shadow copy (if not filtered out)
491 if (Snap.m_SnapshotSetId == snapshotSetID) {
492 for (char ch='A'-'A';ch<='Z'-'A';ch++) {
493 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
494 WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);
499 p_VssFreeSnapshotProperties(&Snap);
504 // Check the status for all selected writers
505 BOOL VSSClientGeneric::CheckWriterStatus()
507 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
508 vector<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
509 vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;
511 pVWriterStates->clear();
512 pVWriterInfo->clear();
514 // Gather writer status to detect potential errors
515 CComPtr<IVssAsync> pAsync;
517 HRESULT hr = pVss->GatherWriterStatus(&pAsync);
519 errno = b_errno_win32;
523 // Waits for the async operation to finish and checks the result
524 WaitAndCheckForAsyncOperation(pAsync);
526 unsigned cWriters = 0;
528 hr = pVss->GetWriterStatusCount(&cWriters);
530 errno = b_errno_win32;
534 // Enumerate each writer
535 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
536 VSS_ID idInstance = GUID_NULL;
537 VSS_ID idWriter= GUID_NULL;
538 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
539 CComBSTR bstrWriterName;
540 HRESULT hrWriterFailure = S_OK;
543 hr = pVss->GetWriterStatus(iWriter,
553 // If the writer is in non-stable state, break
554 switch(eWriterStatus) {
555 case VSS_WS_FAILED_AT_IDENTIFY:
556 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
557 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
558 case VSS_WS_FAILED_AT_FREEZE:
559 case VSS_WS_FAILED_AT_THAW:
560 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
561 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
562 case VSS_WS_FAILED_AT_PRE_RESTORE:
563 case VSS_WS_FAILED_AT_POST_RESTORE:
565 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
568 pVWriterStates->push_back(-1);
573 pVWriterStates->push_back(1);
578 osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")";
580 pVWriterInfo->push_back(osf.str());