/* **++ ** ** Copyright (c) 2000-2001 Microsoft Corporation ** ** ** Module Name: ** ** ml.cpp ** ** ** Abstract: ** ** Test program to exercise backup and multilayer snapshots ** ** Author: ** ** Adi Oltean [aoltean] 02/22/2001 ** ** ** Revision History: ** **-- */ /////////////////////////////////////////////////////////////////////////////// // Includes #include "ml.h" #include "vsbackup.h" #include "ntddsnap.h" #include #include "ichannel.hxx" #include "copy.hxx" #include "pointer.hxx" #include "enum.hxx" #include "qsnap.hxx" /////////////////////////////////////////////////////////////////////////////// // Processing functions void CVssMultilayerTest::Initialize() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::Initialize"); wprintf (L"\n----------------- Initializing ---------------------\n"); // Initialize the random starting point. srand(m_uSeed); // Initialize COM library CHECK_NOFAIL(CoInitializeEx (NULL, COINIT_MULTITHREADED)); m_bCoInitializeSucceeded = true; wprintf (L"COM library initialized.\n"); // Initialize COM security CHECK_SUCCESS ( CoInitializeSecurity ( NULL, // IN PSECURITY_DESCRIPTOR pSecDesc, -1, // IN LONG cAuthSvc, NULL, // IN SOLE_AUTHENTICATION_SERVICE *asAuthSvc, NULL, // IN void *pReserved1, RPC_C_AUTHN_LEVEL_CONNECT, // IN DWORD dwAuthnLevel, RPC_C_IMP_LEVEL_IMPERSONATE, // IN DWORD dwImpLevel, NULL, // IN void *pAuthList, EOAC_NONE, // IN DWORD dwCapabilities, NULL // IN void *pReserved3 ) ); wprintf (L"COM security initialized.\n"); } // Run the tests void CVssMultilayerTest::Run() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::Run"); BS_ASSERT(!m_bAttachYourDebuggerNow); switch(m_eTest) { case VSS_TEST_QUERY_VOLUMES: QuerySupportedVolumes(); break; case VSS_TEST_QUERY_SNAPSHOTS: QuerySnapshots(); break; case VSS_TEST_VOLSNAP_QUERY: QueryVolsnap(); break; case VSS_TEST_DELETE_BY_SNAPSHOT_ID: DeleteBySnapshotId(); break; case VSS_TEST_DELETE_BY_SNAPSHOT_SET_ID: DeleteBySnapshotSetId(); break; case VSS_TEST_QUERY_SNAPSHOTS_ON_VOLUME: QuerySnapshotsByVolume(); break; case VSS_TEST_CREATE: // Preload the list of existing snapshots PreloadExistingSnapshots(); if (m_lContext) CreateTimewarpSnapshotSet(); else CreateBackupSnapshotSet(); break; case VSS_TEST_ADD_DIFF_AREA: AddDiffArea(); break; case VSS_TEST_REMOVE_DIFF_AREA: RemoveDiffArea(); break; case VSS_TEST_CHANGE_DIFF_AREA_MAX_SIZE: ChangeDiffAreaMaximumSize(); break; case VSS_TEST_QUERY_SUPPORTED_VOLUMES_FOR_DIFF_AREA: QueryVolumesSupportedForDiffAreas(); break; case VSS_TEST_QUERY_DIFF_AREAS_FOR_VOLUME: QueryDiffAreasForVolume(); break; case VSS_TEST_QUERY_DIFF_AREAS_ON_VOLUME: QueryDiffAreasOnVolume(); break; case VSS_TEST_IS_VOLUME_SNAPSHOTTED_C: IsVolumeSnapshotted_C(); break; default: BS_ASSERT(false); } } // Querying supported volumes void CVssMultilayerTest::QuerySupportedVolumes() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::QuerySupportedVolumes"); wprintf (L"\n---------- Querying supported volumes ----------------\n"); // Create a Coordinator interface CComPtr pMgmt; CHECK_SUCCESS(pMgmt.CoCreateInstance( CLSID_VssSnapshotMgmt )); wprintf (L"Management object created.\n"); // Get list all snapshots CComPtr pIEnum; CHECK_NOFAIL( pMgmt->QueryVolumesSupportedForSnapshots( m_ProviderId, m_lContext, &pIEnum ) ) if (ft.hr == S_FALSE) { wprintf(L"Query: Empty result...\n"); return; } wprintf(L"\n%-50s %-15s\n", L"Volume Name", L"Display name"); wprintf(L"--------------------------------------------------------------------------------\n"); // For all volumes do... VSS_MGMT_OBJECT_PROP Prop; VSS_VOLUME_PROP& Vol = Prop.Obj.Vol; for(;;) { // Get next element ULONG ulFetched; CHECK_NOFAIL( pIEnum->Next( 1, &Prop, &ulFetched ) ); // Test if the cycle is finished if (ft.hr == S_FALSE) { BS_ASSERT( ulFetched == 0); break; } wprintf(L"%-50s %-15s\n", Vol.m_pwszVolumeName, Vol.m_pwszVolumeDisplayName ); ::CoTaskMemFree(Vol.m_pwszVolumeName); ::CoTaskMemFree(Vol.m_pwszVolumeDisplayName); } wprintf(L"--------------------------------------------------------------------------------\n"); } // Querying snapshots void CVssMultilayerTest::QuerySnapshotsByVolume() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::QuerySnapshotsByVolume"); wprintf (L"\n---------- Querying snapshots on volume ----------------\n"); // Create a Coordinator interface CComPtr pMgmt; CHECK_NOFAIL(pMgmt.CoCreateInstance( CLSID_VssSnapshotMgmt )); wprintf (L"Management object created.\n"); // Get list all snapshots CComPtr pIEnumSnapshots; CHECK_NOFAIL( pMgmt->QuerySnapshotsByVolume( m_pwszVolume, m_ProviderId, &pIEnumSnapshots ) ); if (ft.hr == S_FALSE) { wprintf(L"Query: Empty result...\n"); return; } wprintf(L"\n%-8s %-38s %-50s %-50s\n", L"Attrib.", L"Snapshot ID", L"Original Volume Name", L"Snapshot device name"); wprintf(L"--------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); // For all snapshots do... VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; for(;;) { // Get next element ULONG ulFetched; CHECK_NOFAIL( pIEnumSnapshots->Next( 1, &Prop, &ulFetched ) ); // Test if the cycle is finished if (ft.hr == S_FALSE) { BS_ASSERT( ulFetched == 0); break; } wprintf(L"%08lx " WSTR_GUID_FMT L" %-50s %-50s\n", Snap.m_lSnapshotAttributes, GUID_PRINTF_ARG(Snap.m_SnapshotId), Snap.m_pwszOriginalVolumeName, Snap.m_pwszSnapshotDeviceObject ); ::VssFreeSnapshotProperties(&Snap); } wprintf(L"--------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); } // Querying snapshots void CVssMultilayerTest::QuerySnapshots() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::QuerySnapshots"); wprintf (L"\n---------- Querying existing snapshots ----------------\n"); // Create a Coordinator interface CComPtr pCoord; CHECK_NOFAIL(pCoord.CoCreateInstance( CLSID_VSSCoordinator )); if (m_lContext) CHECK_NOFAIL(pCoord->SetContext(m_lContext)); wprintf (L"Coordinator object created with context 0x%08lx.\n", m_lContext); // Get list all snapshots CComPtr pIEnumSnapshots; CHECK_NOFAIL( pCoord->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots ) ); if (ft.hr == S_FALSE) { wprintf(L"Query: Empty result...\n"); return; } wprintf(L"\n%-8s %-38s %-50s %-50s\n", L"Attrib.", L"Snapshot ID", L"Original Volume Name", L"Snapshot device name"); wprintf(L"--------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); // For all snapshots do... VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; for(;;) { // Get next element ULONG ulFetched; CHECK_NOFAIL( pIEnumSnapshots->Next( 1, &Prop, &ulFetched )); // Test if the cycle is finished if (ft.hr == S_FALSE) { BS_ASSERT( ulFetched == 0); break; } wprintf(L"%08lx " WSTR_GUID_FMT L" %-50s %-50s\n", Snap.m_lSnapshotAttributes, GUID_PRINTF_ARG(Snap.m_SnapshotId), Snap.m_pwszOriginalVolumeName, Snap.m_pwszSnapshotDeviceObject ); ::CoTaskMemFree(Snap.m_pwszOriginalVolumeName); ::CoTaskMemFree(Snap.m_pwszSnapshotDeviceObject); } wprintf(L"--------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); } // Delete by snapshot Id void CVssMultilayerTest::DeleteBySnapshotId() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::DeleteBySnapshotId"); // Create a Timewarp Coordinator interface CHECK_NOFAIL(m_pTimewarpCoord.CoCreateInstance( CLSID_VSSCoordinator )); CHECK_NOFAIL(m_pTimewarpCoord->SetContext(m_lContext)); wprintf (L"Timewarp Coordinator object created.\n"); wprintf (L"\n---------- Deleting TIMEWARP snapshot ----------------\n"); LONG lDeletedSnapshots = 0; VSS_ID ProblemSnapshotId = GUID_NULL; ft.hr = m_pTimewarpCoord->DeleteSnapshots(m_SnapshotId, VSS_OBJECT_SNAPSHOT, TRUE, &lDeletedSnapshots, &ProblemSnapshotId ); if (ft.hr == VSS_E_OBJECT_NOT_FOUND) wprintf( L"Snapshot with ID " WSTR_GUID_FMT L" not found in any provider\n", GUID_PRINTF_ARG(m_SnapshotId)); else if (ft.hr == S_OK) wprintf( L"Snapshot with ID " WSTR_GUID_FMT L" successfully deleted\n", GUID_PRINTF_ARG(m_SnapshotId)); else wprintf( L"Error deleting Snapshot with ID " WSTR_GUID_FMT L" 0x%08lx\n" L"Deleted Snapshots %ld\n", L"Snapshot with problem: " WSTR_GUID_FMT L"\n", GUID_PRINTF_ARG(m_SnapshotId), lDeletedSnapshots, GUID_PRINTF_ARG(ProblemSnapshotId) ); wprintf (L"\n------------------------------------------------------\n"); } // Delete by snapshot set Id void CVssMultilayerTest::DeleteBySnapshotSetId() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::DeleteBySnapshotSetId"); // Create a Timewarp Coordinator interface CHECK_NOFAIL(m_pTimewarpCoord.CoCreateInstance( CLSID_VSSCoordinator )); CHECK_NOFAIL(m_pTimewarpCoord->SetContext(m_lContext)); wprintf (L"Timewarp Coordinator object created.\n"); wprintf (L"\n---------- Deleting TIMEWARP snapshot set ------------\n"); LONG lDeletedSnapshots = 0; VSS_ID ProblemSnapshotId = GUID_NULL; ft.hr = m_pTimewarpCoord->DeleteSnapshots(m_SnapshotSetId, VSS_OBJECT_SNAPSHOT_SET, TRUE, &lDeletedSnapshots, &ProblemSnapshotId ); if (ft.hr == VSS_E_OBJECT_NOT_FOUND) wprintf( L"Snapshot set with ID " WSTR_GUID_FMT L" not found\n", GUID_PRINTF_ARG(m_SnapshotSetId)); else if (ft.hr == S_OK) wprintf( L"Snapshot set with ID " WSTR_GUID_FMT L" successfully deleted\n", GUID_PRINTF_ARG(m_SnapshotSetId)); else wprintf( L"Error deleting Snapshot set with ID " WSTR_GUID_FMT L" 0x%08lx\n" L"Deleted Snapshots %ld\n", L"Snapshot with problem: " WSTR_GUID_FMT L"\n", GUID_PRINTF_ARG(m_SnapshotSetId), lDeletedSnapshots, GUID_PRINTF_ARG(ProblemSnapshotId) ); wprintf (L"\n------------------------------------------------------\n"); } // Querying snapshots using the IOCTL void CVssMultilayerTest::QueryVolsnap() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::QueryVolsnap"); // The GUID that corresponds to the format used to store the // Backup Snapshot Application Info in Client SKU // {BCF5D39C-27A2-4b4c-B9AE-51B111DC9409} const GUID VOLSNAP_APPINFO_GUID_BACKUP_CLIENT_SKU = { 0xbcf5d39c, 0x27a2, 0x4b4c, { 0xb9, 0xae, 0x51, 0xb1, 0x11, 0xdc, 0x94, 0x9 } }; /* // The GUID that corresponds to the format used to store the // Backup Snapshot Application Info in Server SKU // {BAE53126-BC65-41d6-86CC-3D56A5CEE693} const GUID VOLSNAP_APPINFO_GUID_BACKUP_SERVER_SKU = { 0xbae53126, 0xbc65, 0x41d6, { 0x86, 0xcc, 0x3d, 0x56, 0xa5, 0xce, 0xe6, 0x93 } }; // The GUID that corresponds to the format used to store the // Hidden (Inaccessible) Snapshot Application Info // {F12142B4-9A4B-49af-A851-700C42FDC2BE} static const GUID VOLSNAP_APPINFO_GUID_HIDDEN = { 0xf12142b4, 0x9a4b, 0x49af, { 0xa8, 0x51, 0x70, 0xc, 0x42, 0xfd, 0xc2, 0xbe } }; */ wprintf (L"\n---------- Querying existing snapshots ----------------\n"); // Check if the volume represents a real mount point WCHAR wszVolumeName[MAX_TEXT_BUFFER]; if (!GetVolumeNameForVolumeMountPoint(m_pwszVolume, wszVolumeName, MAX_TEXT_BUFFER)) CHECK_NOFAIL(HRESULT_FROM_WIN32(GetLastError())); wprintf(L"Querying snapshots on volume %s\n[From oldest to newest]\n\n", wszVolumeName); // Check if the snapshot is belonging to that volume // Open a IOCTL channel on that volume // Eliminate the last backslash in order to open the volume CVssIOCTLChannel volumeIChannel; CHECK_NOFAIL(volumeIChannel.Open(ft, wszVolumeName, true, false, VSS_ICHANNEL_LOG_NONE)); // Get the list of snapshots // If IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS not // supported then try with the next volume. CHECK_NOFAIL(volumeIChannel.Call(ft, IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS, false, VSS_ICHANNEL_LOG_NONE)); // Get the length of snapshot names multistring ULONG ulMultiszLen; volumeIChannel.Unpack(ft, &ulMultiszLen); // Try to find the snapshot with the corresponding Id DWORD dwInitialOffset = volumeIChannel.GetCurrentOutputOffset(); CVssAutoPWSZ pwszSnapshotName; while(volumeIChannel.UnpackZeroString(ft, pwszSnapshotName.GetRef())) { // Compose the snapshot name in a user-mode style WCHAR wszUserModeSnapshotName[MAX_PATH]; ::VssConcatenate( ft, wszUserModeSnapshotName, MAX_PATH - 1, wszGlobalRootPrefix, pwszSnapshotName ); // Open that snapshot // Do not eliminate the trailing backslash // Do not throw on error CVssIOCTLChannel snapshotIChannel; CHECK_NOFAIL(snapshotIChannel.Open(ft, wszUserModeSnapshotName, false, false, VSS_ICHANNEL_LOG_NONE)); // Send the IOCTL to get the application buffer CHECK_NOFAIL(snapshotIChannel.Call(ft, IOCTL_VOLSNAP_QUERY_APPLICATION_INFO, false, VSS_ICHANNEL_LOG_NONE)); // Unpack the length of the application buffer ULONG ulLen; snapshotIChannel.Unpack(ft, &ulLen); if (ulLen == 0) { wprintf(L"Zero-size snapshot detected: %s\n", pwszSnapshotName); continue; } // Get the application Id VSS_ID AppinfoId; snapshotIChannel.Unpack(ft, &AppinfoId); // Get the snapshot Id VSS_ID CurrentSnapshotId; snapshotIChannel.Unpack(ft, &CurrentSnapshotId); // Get the snapshot set Id VSS_ID CurrentSnapshotSetId; snapshotIChannel.Unpack(ft, &CurrentSnapshotSetId); LONG lStructureContext = -1; if (AppinfoId != VOLSNAP_APPINFO_GUID_BACKUP_CLIENT_SKU) { // Get the snapshot context snapshotIChannel.Unpack(ft, &lStructureContext); } // Get the snapshot counts LONG lSnapshotsCount; snapshotIChannel.Unpack(ft, &lSnapshotsCount); // Reset the ichannel snapshotIChannel.ResetOffsets(); // Get the original volume name CHECK_NOFAIL(snapshotIChannel.Call(ft, IOCTL_VOLSNAP_QUERY_ORIGINAL_VOLUME_NAME, false, VSS_ICHANNEL_LOG_NONE)); // Load the Original volume name VSS_PWSZ pwszOriginalVolumeName = NULL; snapshotIChannel.UnpackSmallString(ft, pwszOriginalVolumeName); // Reset the ichannel snapshotIChannel.ResetOffsets(); // Get the timestamp CHECK_NOFAIL(snapshotIChannel.Call(ft, IOCTL_VOLSNAP_QUERY_CONFIG_INFO, false, VSS_ICHANNEL_LOG_NONE)); // Load the Original volume name VOLSNAP_CONFIG_INFO configStruct; snapshotIChannel.Unpack(ft, &configStruct); // Print the snapshot wprintf( L" * Snapshot with name %s:\n" L" Application Info: " WSTR_GUID_FMT L"\n" L" SnapshotID: " WSTR_GUID_FMT L"\n" L" SnapshotSetID: " WSTR_GUID_FMT L"\n" L" Context: 0x%08lx\n" L" Snapshot count: %d\n" L" Original volume: %s\n" L" Internal attributes: 0x%08lx\n" L" Reserved config info: 0x%08lx\n" L" Timestamp: %I64x\n\n" , pwszSnapshotName.GetRef(), GUID_PRINTF_ARG(AppinfoId), GUID_PRINTF_ARG(CurrentSnapshotId), GUID_PRINTF_ARG(CurrentSnapshotSetId), lStructureContext, lSnapshotsCount, pwszOriginalVolumeName, configStruct.Attributes, configStruct.Reserved, configStruct.SnapshotCreationTime ); ::VssFreeString(pwszOriginalVolumeName); } // Check if all strings were browsed correctly DWORD dwFinalOffset = volumeIChannel.GetCurrentOutputOffset(); BS_VERIFY( (dwFinalOffset - dwInitialOffset == ulMultiszLen)); wprintf(L"----------------------------------------------------------\n"); } // Checks if hte volume is snapshotted using the C API void CVssMultilayerTest::IsVolumeSnapshotted_C() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::IsVolumeSnapshotted_C"); wprintf (L"\n---------- Querying IsVolumeSnapshotted ---------------\n"); BOOL bSnapshotsPresent = FALSE; LONG lSnapshotCompatibility = 0; CHECK_NOFAIL(IsVolumeSnapshotted(m_pwszVolume, &bSnapshotsPresent, &lSnapshotCompatibility)); wprintf(L"\n IsVolumeSnapshotted(%s) returned:\n\tSnapshots present = %s\n\tCompatibility flags = 0x%08lx\n\n", m_pwszVolume, bSnapshotsPresent? L"True": L"False", lSnapshotCompatibility); wprintf(L"----------------------------------------------------------\n"); } // Preloading snapshots void CVssMultilayerTest::PreloadExistingSnapshots() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::PreloadExistingSnapshots"); wprintf (L"\n---------- Preloading existing snapshots ----------------\n"); // Create a Timewarp Coordinator interface CHECK_NOFAIL(m_pAllCoord.CoCreateInstance( CLSID_VSSCoordinator )); CHECK_NOFAIL(m_pAllCoord->SetContext(VSS_CTX_ALL)); wprintf (L"Timewarp Coordinator object created.\n"); // Get list all snapshots CComPtr pIEnumSnapshots; CHECK_NOFAIL( m_pAllCoord->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots ) ); wprintf(L"\n%-8s %-38s %-50s %-50s\n", L"Attrib.", L"Snapshot ID", L"Original Volume Name", L"Snapshot device name"); wprintf(L"--------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); // For all snapshots do... VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; for(;;) { // Get next element ULONG ulFetched; CHECK_NOFAIL( pIEnumSnapshots->Next( 1, &Prop, &ulFetched )); // Test if the cycle is finished if (ft.hr == S_FALSE) { BS_ASSERT( ulFetched == 0); break; } wprintf(L"%08lx " WSTR_GUID_FMT L" %-50s %-50s\n", Snap.m_lSnapshotAttributes, GUID_PRINTF_ARG(Snap.m_SnapshotId), Snap.m_pwszOriginalVolumeName, Snap.m_pwszSnapshotDeviceObject ); // // Adding the snapshot to the internal list // // Create the new snapshot set object, if not exists CVssSnapshotSetInfo* pSet = m_pSnapshotSetCollection.Lookup(Snap.m_SnapshotSetId); bool bSetNew = false; if (pSet == NULL) { pSet = new CVssSnapshotSetInfo(Snap.m_SnapshotSetId); if (pSet == NULL) { ::CoTaskMemFree(Snap.m_pwszOriginalVolumeName); ::CoTaskMemFree(Snap.m_pwszSnapshotDeviceObject); ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } bSetNew = true; } // Create the snapshot info object CVssSnapshotInfo* pSnap = new CVssSnapshotInfo( true, Snap.m_lSnapshotAttributes, Snap.m_SnapshotSetId, Snap.m_pwszSnapshotDeviceObject, Snap.m_pwszOriginalVolumeName, NULL); if (pSnap == NULL) { ::CoTaskMemFree(Snap.m_pwszOriginalVolumeName); ::CoTaskMemFree(Snap.m_pwszSnapshotDeviceObject); if (bSetNew) delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } ::CoTaskMemFree(Snap.m_pwszSnapshotDeviceObject); // Add the snapshot to the snapshot set's internal list if (!pSet->Add(Snap.m_pwszOriginalVolumeName, pSnap)) { ::CoTaskMemFree(Snap.m_pwszOriginalVolumeName); delete pSnap; if (bSetNew) delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } ::CoTaskMemFree(Snap.m_pwszOriginalVolumeName); // Add the snapshot set info to the global list, if needed if (bSetNew) if (!m_pSnapshotSetCollection.Add(Snap.m_SnapshotSetId, pSet)) ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } wprintf(L"--------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); } // Creating a backup snapshot void CVssMultilayerTest::CreateTimewarpSnapshotSet() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::CreateTimewarpSnapshotSet"); // Create a Timewarp Coordinator interface CHECK_NOFAIL(m_pTimewarpCoord.CoCreateInstance( CLSID_VSSCoordinator )); CHECK_NOFAIL(m_pTimewarpCoord->SetContext(m_lContext)); wprintf (L"Timewarp Coordinator object created.\n"); wprintf (L"\n---------- Starting TIMEWARP snapshot ----------------\n"); CVssVolumeMapNoRemove mapVolumes; if (m_uSeed != VSS_SEED) { // Select one volume. Make sure that we have enough iterations for(INT nIterations = 0; nIterations < MAX_VOL_ITERATIONS; nIterations++) { // If we succeeded to select some volumes then continue; if (mapVolumes.GetSize()) break; // Try to select some volumes for backup for (INT nIndex = 0; nIndex < m_mapVolumes.GetSize(); nIndex++) { // Arbitrarily skip volumes if (RndDecision()) continue; CVssVolumeInfo* pVol = m_mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // WARNING: the test assumes that VSS can have multiple backup snapshots at once. if (!mapVolumes.Add(pVol->GetVolumeDisplayName(), pVol)) ft.Err(VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allcation error"); // Add only one volume! break; } } if (nIterations >= MAX_VOL_ITERATIONS) { wprintf (L"Warning: a backup snapshot cannot be created. Insufficient volumes?\n"); wprintf (L"\n---------- Ending TIMEWARP snapshot ----------------\n"); return; } } else { // Select all volumes for (INT nIndex = 0; nIndex < m_mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = m_mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // WARNING: the test assumes that VSS can have multiple backup snapshots at once. if (!mapVolumes.Add(pVol->GetVolumeDisplayName(), pVol)) ft.Err(VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allcation error"); } } wprintf(L"\tCurrent volume set:\n"); for (INT nIndex = 0; nIndex < mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // Get the volume containing the path wprintf(L"\t- Volume %s mounted on %s\n", pVol->GetVolumeName(), pVol->GetVolumeDisplayName() ); } wprintf (L"\n---------- starting the snapshot set ---------------\n"); CComPtr pAsync; CSimpleArray pSnapshotIDsArray; VSS_ID SnapshotSetId = GUID_NULL; // Starting a new snapshot set wprintf(L"Starting a new Snapshot Set\n"); CHECK_SUCCESS(m_pTimewarpCoord->StartSnapshotSet(&SnapshotSetId)); wprintf(L"Snapshot Set created with ID = " WSTR_GUID_FMT L"\n", GUID_PRINTF_ARG(SnapshotSetId)); // Add volumes to the snapshot set wprintf(L"Adding volumes to the Snapshot Set: \n"); for (INT nIndex = 0; nIndex < mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // Get the volume containing the path wprintf(L"\t- Adding volume %s ... ", pVol->GetVolumeDisplayName() ); // Add the volume to the snapshot set VSS_ID SnapshotId; CHECK_SUCCESS(m_pTimewarpCoord->AddToSnapshotSet(pVol->GetVolumeName(), GUID_NULL, &SnapshotId)); // Add the snapshot to the array pSnapshotIDsArray.Add(SnapshotId); BS_ASSERT(nIndex + 1 == pSnapshotIDsArray.GetSize()); wprintf( L"OK\n"); } wprintf (L"\n------------ Creating the snapshot -----------------\n"); // Create the snapshot wprintf(L"\nStarting asynchronous DoSnapshotSet. Please wait...\n"); ft.hr = S_OK; pAsync = NULL; CHECK_SUCCESS(m_pTimewarpCoord->DoSnapshotSet(NULL, &pAsync)); CHECK_SUCCESS(pAsync->Wait()); HRESULT hrReturned = S_OK; CHECK_SUCCESS(pAsync->QueryStatus(&hrReturned, NULL)); CHECK_NOFAIL(hrReturned); wprintf(L"Asynchronous DoSnapshotSet finished.\n"); wprintf(L"Snapshot set created\n"); // Create the new snapshot set object CVssSnapshotSetInfo* pSet = new CVssSnapshotSetInfo(SnapshotSetId); if (pSet == NULL) ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); for (INT nIndex = 0; nIndex < mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); if (pSnapshotIDsArray[nIndex] == GUID_NULL) continue; VSS_SNAPSHOT_PROP prop; CHECK_SUCCESS(m_pTimewarpCoord->GetSnapshotProperties(pSnapshotIDsArray[nIndex], &prop)); wprintf(L"\t- The snapshot on volume %s resides at %s\n", pVol->GetVolumeDisplayName(), prop.m_pwszSnapshotDeviceObject); // Create the snapshot info object CVssSnapshotInfo* pSnap = new CVssSnapshotInfo( true, VSS_CTX_CLIENT_ACCESSIBLE, SnapshotSetId, prop.m_pwszSnapshotDeviceObject, pVol->GetVolumeName(), pVol); if (pSnap == NULL) { ::VssFreeSnapshotProperties(&prop); delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } ::VssFreeSnapshotProperties(&prop); // Add the snapshot to the snapshot set's internal list if (!pSet->Add(pVol->GetVolumeName(), pSnap)) { delete pSnap; delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } } // Add the snapshot set info to the global list if (!m_pSnapshotSetCollection.Add(SnapshotSetId, pSet)) { delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } wprintf (L"\n---------- TIMEWARP snapshot created -----------------\n"); // Wait for user input wprintf(L"\nPress to continue...\n"); getwchar(); } // Creating a backup snapshot void CVssMultilayerTest::CreateBackupSnapshotSet() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::CreateBackupSnapshotSet"); // Create the Backup components object and initialize for backup CHECK_NOFAIL(CreateVssBackupComponents(&m_pBackupComponents)); CHECK_NOFAIL(m_pBackupComponents->InitializeForBackup()); CHECK_SUCCESS(m_pBackupComponents->SetBackupState( false, true, VSS_BT_FULL, false)); wprintf (L"Backup components object created.\n"); // Gather writer metadata GatherWriterMetadata(); wprintf (L"\n---------- Starting BACKUP snapshot ----------------\n"); // Compute a set of volumes. // Select at least one volume. Make sure that we have enough iterations CVssVolumeMapNoRemove mapVolumes; if (m_uSeed != VSS_SEED) { for(INT nIterations = 0; nIterations < MAX_VOL_ITERATIONS; nIterations++) { // If we succeeded to select some volumes then continue; if (mapVolumes.GetSize()) break; // Try to select some volumes for backup for (INT nIndex = 0; nIndex < m_mapVolumes.GetSize(); nIndex++) { // Arbitrarily skip volumes if (RndDecision()) continue; CVssVolumeInfo* pVol = m_mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // WARNING: the test assumes that VSS can have multiple backup snapshots at once. if (!mapVolumes.Add(pVol->GetVolumeDisplayName(), pVol)) ft.Err(VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allcation error"); } } if (nIterations >= MAX_VOL_ITERATIONS) { wprintf (L"Warning: a backup snapshot cannot be created. Insufficient volumes?\n"); wprintf (L"\n---------- Ending BACKUP snapshot ----------------\n"); return; } } else { // Select all volumes for (INT nIndex = 0; nIndex < m_mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = m_mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // WARNING: the test assumes that VSS can have multiple backup snapshots at once. if (!mapVolumes.Add(pVol->GetVolumeDisplayName(), pVol)) ft.Err(VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allcation error"); } } wprintf(L"\tCurrent volume set:\n"); for (INT nIndex = 0; nIndex < mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // Get the volume containing the path wprintf(L"\t- Volume %s mounted on %s\n", pVol->GetVolumeName(), pVol->GetVolumeDisplayName() ); } wprintf (L"\n---------- starting the snapshot set ---------------\n"); CComPtr pAsync; CSimpleArray pSnapshotIDsArray; VSS_ID SnapshotSetId = GUID_NULL; // Starting a new snapshot set wprintf(L"Starting a new Snapshot Set\n"); CHECK_SUCCESS(m_pBackupComponents->StartSnapshotSet(&SnapshotSetId)); wprintf(L"Snapshot Set created with ID = " WSTR_GUID_FMT L"\n", GUID_PRINTF_ARG(SnapshotSetId)); // Add volumes to the snapshot set wprintf(L"Adding volumes to the Snapshot Set: \n"); for (INT nIndex = 0; nIndex < mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); // Get the volume containing the path wprintf(L"\t- Adding volume %s ... ", pVol->GetVolumeDisplayName() ); // Add the volume to the snapshot set VSS_ID SnapshotId; CHECK_SUCCESS(m_pBackupComponents->AddToSnapshotSet(pVol->GetVolumeName(), GUID_NULL, &SnapshotId)); // Add the snapshot to the array pSnapshotIDsArray.Add(SnapshotId); BS_ASSERT(nIndex + 1 == pSnapshotIDsArray.GetSize()); wprintf( L"OK\n"); } wprintf (L"\n------------ Creating the snapshot -----------------\n"); // Prepare for backup wprintf(L"Starting asynchronous PrepareForBackup. Please wait...\n"); ft.hr = S_OK; CHECK_SUCCESS(m_pBackupComponents->PrepareForBackup(&pAsync)); CHECK_SUCCESS(pAsync->Wait()); HRESULT hrReturned = S_OK; CHECK_SUCCESS(pAsync->QueryStatus(&hrReturned, NULL)); CHECK_NOFAIL(hrReturned); wprintf(L"Asynchronous PrepareForBackup finished.\n"); // Create the snapshot wprintf(L"\nStarting asynchronous DoSnapshotSet. Please wait...\n"); ft.hr = S_OK; pAsync = NULL; CHECK_SUCCESS(m_pBackupComponents->DoSnapshotSet(&pAsync)); CHECK_SUCCESS(pAsync->Wait()); CHECK_SUCCESS(pAsync->QueryStatus(&hrReturned, NULL)); CHECK_NOFAIL(hrReturned); wprintf(L"Asynchronous DoSnapshotSet finished.\n"); wprintf(L"Snapshot set created\n"); // Create the new snapshot set object CVssSnapshotSetInfo* pSet = new CVssSnapshotSetInfo(SnapshotSetId); if (pSet == NULL) ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); for (INT nIndex = 0; nIndex < mapVolumes.GetSize(); nIndex++) { CVssVolumeInfo* pVol = mapVolumes.GetValueAt(nIndex); BS_ASSERT(pVol); if (pSnapshotIDsArray[nIndex] == GUID_NULL) continue; VSS_SNAPSHOT_PROP prop; CHECK_SUCCESS(m_pBackupComponents->GetSnapshotProperties(pSnapshotIDsArray[nIndex], &prop)); wprintf(L"\t- The snapshot on volume %s resides at %s\n", pVol->GetVolumeDisplayName(), prop.m_pwszSnapshotDeviceObject); // Create the snapshot info object CVssSnapshotInfo* pSnap = new CVssSnapshotInfo( true, VSS_CTX_BACKUP, SnapshotSetId, prop.m_pwszSnapshotDeviceObject, pVol->GetVolumeName(), pVol); if (pSnap == NULL) { ::VssFreeSnapshotProperties(&prop); delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } ::VssFreeSnapshotProperties(&prop); // Add the snapshot to the snapshot set's internal list if (!pSet->Add(pVol->GetVolumeName(), pSnap)) { delete pSnap; delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } } // Add the snapshot set info to the global list if (!m_pSnapshotSetCollection.Add(SnapshotSetId, pSet)) { delete pSet; ft.Err( VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allocation error"); } wprintf (L"\n---------- BACKUP snapshot created -----------------\n"); // Wait for user input wprintf(L"\nPress to continue...\n"); getwchar(); // Complete the backup BackupComplete(); } void CVssMultilayerTest::BackupComplete() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::BackupComplete"); CComPtr pAsync; wprintf (L"\n------------ Completing backup phase ---------------\n"); // Send the BackupComplete event wprintf(L"\nStarting asynchronous BackupComplete. Please wait...\n"); ft.hr = S_OK; CHECK_SUCCESS(m_pBackupComponents->BackupComplete(&pAsync)); CHECK_SUCCESS(pAsync->Wait()); HRESULT hrReturned = S_OK; CHECK_SUCCESS(pAsync->QueryStatus(&hrReturned, NULL)); CHECK_NOFAIL(hrReturned); wprintf(L"Asynchronous BackupComplete finished.\n"); } // Gather writera metadata and select components for backup, if needed void CVssMultilayerTest::GatherWriterMetadata() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::GatherWriterMetadata"); unsigned cWriters; CComPtr pAsync; wprintf (L"\n---------- Gathering writer metadata ---------------\n"); wprintf(L"Starting asynchronous GatherWriterMetadata. Please wait...\n"); ft.hr = S_OK; CHECK_SUCCESS(m_pBackupComponents->GatherWriterMetadata(&pAsync)); CHECK_SUCCESS(pAsync->Wait()); HRESULT hrReturned = S_OK; CHECK_SUCCESS(pAsync->QueryStatus(&hrReturned, NULL)); CHECK_NOFAIL(hrReturned); wprintf(L"Asynchronous GatherWriterMetadata finished.\n"); CHECK_NOFAIL (m_pBackupComponents->GetWriterMetadataCount (&cWriters)); wprintf(L"Number of writers that responded: %u\n", cWriters); CHECK_SUCCESS (m_pBackupComponents->FreeWriterMetadata()); } void CVssMultilayerTest::GatherWriterStatus( IN LPCWSTR wszWhen ) { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::GatherWriterMetadata"); unsigned cWriters; CComPtr pAsync; wprintf (L"\nGathering writer status %s... ", wszWhen); ft.hr = S_OK; CHECK_SUCCESS(m_pBackupComponents->GatherWriterStatus(&pAsync)); CHECK_SUCCESS(pAsync->Wait()); HRESULT hrReturned = S_OK; CHECK_SUCCESS(pAsync->QueryStatus(&hrReturned, NULL)); CHECK_NOFAIL(hrReturned); CHECK_NOFAIL(m_pBackupComponents->GetWriterStatusCount(&cWriters)); m_pBackupComponents->FreeWriterStatus(); wprintf (L"%d writers responded\n", cWriters); } CVssMultilayerTest::CVssMultilayerTest( IN INT nArgsCount, IN WCHAR ** ppwszArgsArray ) { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::CVssMultilayerTest"); // Initialize data members m_bCoInitializeSucceeded = false; m_bAttachYourDebuggerNow = false; // Command line options m_eTest = VSS_TEST_UNKNOWN; m_uSeed = VSS_SEED; m_lContext = VSS_CTX_BACKUP; m_pwszVolume = NULL; m_pwszDiffAreaVolume = NULL; m_ProviderId = VSS_SWPRV_ProviderId; m_llMaxDiffArea = VSS_ASSOC_NO_MAX_SPACE; m_SnapshotId = GUID_NULL; m_SnapshotSetId = GUID_NULL; // Command line arguments m_nCurrentArgsCount = nArgsCount; m_ppwszCurrentArgsArray = ppwszArgsArray; // Print display header wprintf(L"\nVSS Multilayer Test application, version 1.0\n"); } CVssMultilayerTest::~CVssMultilayerTest() { CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::~CVssMultilayerTest"); VssFreeString(m_pwszVolume); VssFreeString(m_pwszDiffAreaVolume); m_pTimewarpCoord = NULL; m_pAllCoord = NULL; m_pBackupComponents = NULL; // Unloading the COM library if (m_bCoInitializeSucceeded) CoUninitialize(); }