// Delete the given shadow copy set void VssClient::DeleteSnapshotSet(VSS_ID snapshotSetID) { FunctionTracer ft(DBG_INFO); // Print the deleted shadow copy... ft.WriteLine(L"- Deleting shadow copy set " WSTR_GUID_FMT L" ...", GUID_PRINTF_ARG(snapshotSetID)); // Perform the actual deletion LONG lSnapshots = 0; VSS_ID idNonDeletedSnapshotID = GUID_NULL; HRESULT hr = m_pVssObject->DeleteSnapshots( snapshotSetID, VSS_OBJECT_SNAPSHOT_SET, 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(snapshotSetID, VSS_OBJECT_SNAPSHOT_SET,FALSE,&lSnapshots,&idNonDeleted)"); } }
// Make the volumes in this list read-write using VDS API void VssClient::MakeVolumesReadWrite(vector<wstring> snapshotVolumes) { FunctionTracer ft(DBG_INFO); ft.Trace(DBG_INFO, L"Clearing read-only on %d volumes ... ", snapshotVolumes.size()); // Get the VDS loader CComPtr<IVdsServiceLoader> pLoader; CHECK_COM(CoCreateInstance(CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER, __uuidof(IVdsServiceLoader), (void **)&pLoader)); // Get the service interface pointer CComPtr<IVdsService> pService; CHECK_COM(pLoader->LoadService(NULL, &pService)); CHECK_COM(pService->WaitForServiceReady()); vector<wstring> clearedVolumes; // Get the unique volume names for the cached snapshot volume names // which might change after the break vector<wstring> snapshotVolumeUniqueNames; for (unsigned i = 0; i < snapshotVolumes.size( ); i++) snapshotVolumeUniqueNames.push_back(GetUniqueVolumeNameForMountPoint(snapshotVolumes[i])); // Enumerate the Software providers HRESULT hr; CComPtr<IEnumVdsObject> pEnumProvider; CHECK_COM(pService->QueryProviders(VDS_QUERY_SOFTWARE_PROVIDERS,&pEnumProvider)); vector< CComPtr<IUnknown> > providers = EnumerateVdsObjects(pEnumProvider); for(unsigned iProvider = 0; iProvider < providers.size(); iProvider++) { // QueryInterface for IVdsSwProvider CComQIPtr<IVdsSwProvider> pSwProvider = providers[iProvider]; ft.Trace(DBG_INFO, L"- Provider %d", iProvider); // Enumerate packs for this provider CComPtr<IEnumVdsObject> pEnumPack; CHECK_COM(pSwProvider->QueryPacks(&pEnumPack)); vector< CComPtr<IUnknown> > packs = EnumerateVdsObjects(pEnumPack); for(unsigned iPack = 0; iPack < packs.size(); iPack++) { // QueryInterface for IVdsPack CComQIPtr<IVdsPack> pPack = packs[iPack]; ft.Trace(DBG_INFO, L"- Pack %d/%d", iPack, iProvider); // Enumerate volumes CComPtr<IEnumVdsObject> pEnumVolumes; hr = pPack->QueryVolumes(&pEnumVolumes); if (FAILED(hr)) { if (hr == VDS_E_INVALID_PACK) { hr = S_OK; } else ft.Trace( DBG_INFO, L"COM Error: GetProperties for VDS pack failed. hr = 0x%08lx", hr); continue; } vector< CComPtr<IUnknown> > volumes = EnumerateVdsObjects(pEnumVolumes); for(unsigned iVol = 0; iVol < volumes.size(); iVol++) { // QueryInterface for IVdsVolumeMF and IVdsVolume CComQIPtr<IVdsVolume> pVolume = volumes[iVol]; // Get volume properties. Ignore deleted volumes VDS_VOLUME_PROP volProp; HRESULT innerHR = pVolume->GetProperties(&volProp); if (innerHR == VDS_E_OBJECT_DELETED ) continue; CHECK_COM_ERROR(innerHR, L"pVolume->GetProperties(&volProp)"); // Skip failed volumes if ( (volProp.status == VDS_VS_FAILED) && (volProp.health == VDS_H_FAILED) || !volProp.pwszName) continue; // Skip hidden volumes (it fails GetVolumeNameForMountPoint) if (volProp.ulFlags & VDS_VF_HIDDEN) continue; // Automatically call CoTaskMemFree on this pointer at the end of scope CAutoComPointer ptrAutoCleanup(volProp.pwszName); // Get the initial device name (normally with the format \\?\GLOBALROOT\Device\HarddiskVolumeXX) wstring name = volProp.pwszName; // Get the unique volume guid name for this device name. wstring uniqueVolumeName = GetUniqueVolumeNameForMountPoint(name); ft.Trace(DBG_INFO, L"- Found volume %s [device = %s] in %d/%d", uniqueVolumeName.c_str(), name.c_str(), iPack, iProvider); // Check to see if this is one of our volumes. If not, continue if (!FindStringInList(uniqueVolumeName, snapshotVolumeUniqueNames)) continue; // Clear the read-only flag ft.WriteLine(L"- Clearing read-only flag for volume %s [%s] ...", uniqueVolumeName.c_str(), name.c_str()); CHECK_COM(pVolume->ClearFlags(VDS_VF_READONLY)); // Force-dismounts the volume // since we want to re-mount the file system as read-write CComQIPtr<IVdsVolumeMF> pVolumeMF = pVolume; ft.WriteLine(L"- Dismounting volume %s ...", name.c_str()); CHECK_COM(pVolumeMF->Dismount(TRUE, FALSE)); clearedVolumes.push_back(uniqueVolumeName); } } } // Check that all volumes have been cleared ... if (clearedVolumes.size() != snapshotVolumeUniqueNames.size()) { ft.WriteLine(L"WARNING: some volumes were not succesfully converted to read-write!"); for (unsigned i = 0; i < snapshotVolumeUniqueNames.size(); i++) if (!FindStringInList(snapshotVolumeUniqueNames[i], clearedVolumes)) ft.WriteLine(L"- Volume %s not found on the system. Clearing the read-only flag failed on it.", snapshotVolumeUniqueNames[i].c_str()); } }
// 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)"); } } }