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
29 #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
71 #include "vss/inc/WinXP/vss.h"
72 #include "vss/inc/WinXP/vswriter.h"
73 #include "vss/inc/WinXP/vsbackup.h"
76 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
77 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
79 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
80 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
82 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
86 #pragma message("compile VSS for Windows 2003")
87 #define VSSClientGeneric VSSClient2003
89 #include "vss/inc/Win2003/vss.h"
90 #include "vss/inc/Win2003/vswriter.h"
91 #include "vss/inc/Win2003/vsbackup.h"
94 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
95 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
97 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
98 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
100 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
107 * some helper functions
112 // Append a backslash to the current string
113 inline wstring AppendBackslash(wstring str)
115 if (str.length() == 0)
116 return wstring(L"\\");
117 if (str[str.length() - 1] == L'\\')
119 return str.append(L"\\");
122 // Get the unique volume name for the given path
123 inline wstring GetUniqueVolumeNameForPath(wstring path)
125 _ASSERTE(path.length() > 0);
127 // Add the backslash termination, if needed
128 path = AppendBackslash(path);
130 // Get the root path of the volume
131 WCHAR volumeRootPath[MAX_PATH];
132 WCHAR volumeName[MAX_PATH];
133 WCHAR volumeUniqueName[MAX_PATH];
135 if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
138 // Get the volume name alias (might be different from the unique volume name in rare cases)
139 if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
142 // Get the unique volume name
143 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
146 return volumeUniqueName;
150 // Helper macro for quick treatment of case statements for error codes
151 #define GEN_MERGE(A, B) A##B
152 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
154 #define CHECK_CASE_FOR_CONSTANT(value) \
155 case value: return (GEN_MAKE_W(#value));
158 // Convert a writer status into a string
159 inline const WCHAR* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
161 switch (eWriterStatus) {
162 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
163 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
164 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
165 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
166 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
167 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
168 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
169 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
170 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
171 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
172 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
173 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
174 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
175 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
178 return L"Error or Undefined";
184 VSSClientGeneric::VSSClientGeneric()
186 m_hLib = LoadLibraryA("VSSAPI.DLL");
188 p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
189 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
191 p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
192 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
199 VSSClientGeneric::~VSSClientGeneric()
205 // Initialize the COM infrastructure and the internal pointers
206 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
208 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
215 if (!m_bCoInitializeCalled) {
216 if (FAILED(CoInitialize(NULL))) {
217 errno = b_errno_win32;
220 m_bCoInitializeCalled = true;
223 // Initialize COM security
224 if (!m_bCoInitializeSecurityCalled) {
226 CoInitializeSecurity(
227 NULL, // Allow *all* VSS writers to communicate back!
228 -1, // Default COM authentication service
229 NULL, // Default COM authorization service
230 NULL, // reserved parameter
231 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
232 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
233 NULL, // Default COM authentication settings
234 EOAC_NONE, // No special options
235 NULL // Reserved parameter
239 errno = b_errno_win32;
242 m_bCoInitializeSecurityCalled = true;
245 // Release the IVssBackupComponents interface
247 m_pVssObject->Release();
251 // Create the internal backup components object
252 hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
254 errno = b_errno_win32;
259 if (dwContext != VSS_CTX_BACKUP) {
260 hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
262 errno = b_errno_win32;
268 if (!bDuringRestore) {
269 // 1. InitializeForBackup
270 hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
272 errno = b_errno_win32;
277 hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
279 errno = b_errno_win32;
283 CComPtr<IVssAsync> pAsync1;
284 // 3. GatherWriterMetaData
285 hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1);
287 errno = b_errno_win32;
290 // Waits for the async operation to finish and checks the result
291 WaitAndCheckForAsyncOperation(pAsync1);
295 // We are during restore now?
296 m_bDuringRestore = bDuringRestore;
299 m_dwContext = dwContext;
305 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
307 // Wait until the async operation finishes
308 // unfortunately we can't use a timeout here yet.
309 // the interface would allow it on W2k3,
310 // but it is not implemented yet....
314 // Check the result of the asynchronous operation
315 HRESULT hrReturned = S_OK;
317 int timeout = 600; // 10 minutes....
321 if (hrReturned != S_OK)
325 hr = pAsync->QueryStatus(&hrReturned, NULL);
329 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
331 if (hrReturned == VSS_S_ASYNC_FINISHED)
336 // Check if the async operation succeeded...
337 if(hrReturned != VSS_S_ASYNC_FINISHED) {
338 PWCHAR pwszBuffer = NULL;
339 DWORD dwRet = ::FormatMessageW(
340 FORMAT_MESSAGE_ALLOCATE_BUFFER
341 | FORMAT_MESSAGE_FROM_SYSTEM
342 | FORMAT_MESSAGE_IGNORE_INSERTS,
344 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
345 (LPWSTR)&pwszBuffer, 0, NULL);
348 LocalFree(pwszBuffer);
350 errno = b_errno_win32;
357 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
359 /* szDriveLetters contains all drive letters in uppercase */
360 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
361 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
363 if (!m_pVssObject || m_bBackupIsInitialized) {
368 m_uidCurrentSnapshotSet = GUID_NULL;
370 IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
372 /* startSnapshotSet */
374 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
376 /* AddToSnapshotSet */
384 CComPtr<IVssAsync> pAsync1;
385 CComPtr<IVssAsync> pAsync2;
388 for (size_t i=0; i < strlen (szDriveLetters); i++) {
389 szDrive[0] = szDriveLetters[i];
390 volume = GetUniqueVolumeNameForPath(szDrive);
391 // store uniquevolumname
392 if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
393 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
396 szDriveLetters[i] = tolower (szDriveLetters[i]);
400 /* PrepareForBackup */
401 if (FAILED(pVss->PrepareForBackup(&pAsync1))) {
405 // Waits for the async operation to finish and checks the result
406 WaitAndCheckForAsyncOperation(pAsync1);
408 /* get latest info about writer status */
409 if (!CheckWriterStatus()) {
414 if (FAILED(pVss->DoSnapshotSet(&pAsync2))) {
418 // Waits for the async operation to finish and checks the result
419 WaitAndCheckForAsyncOperation(pAsync2);
421 /* query snapshot info */
422 QuerySnapshotSet(m_uidCurrentSnapshotSet);
424 m_bBackupIsInitialized = true;
429 BOOL VSSClientGeneric::CloseBackup()
435 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
436 CComPtr<IVssAsync> pAsync;
438 m_bBackupIsInitialized = false;
440 if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
441 // Waits for the async operation to finish and checks the result
442 WaitAndCheckForAsyncOperation(pAsync);
445 errno = b_errno_win32;
449 /* get latest info about writer status */
452 if (m_uidCurrentSnapshotSet != GUID_NULL) {
453 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
456 pVss->DeleteSnapshots(
457 m_uidCurrentSnapshotSet,
458 VSS_OBJECT_SNAPSHOT_SET,
461 &idNonDeletedSnapshotID);
463 m_uidCurrentSnapshotSet = GUID_NULL;
470 // Call CoUninitialize if the CoInitialize was performed sucesfully
471 if (m_bCoInitializeCalled) {
473 m_bCoInitializeCalled = false;
479 // Query all the shadow copies in the given set
480 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
482 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
487 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
489 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
494 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
496 // Get list all shadow copies.
497 CComPtr<IVssEnumObject> pIEnumSnapshots;
498 HRESULT hr = pVss->Query( GUID_NULL,
503 // If there are no shadow copies, just return
505 errno = b_errno_win32;
509 // Enumerate all shadow copies.
510 VSS_OBJECT_PROP Prop;
511 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
514 // Get the next element
516 hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
518 // We reached the end of list
522 // Print the shadow copy (if not filtered out)
523 if (Snap.m_SnapshotSetId == snapshotSetID) {
524 for (char ch='A'-'A';ch<='Z'-'A';ch++) {
525 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
526 wcsncpy (m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);
531 p_VssFreeSnapshotProperties(&Snap);
536 // Check the status for all selected writers
537 BOOL VSSClientGeneric::CheckWriterStatus()
540 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
542 IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
545 // Gather writer status to detect potential errors
546 CComPtr<IVssAsync> pAsync;
548 HRESULT hr = pVss->GatherWriterStatus(&pAsync);
550 errno = b_errno_win32;
554 // Waits for the async operation to finish and checks the result
555 WaitAndCheckForAsyncOperation(pAsync);
557 unsigned cWriters = 0;
559 hr = pVss->GetWriterStatusCount(&cWriters);
561 errno = b_errno_win32;
567 // Enumerate each writer
568 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
569 VSS_ID idInstance = GUID_NULL;
570 VSS_ID idWriter= GUID_NULL;
571 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
572 CComBSTR bstrWriterName;
573 HRESULT hrWriterFailure = S_OK;
576 hr = pVss->GetWriterStatus(iWriter,
587 switch(eWriterStatus) {
588 case VSS_WS_FAILED_AT_IDENTIFY:
589 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
590 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
591 case VSS_WS_FAILED_AT_FREEZE:
592 case VSS_WS_FAILED_AT_THAW:
593 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
594 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
595 case VSS_WS_FAILED_AT_PRE_RESTORE:
596 case VSS_WS_FAILED_AT_POST_RESTORE:
598 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
610 /* store text info */
613 itoa(eWriterStatus, szBuf, 16);
616 str.Append (bstrWriterName);
617 str.Append ("\", State: 0x");
620 str.Append (GetStringFromWriterStatus(eWriterStatus));
623 AppendWriterInfo(nState, CW2A(str));
624 // SysFreeString (bstrWriterName);
627 hr = pVss->FreeWriterStatus();
630 errno = b_errno_win32;