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) 2004-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 as
11 // published by the Free Software Foundation; either version 2 of
12 // the License, or (at your option) any later version.
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 GNU
17 // General Public License for more details.
19 // You should have received a copy of the GNU General Public
20 // License along with this program; if not, write to the Free
21 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 // MA 02111-1307, USA.
24 // Author : Thorsten Engel
25 // Created On : Fri May 06 21:44:00 2006
31 #include <sys/types.h>
63 #include <atlcomcli.h>
66 // Used for safe string manipulation
70 #pragma message("compile VSS for Windows XP")
71 #define VSSClientGeneric VSSClientXP
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
91 #include "vss/inc/Win2003/vss.h"
92 #include "vss/inc/Win2003/vswriter.h"
93 #include "vss/inc/Win2003/vsbackup.h"
96 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
97 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
99 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
100 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
102 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
109 * some helper functions
114 // Append a backslash to the current string
115 inline wstring AppendBackslash(wstring str)
117 if (str.length() == 0)
118 return wstring(L"\\");
119 if (str[str.length() - 1] == L'\\')
121 return str.append(L"\\");
124 // Get the unique volume name for the given path
125 inline wstring GetUniqueVolumeNameForPath(wstring path)
127 _ASSERTE(path.length() > 0);
129 // Add the backslash termination, if needed
130 path = AppendBackslash(path);
132 // Get the root path of the volume
133 WCHAR volumeRootPath[MAX_PATH];
134 WCHAR volumeName[MAX_PATH];
135 WCHAR volumeUniqueName[MAX_PATH];
137 if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
140 // Get the volume name alias (might be different from the unique volume name in rare cases)
141 if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
144 // Get the unique volume name
145 if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
148 return volumeUniqueName;
152 // Helper macro for quick treatment of case statements for error codes
153 #define GEN_MERGE(A, B) A##B
154 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
156 #define CHECK_CASE_FOR_CONSTANT(value) \
157 case value: return wstring(GEN_MAKE_W(#value));
160 // Convert a writer status into a string
161 inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
163 switch (eWriterStatus)
165 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
166 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
167 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
168 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
169 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
170 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
171 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
172 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
173 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
174 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
175 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
176 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
177 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
178 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
181 return wstring(L"Undefined");
187 VSSClientGeneric::VSSClientGeneric()
189 m_hLib = LoadLibraryA("VSSAPI.DLL");
191 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
192 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
194 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
195 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
202 VSSClientGeneric::~VSSClientGeneric()
208 // Initialize the COM infrastructure and the internal pointers
209 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
211 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
216 if (!m_bCoInitializeCalled) {
217 if (FAILED(CoInitialize(NULL)))
220 m_bCoInitializeCalled = true;
222 // Initialize COM security
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
240 // Release the IVssBackupComponents interface
242 m_pVssObject->Release();
246 // Create the internal backup components object
247 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
252 if (dwContext != VSS_CTX_BACKUP) {
253 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
259 // We are during restore now?
260 m_bDuringRestore = bDuringRestore;
263 m_dwContext = dwContext;
269 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
271 // Wait until the async operation finishes
272 HRESULT hr = pAsync->Wait();
274 // Check the result of the asynchronous operation
275 HRESULT hrReturned = S_OK;
276 hr = pAsync->QueryStatus(&hrReturned, NULL);
278 // Check if the async operation succeeded...
279 if(FAILED(hrReturned))
281 PWCHAR pwszBuffer = NULL;
282 DWORD dwRet = ::FormatMessageW(
283 FORMAT_MESSAGE_ALLOCATE_BUFFER
284 | FORMAT_MESSAGE_FROM_SYSTEM
285 | FORMAT_MESSAGE_IGNORE_INSERTS,
287 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
288 (LPWSTR)&pwszBuffer, 0, NULL);
290 // No message found for this error. Just return <Unknown>
293 // Convert the message into wstring
295 LocalFree(pwszBuffer);
300 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
302 /* szDriveLetters contains all drive letters in uppercase */
303 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
304 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
306 if (!m_pVssObject || m_bBackupIsInitialized)
309 m_uidCurrentSnapshotSet = GUID_NULL;
311 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
313 // 1. InitializeForBackup
314 HRESULT hr = pVss->InitializeForBackup();
319 hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
323 CComPtr<IVssAsync> pAsync1;
324 CComPtr<IVssAsync> pAsync2;
325 CComPtr<IVssAsync> pAsync3;
328 // 3. GatherWriterMetaData
329 hr = pVss->GatherWriterMetadata(&pAsync3);
333 // Waits for the async operation to finish and checks the result
334 WaitAndCheckForAsyncOperation(pAsync3);
338 // 4. startSnapshotSet
340 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
342 // 4. AddToSnapshotSet
350 for (size_t i=0; i < strlen (szDriveLetters); i++) {
351 szDrive[0] = szDriveLetters[i];
352 volume = GetUniqueVolumeNameForPath(szDrive);
353 // store uniquevolumname
354 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
355 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
357 szDriveLetters[i] = tolower (szDriveLetters[i]);
360 // 5. PrepareForBackup
361 pVss->PrepareForBackup(&pAsync1);
363 // Waits for the async operation to finish and checks the result
364 WaitAndCheckForAsyncOperation(pAsync1);
367 pVss->DoSnapshotSet(&pAsync2);
369 // Waits for the async operation to finish and checks the result
370 WaitAndCheckForAsyncOperation(pAsync2);
372 /* query snapshot info */
373 QuerySnapshotSet(m_uidCurrentSnapshotSet);
375 m_bBackupIsInitialized = true;
380 BOOL VSSClientGeneric::CloseBackup()
386 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
387 CComPtr<IVssAsync> pAsync;
389 m_bBackupIsInitialized = false;
391 if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
392 // Waits for the async operation to finish and checks the result
393 WaitAndCheckForAsyncOperation(pAsync);
400 if (m_uidCurrentSnapshotSet != GUID_NULL) {
401 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
404 pVss->DeleteSnapshots(
405 m_uidCurrentSnapshotSet,
406 VSS_OBJECT_SNAPSHOT_SET,
409 &idNonDeletedSnapshotID);
411 m_uidCurrentSnapshotSet = GUID_NULL;
421 // Query all the shadow copies in the given set
422 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
424 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
427 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
429 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL)
432 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
434 // Get list all shadow copies.
435 CComPtr<IVssEnumObject> pIEnumSnapshots;
436 HRESULT hr = pVss->Query( GUID_NULL,
441 // If there are no shadow copies, just return
446 // Enumerate all shadow copies.
447 VSS_OBJECT_PROP Prop;
448 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
452 // Get the next element
454 hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
456 // We reached the end of list
460 // Print the shadow copy (if not filtered out)
461 if (Snap.m_SnapshotSetId == snapshotSetID) {
462 for (char ch='A'-'A';ch<='Z'-'A';ch++) {
463 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
464 WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);
469 p_VssFreeSnapshotProperties(&Snap);
473 // Check the status for all selected writers
474 BOOL VSSClientGeneric::CheckWriterStatus()
476 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
477 vector<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
478 vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;
480 pVWriterStates->clear();
481 pVWriterInfo->clear();
483 // Gather writer status to detect potential errors
484 CComPtr<IVssAsync> pAsync;
486 HRESULT hr = pVss->GatherWriterStatus(&pAsync);
490 // Waits for the async operation to finish and checks the result
491 WaitAndCheckForAsyncOperation(pAsync);
493 unsigned cWriters = 0;
495 hr = pVss->GetWriterStatusCount(&cWriters);
499 // Enumerate each writer
500 for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
502 VSS_ID idInstance = GUID_NULL;
503 VSS_ID idWriter= GUID_NULL;
504 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
505 CComBSTR bstrWriterName;
506 HRESULT hrWriterFailure = S_OK;
509 hr = pVss->GetWriterStatus(iWriter,
518 // If the writer is in non-stable state, break
519 switch(eWriterStatus)
521 case VSS_WS_FAILED_AT_IDENTIFY:
522 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
523 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
524 case VSS_WS_FAILED_AT_FREEZE:
525 case VSS_WS_FAILED_AT_THAW:
526 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
527 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
528 case VSS_WS_FAILED_AT_PRE_RESTORE:
529 case VSS_WS_FAILED_AT_POST_RESTORE:
531 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
534 pVWriterStates->push_back(-1);
539 pVWriterStates->push_back(1);
544 osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")";
546 pVWriterInfo->push_back(osf.str());