|
|
/*++
Copyright (c) 1999-2001 Microsoft Corporation
Abstract:
@doc @module process.cpp | The processing functions for the VSS admin CLI @end
Author:
Adi Oltean [aoltean] 04/04/2000
TBD: Add comments.
Revision History:
Name Date Comments aoltean 04/04/2000 Created ssteiner 10/20/2000 Changed List SnapshotSets to use more limited VSS queries.
--*/
/////////////////////////////////////////////////////////////////////////////
// Includes
// The rest of includes are specified here
#include "vssadmin.h"
#include "vswriter.h"
#include "vsbackup.h"
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "ADMPROCC"
//
////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Implementation
class CVssAdmSnapshotSetEntry { public: // Constructor - Throws NOTHING
CVssAdmSnapshotSetEntry( IN VSS_ID SnapshotSetId, IN INT nOriginalSnapshotsCount ) : m_SnapshotSetId( SnapshotSetId ), m_nOriginalSnapshotCount(nOriginalSnapshotsCount){ }
~CVssAdmSnapshotSetEntry() { // Have to delete all snapshots entries
int iCount = GetSnapshotCount(); for ( int i = 0; i < iCount; ++i ) { VSS_SNAPSHOT_PROP *pSSProp; pSSProp = GetSnapshotAt( i ); ::VssFreeSnapshotProperties(pSSProp);
delete pSSProp; } } // Add new snapshot to the snapshot set
HRESULT AddSnapshot( IN CVssFunctionTracer &ft, IN VSS_SNAPSHOT_PROP *pVssSnapshotProp ) { HRESULT hr = S_OK; try { VSS_SNAPSHOT_PROP *pNewVssSnapshotProp = new VSS_SNAPSHOT_PROP; if ( pNewVssSnapshotProp == NULL ) ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" ); *pNewVssSnapshotProp = *pVssSnapshotProp; if ( !m_mapSnapshots.Add( pNewVssSnapshotProp->m_SnapshotId, pNewVssSnapshotProp ) ) { delete pNewVssSnapshotProp; ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" ); } } BS_STANDARD_CATCH();
return hr; }
INT GetSnapshotCount() { return m_mapSnapshots.GetSize(); }
INT GetOriginalSnapshotCount() { return m_nOriginalSnapshotCount; }
VSS_ID GetSnapshotSetId() { return m_SnapshotSetId; } VSS_SNAPSHOT_PROP *GetSnapshotAt( IN int nIndex ) { BS_ASSERT( !(nIndex < 0 || nIndex >= GetSnapshotCount()) ); return m_mapSnapshots.GetValueAt( nIndex ); } private: VSS_ID m_SnapshotSetId; INT m_nOriginalSnapshotCount; CVssSimpleMap<VSS_ID, VSS_SNAPSHOT_PROP *> m_mapSnapshots; };
// This class queries the list of all snapshots and assembles from the query
// the list of snapshotsets and the volumes which are in the snapshotset.
class CVssAdmSnapshotSets { public: // Constructor - Throws HRESULTS
CVssAdmSnapshotSets( IN VSS_ID FilteredSnapshotSetId = GUID_NULL ) { CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdmSnapshotSets::CVssAdmSnapshotSets" ); bool bFiltered = !( FilteredSnapshotSetId == GUID_NULL );
// Create the coordinator object
CComPtr<IVssCoordinator> pICoord;
ft.LogVssStartupAttempt(); ft.hr = pICoord.CoCreateInstance( CLSID_VSSCoordinator ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Connection failed with hr = 0x%08lx", ft.hr);
// Get list all snapshots
CComPtr<IVssEnumObject> pIEnumSnapshots; ft.hr = pICoord->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, &pIEnumSnapshots ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Query failed with hr = 0x%08lx", ft.hr);
// For all snapshots do...
VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; for(;;) { // Get next element
ULONG ulFetched; ft.hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Next failed with hr = 0x%08lx", ft.hr); // Test if the cycle is finished
if (ft.hr == S_FALSE) { BS_ASSERT( ulFetched == 0); break; }
// If filtering, skip entry if snapshot is not in the specified snapshot set
if ( bFiltered && !( Snap.m_SnapshotSetId == FilteredSnapshotSetId ) ) continue;
ft.Trace( VSSDBG_VSSADMIN, L"Snapshot: %s", Snap.m_pwszOriginalVolumeName ); // Look up the snapshot set id in the list of snapshot sets
CVssAdmSnapshotSetEntry *pcSSE; pcSSE = m_mapSnapshotSets.Lookup( Snap.m_SnapshotSetId ); if ( pcSSE == NULL ) { // Haven't seen this snapshot set before, add it to list
pcSSE = new CVssAdmSnapshotSetEntry( Snap.m_SnapshotSetId, Snap.m_lSnapshotsCount ); if ( pcSSE == NULL ) ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" ); if ( !m_mapSnapshotSets.Add( Snap.m_SnapshotSetId, pcSSE ) ) { delete pcSSE; ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" ); } }
// Now add the snapshot to the snapshot set
ft.hr = pcSSE->AddSnapshot( ft, &Snap ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"AddSnapshot failed" ); } }
~CVssAdmSnapshotSets() { CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdmSnapshotSets::~CVssAdmSnapshotSets" ); // Have to delete all
int iCount; iCount = m_mapSnapshotSets.GetSize(); for ( int i = 0; i < iCount; ++i ) { delete m_mapSnapshotSets.GetValueAt( i ); } }
INT GetSnapshotSetCount() { return m_mapSnapshotSets.GetSize(); }
CVssAdmSnapshotSetEntry *GetSnapshotSetAt( IN int nIndex ) { BS_ASSERT( !(nIndex < 0 || nIndex >= GetSnapshotSetCount()) ); return m_mapSnapshotSets.GetValueAt( nIndex ); }
private: CVssSimpleMap<VSS_ID, CVssAdmSnapshotSetEntry *> m_mapSnapshotSets; };
/////////////////////////////////////////////////////////////////////////////
// Implementation
void CVssAdminCLI::PrintUsage( IN CVssFunctionTracer& ft ) throw(HRESULT) { // Usage:\n\n
// vssadmin list snapshots [-set {snapshot set guid}]\n
// \tWill list all snapshots in the system, grouped by snapshot set Id.\n\n
// vssadmin list writers\n
// \tWill list all writers in the system\n\n
// vssadmin list providers\n
// \tWill list all currently installed snapshot providers\n
Output( ft, IDS_USAGE ); Output( ft, IDS_USAGE_SNAPSHOTS, wszVssOptVssadmin, wszVssOptList, wszVssOptSnapshots, wszVssOptSet ); Output( ft, IDS_USAGE_WRITERS, wszVssOptVssadmin, wszVssOptList, wszVssOptWriters ); Output( ft, IDS_USAGE_PROVIDERS, wszVssOptVssadmin, wszVssOptList, wszVssOptProviders); }
void CVssAdminCLI::ListSnapshots( IN CVssFunctionTracer& ft ) throw(HRESULT) { bool bNonEmptyResult = false; // Check the filter type
switch ( m_eFilterObjectType ) { case VSS_OBJECT_SNAPSHOT_SET: case VSS_OBJECT_NONE: break;
default: BS_ASSERT(false); ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Invalid object type %d", m_eFilterObjectType); }
CVssAdmSnapshotSets cVssAdmSS( m_FilterSnapshotSetId );
INT iSnapshotSetCount = cVssAdmSS.GetSnapshotSetCount();
// If there are no present snapshots then display a message.
if (iSnapshotSetCount == 0) { Output( ft, (m_eFilterObjectType == VSS_OBJECT_SNAPSHOT_SET)? IDS_NO_SNAPSHOTS_FOR_SET: IDS_NO_SNAPSHOTS ); }
// For all snapshot sets do...
for ( INT iSSS = 0; iSSS < iSnapshotSetCount; ++iSSS ) { CVssAdmSnapshotSetEntry *pcSSE;
pcSSE = cVssAdmSS.GetSnapshotSetAt( iSSS ); BS_ASSERT( pcSSE != NULL ); // Print each snapshot set
Output( ft, IDS_SNAPSHOT_SET_HEADER, GUID_PRINTF_ARG( pcSSE->GetSnapshotSetId() ), pcSSE->GetOriginalSnapshotCount(), pcSSE->GetSnapshotCount());
// TBD: add creation time from the first snapshot.
INT iSnapshotCount = pcSSE->GetSnapshotCount(); VSS_SNAPSHOT_PROP *pSnap; for( INT iSS = 0; iSS < iSnapshotCount; ++iSS ) { pSnap = pcSSE->GetSnapshotAt( iSS ); BS_ASSERT( pSnap != NULL );
// Get the provider name
LPCWSTR pwszProviderName = GetProviderName(ft, pSnap->m_ProviderId);
// Print each snapshot
Output( ft, IDS_SNAPSHOT_CONTENTS, pwszProviderName? pwszProviderName: L"", GUID_PRINTF_ARG(pSnap->m_SnapshotId), pSnap->m_pwszOriginalVolumeName );
Output( ft, wszVssFmtNewline );
bNonEmptyResult = true; } }
m_nReturnValue = bNonEmptyResult? VSS_CMDRET_SUCCESS: VSS_CMDRET_EMPTY_RESULT; }
void CVssAdminCLI::ListWriters( IN CVssFunctionTracer& ft ) throw(HRESULT) { bool bNonEmptyResult = false; // Get the backup components object
CComPtr<IVssBackupComponents> pBackupComp; CComPtr<IVssAsync> pAsync; ft.hr = ::CreateVssBackupComponents(&pBackupComp); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"CreateVssBackupComponents failed with hr = 0x%08lx", ft.hr);
// BUGBUG Initialize for backup
ft.hr = pBackupComp->InitializeForBackup(); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"InitializeForBackup failed with hr = 0x%08lx", ft.hr);
UINT unWritersCount; // get metadata for all writers
ft.hr = pBackupComp->GatherWriterMetadata(&pAsync); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"GatherWriterMetadata failed with hr = 0x%08lx", ft.hr);
// Using polling, try to obtain the list of writers as soon as possible
HRESULT hrReturned = S_OK; for (int nRetries = 0; nRetries < MAX_RETRIES_COUNT; nRetries++ ) {
// Wait a little
::Sleep(nPollingInterval);
// Check if finished
INT nReserved = 0; ft.hr = pAsync->QueryStatus( &hrReturned, &nReserved ); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"IVssAsync::QueryStatus failed with hr = 0x%08lx", ft.hr); if (hrReturned == VSS_S_ASYNC_FINISHED) break; if (hrReturned == VSS_S_ASYNC_PENDING) continue; ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"IVssAsync::QueryStatus returned hr = 0x%08lx", hrReturned); }
// If still not ready, then print the "waiting for responses" message and wait.
if (hrReturned == VSS_S_ASYNC_PENDING) { Output( ft, IDS_WAITING_RESPONSES ); ft.hr = pAsync->Wait(); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"IVssAsync::Wait failed with hr = 0x%08lx", ft.hr); }
pAsync = NULL; // Gather the status of all writers
ft.hr = pBackupComp->GatherWriterStatus(&pAsync); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"GatherWriterMetadata failed with hr = 0x%08lx", ft.hr);
ft.hr = pAsync->Wait(); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"IVssAsync::Wait failed with hr = 0x%08lx", ft.hr);
pAsync = NULL;
ft.hr = pBackupComp->GetWriterStatusCount(&unWritersCount); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"GetWriterStatusCount failed with hr = 0x%08lx", ft.hr);
// Print each writer status+supplementary info
for(UINT unIndex = 0; unIndex < unWritersCount; unIndex++) { VSS_ID idInstance; VSS_ID idWriter; CComBSTR bstrWriter; VSS_WRITER_STATE eStatus; HRESULT hrWriterFailure;
// Get the status for the (unIndex)-th writer
ft.hr = pBackupComp->GetWriterStatus(unIndex, &idInstance, &idWriter, &bstrWriter, &eStatus, &hrWriterFailure); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"GetWriterStatus failed with hr = 0x%08lx", ft.hr);
// Get the status description strings
LPCWSTR pwszStatusDescription; switch (eStatus) { case VSS_WS_STABLE: pwszStatusDescription = LoadString( ft, IDS_WRITER_STATUS_STABLE); break; case VSS_WS_WAITING_FOR_FREEZE: pwszStatusDescription = LoadString( ft, IDS_WRITER_STATUS_WAITING_FOR_FREEZE); break; case VSS_WS_WAITING_FOR_THAW: pwszStatusDescription = LoadString( ft, IDS_WRITER_STATUS_FROZEN); break; case VSS_WS_WAITING_FOR_BACKUP_COMPLETE: pwszStatusDescription = LoadString( ft, IDS_WRITER_STATUS_WAITING_FOR_COMPLETION); break; case VSS_WS_FAILED_AT_IDENTIFY: case VSS_WS_FAILED_AT_PREPARE_BACKUP: case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT: case VSS_WS_FAILED_AT_FREEZE: case VSS_WS_FAILED_AT_THAW: pwszStatusDescription = LoadString( ft, IDS_WRITER_STATUS_FAILED); break; default: pwszStatusDescription = LoadString( ft, IDS_WRITER_STATUS_UNKNOWN); break; } BS_ASSERT(pwszStatusDescription);
// Print status+info about each writer
Output( ft, IDS_WRITER_CONTENTS, (LPWSTR)bstrWriter? (LPWSTR)bstrWriter: L"", GUID_PRINTF_ARG(idWriter), GUID_PRINTF_ARG(idInstance), (INT)eStatus, pwszStatusDescription );
Output( ft, wszVssFmtNewline );
bNonEmptyResult = true; }
ft.hr = pBackupComp->FreeWriterStatus(); if (ft.HrFailed()) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"FreeWriterStatus failed with hr = 0x%08lx", ft.hr);
m_nReturnValue = bNonEmptyResult? VSS_CMDRET_SUCCESS: VSS_CMDRET_EMPTY_RESULT; }
void CVssAdminCLI::ListProviders( IN CVssFunctionTracer& ft ) throw(HRESULT) { bool bNonEmptyResult = false; // Check the filter type
switch ( m_eFilterObjectType ) {
case VSS_OBJECT_NONE: break;
default: BS_ASSERT(false); ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Invalid object type %d", m_eFilterObjectType); }
// Create the coordinator object
CComPtr<IVssCoordinator> pICoord;
ft.LogVssStartupAttempt(); ft.hr = pICoord.CoCreateInstance( CLSID_VSSCoordinator ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Connection failed with hr = 0x%08lx", ft.hr);
// Query all (filtered) snapshot sets
CComPtr<IVssEnumObject> pIEnumProv; ft.hr = pICoord->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_PROVIDER, &pIEnumProv ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Query failed with hr = 0x%08lx", ft.hr);
// For all snapshot sets do...
VSS_OBJECT_PROP Prop; VSS_PROVIDER_PROP& Prov = Prop.Obj.Prov; for(;;) { // Get next element
ULONG ulFetched; ft.hr = pIEnumProv->Next( 1, &Prop, &ulFetched ); if ( ft.HrFailed() ) ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Next failed with hr = 0x%08lx", ft.hr); // Test if the cycle is ended
if (ft.hr == S_FALSE) { BS_ASSERT( ulFetched == 0); break; }
// Get the provider type strings
LPCWSTR pwszProviderType; switch (Prov.m_eProviderType) { case VSS_PROV_SYSTEM: pwszProviderType = LoadString( ft, IDS_PROV_TYPE_SYSTEM); break; case VSS_PROV_SOFTWARE: pwszProviderType = LoadString( ft, IDS_PROV_TYPE_SOFTWARE); break; case VSS_PROV_HARDWARE: pwszProviderType = LoadString( ft, IDS_PROV_TYPE_HARDWARE); break; default: pwszProviderType = LoadString( ft, IDS_PROV_TYPE_UNKNOWN); break; } BS_ASSERT(pwszProviderType);
// Print each snapshot set
Output( ft, IDS_PROVIDER_CONTENTS, Prov.m_pwszProviderName? Prov.m_pwszProviderName: L"", pwszProviderType, GUID_PRINTF_ARG(Prov.m_ProviderId), Prov.m_pwszProviderVersion? Prov.m_pwszProviderVersion: L"");
::CoTaskMemFree(Prov.m_pwszProviderName); ::CoTaskMemFree(Prov.m_pwszProviderVersion);
bNonEmptyResult = true; }
m_nReturnValue = bNonEmptyResult? VSS_CMDRET_SUCCESS: VSS_CMDRET_EMPTY_RESULT; }
|