///////////////////////////////////////////////////////////////////////// // Copyright © Microsoft Corporation. All rights reserved. // // This file may contain preliminary information or inaccuracies, // and may not correctly represent any associated Microsoft // Product as commercially released. All Materials are provided entirely // “AS IS.” To the extent permitted by law, MICROSOFT MAKES NO // WARRANTY OF ANY KIND, DISCLAIMS ALL EXPRESS, IMPLIED AND STATUTORY // WARRANTIES, AND ASSUMES NO LIABILITY TO YOU FOR ANY DAMAGES OF // ANY TYPE IN CONNECTION WITH THESE MATERIALS OR ANY INTELLECTUAL PROPERTY IN THEM. // // Main header #include "stdafx.h" void VssClient::CreateSnapshotSet( vector volumeList, wstring outputXmlFile, vector excludedWriterList, vector includedWriterList ) { FunctionTracer ft(DBG_INFO); bool bSnapshotWithWriters = ((m_dwContext & VSS_VOLSNAP_ATTR_NO_WRITERS) == 0); // Gather writer metadata if (bSnapshotWithWriters) GatherWriterMetadata(); // Select writer components based on the given shadow volume list if (bSnapshotWithWriters) SelectComponentsForBackup(volumeList, excludedWriterList, includedWriterList); // Start the shadow set CHECK_COM(m_pVssObject->StartSnapshotSet(&m_latestSnapshotSetID)) ft.WriteLine(L"Creating shadow set " WSTR_GUID_FMT L" ...", GUID_PRINTF_ARG(m_latestSnapshotSetID)); // Add the specified volumes to the shadow set AddToSnapshotSet(volumeList); // Prepare for backup. // This will internally create the backup components document with the selected components if (bSnapshotWithWriters) PrepareForBackup(); // Creates the shadow set DoSnapshotSet(); // Do not attempt to continue with delayed snapshot ... if (m_dwContext & VSS_VOLSNAP_ATTR_DELAYED_POSTSNAPSHOT) { ft.WriteLine(L"\nFast snapshot created. Exiting... \n"); return; } // Saves the backup components document, if needed if (outputXmlFile.length() > 0) SaveBackupComponentsDocument(outputXmlFile); // List all the created shadow copies if ((m_dwContext & VSS_VOLSNAP_ATTR_TRANSPORTABLE) == 0) { ft.WriteLine(L"\nList of created shadow copies: \n"); QuerySnapshotSet(m_latestSnapshotSetID); } } // Prepare the shadow for backup void VssClient::PrepareForBackup() { FunctionTracer ft(DBG_INFO); ft.WriteLine(L"Preparing for backup ... "); CComPtr pAsync; CHECK_COM(m_pVssObject->PrepareForBackup(&pAsync)); // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync); // Check selected writer status CheckSelectedWriterStatus(); } // Add volumes to the shadow set void VssClient::AddToSnapshotSet(vector volumeList) { FunctionTracer ft(DBG_INFO); // Preserve the list of volumes for script generation m_latestVolumeList = volumeList; _ASSERTE(m_latestSnapshotIdList.size() == 0); // Add volumes to the shadow set for (unsigned i = 0; i < volumeList.size(); i++) { wstring volume = volumeList[i]; ft.WriteLine(L"- Adding volume %s [%s] to the shadow set...", volume.c_str(), GetDisplayNameForVolume(volume).c_str()); VSS_ID SnapshotID; CHECK_COM(m_pVssObject->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &SnapshotID)); // Preserve this shadow ID for script generation m_latestSnapshotIdList.push_back(SnapshotID); } } // Effectively creating the shadow (calling DoSnapshotSet) void VssClient::DoSnapshotSet() { FunctionTracer ft(DBG_INFO); ft.WriteLine(L"Creating the shadow (DoSnapshotSet) ... "); CComPtr pAsync; CHECK_COM(m_pVssObject->DoSnapshotSet(&pAsync)); // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync); // Do not attempt to continue with delayed snapshot ... if (m_dwContext & VSS_VOLSNAP_ATTR_DELAYED_POSTSNAPSHOT) { ft.WriteLine(L"\nFast DoSnapshotSet finished. \n"); return; } // Check selected writer status CheckSelectedWriterStatus(); ft.WriteLine(L"Shadow copy set succesfully created."); } // Ending the backup (calling BackupComplete) void VssClient::BackupComplete(bool succeeded) { FunctionTracer ft(DBG_INFO); unsigned cWriters = 0; CHECK_COM(m_pVssObject->GetWriterComponentsCount(&cWriters)); if (cWriters == 0) { ft.WriteLine(L"- There were no writer components in this backup"); return; } else if (succeeded) ft.WriteLine(L"- Mark all writers as succesfully backed up... "); else ft.WriteLine(L"- Backup failed. Mark all writers as not succesfully backed up... "); SetBackupSucceeded(succeeded); ft.WriteLine(L"Completing the backup (BackupComplete) ... "); CComPtr pAsync; CHECK_COM(m_pVssObject->BackupComplete(&pAsync)); // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync); // Check selected writer status CheckSelectedWriterStatus(); } // Save the backup components document void VssClient::SaveBackupComponentsDocument(wstring fileName) { FunctionTracer ft(DBG_INFO); ft.WriteLine(L"Saving the backup components document ... "); // Get the Backup Components in XML format CComBSTR bstrXML; CHECK_COM(m_pVssObject->SaveAsXML(&bstrXML)); // Save the XML string to the file WriteFile(fileName, BSTR2WString(bstrXML)); } // Generate the SETVAR script // This is useful for management operations void VssClient::GenerateSetvarScript(wstring stringFileName) { FunctionTracer ft(DBG_INFO); ft.WriteLine(L"Generating the SETVAR script (%s) ... ", stringFileName.c_str()); wofstream ofile; ofile.open(WString2String(stringFileName).c_str()); ofile << L"@echo.\n"; ofile << L"@echo [This script is generated by VSHADOW.EXE for the shadow set " << Guid2WString(m_latestSnapshotSetID).c_str() << L"]\n"; ofile << L"@echo.\n\n"; wstring snapshotSetID = Guid2WString(m_latestSnapshotSetID); ofile << L"SET SHADOW_SET_ID=" << snapshotSetID.c_str() << L"\n"; // For each added volume add the VSHADOW.EXE exposure command for (unsigned i = 0; i < m_latestSnapshotIdList.size(); i++) { wstring snapshotID = Guid2WString(m_latestSnapshotIdList[i]); ofile << L"SET SHADOW_ID_" << i+1 << L"=" << snapshotID.c_str() << L"\n"; // Get shadow copy device (if the snapshot is there) if ((m_dwContext & VSS_VOLSNAP_ATTR_TRANSPORTABLE) == 0) { VSS_SNAPSHOT_PROP Snap; CHECK_COM(m_pVssObject->GetSnapshotProperties(WString2Guid(snapshotID), &Snap)); // Automatically call VssFreeSnapshotProperties on this structure at the end of scope CAutoSnapPointer snapAutoCleanup(&Snap); ofile << L"SET SHADOW_DEVICE_" << i+1 << L"=" << Snap.m_pwszSnapshotDeviceObject << L"\n"; } } ofile.close(); } // Import the shadow set void VssClient::ImportSnapshotSet() { FunctionTracer ft(DBG_INFO); ft.WriteLine(L"Importing the transportable snapshot set ... "); CComPtr pAsync; CHECK_COM(m_pVssObject->ImportSnapshots(&pAsync)); // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync); ft.WriteLine(L"Shadow copy set succesfully imported."); } // Marks all selected components as succeeded for backup void VssClient::SetBackupSucceeded(bool succeeded) { FunctionTracer ft(DBG_INFO); // Enumerate writers for (unsigned iWriter = 0; iWriter < m_writerList.size(); iWriter++) { VssWriter & writer = m_writerList[iWriter]; // Enumerate components for(unsigned iComponent = 0; iComponent < writer.components.size(); iComponent++) { VssComponent & component = writer.components[iComponent]; // Test that the component is explicitely selected and requires notification if (!component.isExplicitlyIncluded) continue; // Call SetBackupSucceeded for this component CHECK_COM(m_pVssObject->SetBackupSucceeded( WString2Guid(writer.instanceId), WString2Guid(writer.id), component.type, component.logicalPath.c_str(), component.name.c_str(), succeeded)); } } }