// Query the properties of the given shadow copy void VssClient::GetSnapshotProperties(VSS_ID snapshotID) { FunctionTracer ft(DBG_INFO); // Get the shadow copy properties VSS_SNAPSHOT_PROP Snap; CHECK_COM(m_pVssObject->GetSnapshotProperties(snapshotID, &Snap)); // Automatically call VssFreeSnapshotProperties on this structure at the end of scope CAutoSnapPointer snapAutoCleanup(&Snap); // Print the properties of this shadow copy PrintSnapshotProperties(Snap); }
// Query all the shadow copies in the given set // If snapshotSetID is NULL, just query all shadow copies in the system void VssClient::QuerySnapshotSet(VSS_ID snapshotSetID) { FunctionTracer ft(DBG_INFO); if (snapshotSetID == GUID_NULL) ft.WriteLine(L"\nQuerying all shadow copies in the system ...\n"); else ft.WriteLine(L"\nQuerying all shadow copies with the SnapshotSetID " WSTR_GUID_FMT L" ...\n", GUID_PRINTF_ARG(snapshotSetID)); // Get list all shadow copies. CComPtr<IVssEnumObject> pIEnumSnapshots; HRESULT hr = m_pVssObject->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots ); CHECK_COM_ERROR(hr, L"m_pVssObject->Query(GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots )") // If there are no shadow copies, just return if (hr == S_FALSE) { if (snapshotSetID == GUID_NULL) ft.WriteLine(L"\nThere are no shadow copies in the system\n"); return; } // Enumerate all shadow copies. VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; while(true) { // Get the next element ULONG ulFetched; hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched ); CHECK_COM_ERROR(hr, L"pIEnumSnapshots->Next( 1, &Prop, &ulFetched )") // We reached the end of list if (ulFetched == 0) break; // Automatically call VssFreeSnapshotProperties on this structure at the end of scope CAutoSnapPointer snapAutoCleanup(&Snap); // Print the shadow copy (if not filtered out) if ((snapshotSetID == GUID_NULL) || (Snap.m_SnapshotSetId == snapshotSetID)) PrintSnapshotProperties(Snap); } }
// Return the list of snapshot volume devices in this snapshot set vector<wstring> VssClient::GetSnapshotDevices(VSS_ID snapshotSetID) { FunctionTracer ft(DBG_INFO); vector<wstring> volumes; // Get list all snapshots. CComPtr<IVssEnumObject> pIEnumSnapshots; CHECK_COM( m_pVssObject->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots ) ); // Enumerate all snapshots. VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; while(true) { // Get the next element ULONG ulFetched = 0; CHECK_COM(pIEnumSnapshots->Next( 1, &Prop, &ulFetched )); // We reached the end of list if (ulFetched == 0) break; // Automatically call VssFreeSnapshotProperties on this structure at the end of scope CAutoSnapPointer snapAutoCleanup(&Snap); // Ignore snapshots not part of this set if (Snap.m_SnapshotSetId == snapshotSetID) { // Get the snapshot device object name which is a volume guid name for persistent snapshot // and a device name for non persistent snapshot. // The volume guid name and the device name we obtained here might change after breaksnapshot // depending on if the disk signature is reverted, but those cached names should still work // as symbolic links, in which case they can not persist after reboot. wstring snapshotDeviceObjectName = Snap.m_pwszSnapshotDeviceObject; // Add it to the array ft.WriteLine(L"- Will convert %s to read-write ...", snapshotDeviceObjectName.c_str()); volumes.push_back(snapshotDeviceObjectName); } } // Return the list of snapshot volumes return volumes; }
void VssClient::RevertToSnapshot(VSS_ID snapshotID) { FunctionTracer ft(DBG_INFO); // Get the shadow copy properties VSS_SNAPSHOT_PROP Snap; CHECK_COM(m_pVssObject->GetSnapshotProperties(snapshotID, &Snap)); // Automatically call VssFreeSnapshotProperties on this structure at the end of scope CAutoSnapPointer snapAutoCleanup(&Snap); ft.WriteLine(L"- Reverting to shadow copy " WSTR_GUID_FMT L" on %s from provider " WSTR_GUID_FMT L" [0x%08lx]...", GUID_PRINTF_ARG(Snap.m_SnapshotId), Snap.m_pwszOriginalVolumeName, GUID_PRINTF_ARG(Snap.m_ProviderId), Snap.m_lSnapshotAttributes); bool bBlock = false; CHECK_COM(::ShouldBlockRevert(Snap.m_pwszOriginalVolumeName, &bBlock)); if (bBlock) { ft.WriteLine(L"Revert is disabled on the volume %s because of writers", Snap.m_pwszOriginalVolumeName); return; } HRESULT hr = m_pVssObject->RevertToSnapshot(snapshotID, true); if (FAILED(hr)) { switch (hr) { case VSS_E_OBJECT_NOT_FOUND: ft.WriteLine(L"Shadow Copy with id " WSTR_GUID_FMT L" was not found", GUID_PRINTF_ARG(snapshotID)); return; case VSS_E_VOLUME_IN_USE: ft.WriteLine(L"The voulume %s cannot be reverted since it is in use", Snap.m_pwszOriginalVolumeName); return; case VSS_E_REVERT_IN_PROGRESS: ft.WriteLine(L"A revert is current in progress on the volume %s", Snap.m_pwszOriginalVolumeName); return; case VSS_E_VOLUME_NOT_SUPPORTED: ft.WriteLine(L"Revert is not supported on the volume %s", Snap.m_pwszOriginalVolumeName); return; default: ft.WriteLine(L"RevertToSnapshot on Shadow Copy " WSTR_GUID_FMT L" failed with error 0x%08lx", GUID_PRINTF_ARG(snapshotID), hr); return; } } CComPtr<IVssAsync> pAsync; hr = m_pVssObject->QueryRevertStatus(Snap.m_pwszOriginalVolumeName, &pAsync); if (hr != VSS_E_OBJECT_NOT_FOUND) { if (FAILED(hr)) { ft.WriteLine(L"QueryRevertStatus failed with error 0x%08lx", hr); ft.WriteLine(L"Revert may still be in progress, but cannot be tracked"); return; } hr = pAsync->Wait(); if (FAILED(hr)) { ft.WriteLine(L"IVssAsync::Wait failed with error 0x%08lx", hr); ft.WriteLine(L"Revert may still be in progress, but cannot be tracked"); return; } } ft.WriteLine(L"The shadow copy has been successfully reverted"); }
// Delete all the shadow copies in the system void VssClient::DeleteAllSnapshots() { FunctionTracer ft(DBG_INFO); // Get list all shadow copies. CComPtr<IVssEnumObject> pIEnumSnapshots; HRESULT hr = m_pVssObject->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots ); CHECK_COM_ERROR(hr, L"m_pVssObject->Query(GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots )") // If there are no shadow copies, just return if (hr == S_FALSE) { ft.WriteLine(L"\nThere are no shadow copies on the system\n"); return; } // Enumerate all shadow copies. Delete each one VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; while(true) { // Get the next element ULONG ulFetched; hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched ); CHECK_COM_ERROR(hr, L"pIEnumSnapshots->Next( 1, &Prop, &ulFetched )") // We reached the end of list if (ulFetched == 0) break; // Automatically call VssFreeSnapshotProperties on this structure at the end of scope CAutoSnapPointer snapAutoCleanup(&Snap); // Print the deleted shadow copy... ft.WriteLine(L"- Deleting shadow copy " WSTR_GUID_FMT L" on %s from provider " WSTR_GUID_FMT L" [0x%08lx]...", GUID_PRINTF_ARG(Snap.m_SnapshotId), Snap.m_pwszOriginalVolumeName, GUID_PRINTF_ARG(Snap.m_ProviderId), Snap.m_lSnapshotAttributes); // Perform the actual deletion LONG lSnapshots = 0; VSS_ID idNonDeletedSnapshotID = GUID_NULL; hr = m_pVssObject->DeleteSnapshots( Snap.m_SnapshotId, VSS_OBJECT_SNAPSHOT, FALSE, &lSnapshots, &idNonDeletedSnapshotID); if (FAILED(hr)) { ft.WriteLine(L"Error while deleting shadow copies..."); ft.WriteLine(L"- Last shadow copy that could not be deleted: " WSTR_GUID_FMT, GUID_PRINTF_ARG(idNonDeletedSnapshotID)); CHECK_COM_ERROR(hr, L"m_pVssObject->DeleteSnapshots(Snap.m_SnapshotId, VSS_OBJECT_SNAPSHOT,FALSE,&lSnapshots,&idNonDeleted)"); } } }