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 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
66 #pragma message("compile VSS for Windows XP")
67 #define VSSClientGeneric VSSClientXP
69 #include "vss/inc/WinXP/vss.h"
70 #include "vss/inc/WinXP/vswriter.h"
71 #include "vss/inc/WinXP/vsbackup.h"
74 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
75 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
77 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
78 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
80 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
84 #pragma message("compile VSS for Windows 2003")
85 #define VSSClientGeneric VSSClient2003
87 #include "vss/inc/Win2003/vss.h"
88 #include "vss/inc/Win2003/vswriter.h"
89 #include "vss/inc/Win2003/vsbackup.h"
92 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
93 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
95 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
96 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
98 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
105 * some helper functions
110 // Append a backslash to the current string
111 inline wstring AppendBackslash(wstring str)
113 if (str.length() == 0)
114 return wstring(L"\\");
115 if (str[str.length() - 1] == L'\\')
117 return str.append(L"\\");
120 // Get the unique volume name for the given path
121 inline wstring GetUniqueVolumeNameForPath(wstring path)
123 _ASSERTE(path.length() > 0);
125 // Add the backslash termination, if needed
126 path = AppendBackslash(path);
128 // Get the root path of the volume
129 WCHAR volumeRootPath[MAX_PATH];
130 WCHAR volumeName[MAX_PATH];
131 WCHAR volumeUniqueName[MAX_PATH];
133 if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
136 // Get the volume name alias (might be different from the unique volume name in rare cases)
137 if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
140 // Get the unique volume name
141 if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
144 return volumeUniqueName;
148 // Helper macro for quick treatment of case statements for error codes
149 #define GEN_MERGE(A, B) A##B
150 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
152 #define CHECK_CASE_FOR_CONSTANT(value) \
153 case value: return wstring(GEN_MAKE_W(#value));
156 // Convert a writer status into a string
157 inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
159 switch (eWriterStatus) {
160 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
161 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
162 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
163 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
164 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
165 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
166 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
167 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
168 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
169 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
170 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
171 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
172 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
173 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
176 return wstring(L"Error or Undefined");
182 VSSClientGeneric::VSSClientGeneric()
184 m_hLib = LoadLibraryA("VSSAPI.DLL");
186 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
187 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
189 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
190 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
197 VSSClientGeneric::~VSSClientGeneric()
203 // Initialize the COM infrastructure and the internal pointers
204 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
206 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
213 if (!m_bCoInitializeCalled) {
214 if (FAILED(CoInitialize(NULL))) {
215 errno = b_errno_win32;
218 m_bCoInitializeCalled = true;
221 // Initialize COM security
222 if (!m_bCoInitializeSecurityCalled) {
224 CoInitializeSecurity(
225 NULL, // Allow *all* VSS writers to communicate back!
226 -1, // Default COM authentication service
227 NULL, // Default COM authorization service
228 NULL, // reserved parameter
229 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
230 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
231 NULL, // Default COM authentication settings
232 EOAC_NONE, // No special options
233 NULL // Reserved parameter
237 errno = b_errno_win32;
240 m_bCoInitializeSecurityCalled = true;
243 // Release the IVssBackupComponents interface
245 m_pVssObject->Release();
249 // Create the internal backup components object
250 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
252 errno = b_errno_win32;
257 if (dwContext != VSS_CTX_BACKUP) {
258 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
260 errno = b_errno_win32;
266 // We are during restore now?
267 m_bDuringRestore = bDuringRestore;
270 m_dwContext = dwContext;
276 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
278 // Wait until the async operation finishes
279 HRESULT hr = pAsync->Wait();
281 // Check the result of the asynchronous operation
282 HRESULT hrReturned = S_OK;
283 hr = pAsync->QueryStatus(&hrReturned, NULL);
285 // Check if the async operation succeeded...
286 if(FAILED(hrReturned)) {
287 PWCHAR pwszBuffer = NULL;
288 DWORD dwRet = ::FormatMessageW(
289 FORMAT_MESSAGE_ALLOCATE_BUFFER
290 | FORMAT_MESSAGE_FROM_SYSTEM
291 | FORMAT_MESSAGE_IGNORE_INSERTS,
293 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
294 (LPWSTR)&pwszBuffer, 0, NULL);
296 // No message found for this error. Just return <Unknown>
298 LocalFree(pwszBuffer);
303 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
305 /* szDriveLetters contains all drive letters in uppercase */
306 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
307 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
309 if (!m_pVssObject || m_bBackupIsInitialized) {
314 m_uidCurrentSnapshotSet = GUID_NULL;
316 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
318 // 1. InitializeForBackup
319 HRESULT hr = pVss->InitializeForBackup();
321 errno = b_errno_win32;
326 hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
328 errno = b_errno_win32;
332 CComPtr<IVssAsync> pAsync1;
333 CComPtr<IVssAsync> pAsync2;
334 CComPtr<IVssAsync> pAsync3;
337 // 3. GatherWriterMetaData
338 hr = pVss->GatherWriterMetadata(&pAsync3);
340 errno = b_errno_win32;
344 // Waits for the async operation to finish and checks the result
345 WaitAndCheckForAsyncOperation(pAsync3);
349 // 4. startSnapshotSet
351 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
353 // 4. AddToSnapshotSet
361 for (size_t i=0; i < strlen (szDriveLetters); i++) {
362 szDrive[0] = szDriveLetters[i];
363 volume = GetUniqueVolumeNameForPath(szDrive);
364 // store uniquevolumname
365 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
366 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
368 szDriveLetters[i] = tolower (szDriveLetters[i]);
371 // 5. PrepareForBackup
372 pVss->PrepareForBackup(&pAsync1);
374 // Waits for the async operation to finish and checks the result
375 WaitAndCheckForAsyncOperation(pAsync1);
378 pVss->DoSnapshotSet(&pAsync2);
380 // Waits for the async operation to finish and checks the result
381 WaitAndCheckForAsyncOperation(pAsync2);
383 /* query snapshot info */
384 QuerySnapshotSet(m_uidCurrentSnapshotSet);
386 m_bBackupIsInitialized = true;
391 BOOL VSSClientGeneric::CloseBackup()
397 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
398 CComPtr<IVssAsync> pAsync;
400 m_bBackupIsInitialized = false;
402 if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
403 // Waits for the async operation to finish and checks the result
404 WaitAndCheckForAsyncOperation(pAsync);
407 errno = b_errno_win32;
411 if (m_uidCurrentSnapshotSet != GUID_NULL) {
412 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
415 pVss->DeleteSnapshots(
416 m_uidCurrentSnapshotSet,
417 VSS_OBJECT_SNAPSHOT_SET,
420 &idNonDeletedSnapshotID);
422 m_uidCurrentSnapshotSet = GUID_NULL;
429 // Call CoUninitialize if the CoInitialize was performed sucesfully
430 if (m_bCoInitializeCalled) {
432 m_bCoInitializeCalled = false;
438 // Query all the shadow copies in the given set
439 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
441 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
446 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
448 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
453 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
455 // Get list all shadow copies.
456 CComPtr<IVssEnumObject> pIEnumSnapshots;
457 HRESULT hr = pVss->Query( GUID_NULL,
462 // If there are no shadow copies, just return
464 errno = b_errno_win32;
468 // Enumerate all shadow copies.
469 VSS_OBJECT_PROP Prop;
470 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
473 // Get the next element
475 hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
477 // We reached the end of list
481 // Print the shadow copy (if not filtered out)
482 if (Snap.m_SnapshotSetId == snapshotSetID) {
483 for (char ch='A'-'A';ch<='Z'-'A';ch++) {
484 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
485 WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);
490 p_VssFreeSnapshotProperties(&Snap);
495 // Check the status for all selected writers
496 BOOL VSSClientGeneric::CheckWriterStatus()
498 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
499 vector<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
500 vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;
502 pVWriterStates->clear();
503 pVWriterInfo->clear();
505 // Gather writer status to detect potential errors
506 CComPtr<IVssAsync> pAsync;
508 HRESULT hr = pVss->GatherWriterStatus(&pAsync);
510 errno = b_errno_win32;
514 // Waits for the async operation to finish and checks the result
515 WaitAndCheckForAsyncOperation(pAsync);
517 unsigned cWriters = 0;
519 hr = pVss->GetWriterStatusCount(&cWriters);
521 errno = b_errno_win32;
525 // Enumerate each writer
526 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
527 VSS_ID idInstance = GUID_NULL;
528 VSS_ID idWriter= GUID_NULL;
529 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
530 CComBSTR bstrWriterName;
531 HRESULT hrWriterFailure = S_OK;
534 hr = pVss->GetWriterStatus(iWriter,
544 // If the writer is in non-stable state, break
545 switch(eWriterStatus) {
546 case VSS_WS_FAILED_AT_IDENTIFY:
547 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
548 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
549 case VSS_WS_FAILED_AT_FREEZE:
550 case VSS_WS_FAILED_AT_THAW:
551 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
552 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
553 case VSS_WS_FAILED_AT_PRE_RESTORE:
554 case VSS_WS_FAILED_AT_POST_RESTORE:
556 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
559 pVWriterStates->push_back(-1);
564 pVWriterStates->push_back(1);
569 osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")";
571 pVWriterInfo->push_back(osf.str());