You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1962 lines
68 KiB
1962 lines
68 KiB
/*++
|
|
|
|
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 "commandverifier.h"
|
|
#include "versionspecific.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"
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#define VSSADM_INFINITE_DIFFAREA 0xFFFFFFFFFFFFFFFF
|
|
|
|
#define VSS_CTX_ATTRIB_MASK 0x01F
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 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 VSS_SNAPSHOT_PROP *pVssSnapshotProp )
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdmSnapshotSetEntry::AddSnapshot" );
|
|
|
|
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;
|
|
|
|
//
|
|
// Transfer of pointer ownership
|
|
//
|
|
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
|
|
CVssAdmSnapshotSets() { };
|
|
|
|
void Initialize(
|
|
IN LONG lSnapshotContext,
|
|
IN VSS_ID FilteredSnapshotSetId,
|
|
IN VSS_ID FilteredSnapshotId,
|
|
IN VSS_ID FilteredProviderId,
|
|
IN LPCWSTR pwszFilteredForVolume
|
|
)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdmSnapshotSets::CVssAdmSnapshotSets" );
|
|
|
|
// Create the coordinator object
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VSSCoordinator,
|
|
L"Coordinator",
|
|
CLSCTX_ALL,
|
|
IID_IVssCoordinator,
|
|
(IUnknown**)&(pICoord));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Set the context
|
|
ft.hr = pICoord->SetContext( lSnapshotContext );
|
|
|
|
//
|
|
// If access denied, don't stop, it probably is a backup operator making this
|
|
// call. Continue. Also continue if E_NOTIMPL. The coordinator will use the backup context.
|
|
//
|
|
if ( ft.HrFailed() && ft.hr != E_ACCESSDENIED && ft.hr != E_NOTIMPL )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"SetContext 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, ft.hr, L"Query failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// For all snapshots do...
|
|
VSS_OBJECT_PROP Prop;
|
|
for(;;) {
|
|
// Get next element
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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;
|
|
}
|
|
|
|
// Use auto delete class to manage the snapshot properties
|
|
CVssAutoSnapshotProperties cSnap( Prop );
|
|
|
|
// If filtering, skip entry if snapshot set id is not in the specified snapshot set
|
|
if ( ( FilteredSnapshotSetId != GUID_NULL ) &&
|
|
!( cSnap->m_SnapshotSetId == FilteredSnapshotSetId ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If filtering, skip entry if snapshot id is not in the specified snapshot set
|
|
if ( ( FilteredSnapshotId != GUID_NULL ) &&
|
|
!( cSnap->m_SnapshotId == FilteredSnapshotId ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If filtering, skip entry if provider ID is not in the specified snapshot
|
|
if ( ( FilteredProviderId != GUID_NULL ) &&
|
|
!( cSnap->m_ProviderId == FilteredProviderId ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If filtering, skip entry if FOR volume is not in the specified snapshot
|
|
if ( ( pwszFilteredForVolume != NULL ) && ( pwszFilteredForVolume[0] != '\0' ) &&
|
|
( ::_wcsicmp( pwszFilteredForVolume, cSnap->m_pwszOriginalVolumeName ) != 0 ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ft.Trace( VSSDBG_VSSADMIN, L"Snapshot: %s", cSnap->m_pwszOriginalVolumeName );
|
|
|
|
// Look up the snapshot set id in the list of snapshot sets
|
|
CVssAdmSnapshotSetEntry *pcSSE;
|
|
pcSSE = m_mapSnapshotSets.Lookup( cSnap->m_SnapshotSetId );
|
|
if ( pcSSE == NULL )
|
|
{
|
|
// Haven't seen this snapshot set before, add it to list
|
|
pcSSE = new CVssAdmSnapshotSetEntry( cSnap->m_SnapshotSetId,
|
|
cSnap->m_lSnapshotsCount );
|
|
if ( pcSSE == NULL )
|
|
ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" );
|
|
if ( !m_mapSnapshotSets.Add( cSnap->m_SnapshotSetId, pcSSE ) )
|
|
{
|
|
delete pcSSE;
|
|
ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" );
|
|
}
|
|
}
|
|
|
|
// Now add the snapshot to the snapshot set. Transfer of pointer
|
|
// ownership of &Snap.
|
|
ft.hr = pcSSE->AddSnapshot( cSnap.GetPtr() );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"AddSnapshot failed" );
|
|
}
|
|
cSnap.Transferred();
|
|
}
|
|
}
|
|
|
|
~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;
|
|
};
|
|
|
|
void CVssAdminCLI::GetDifferentialSoftwareSnapshotMgmtInterface(
|
|
IN VSS_ID ProviderId,
|
|
IN IVssSnapshotMgmt *pIMgmt,
|
|
OUT IUnknown** ppItf
|
|
)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"GetDifferentialSoftwareSnapshotMgmtInterface" );
|
|
|
|
BS_ASSERT( pIMgmt != NULL );
|
|
|
|
ft.hr = pIMgmt->GetProviderMgmtInterface( ProviderId, IID_IVssDifferentialSoftwareSnapshotMgmt, ppItf );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
if ( ft.hr == E_NOINTERFACE )
|
|
{
|
|
// The provider doesn't support this interface
|
|
OutputErrorMsg( MSG_ERROR_PROVIDER_DOESNT_SUPPORT_DIFFAREAS, GetOptionValueStr( VSSADM_O_PROVIDER ) );
|
|
ft.Throw( VSSDBG_VSSADMIN, S_OK, L"Provider doesn't support diff aras");
|
|
}
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"GetProviderMgmtInterface failed with hr = 0x%08lx", ft.hr);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Implementation
|
|
|
|
|
|
void CVssAdminCLI::PrintUsage(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::PrintUsage" );
|
|
|
|
//
|
|
// Based on parsed command line type, print detailed command usage if
|
|
// eAdmCmd is valid, else print general vssadmin usage
|
|
//
|
|
if ( m_sParsedCommand.eAdmCmd != VSSADM_C_INVALID )
|
|
{
|
|
OutputMsg( g_asAdmCommands[m_sParsedCommand.eAdmCmd].lMsgDetail,
|
|
g_asAdmCommands[m_sParsedCommand.eAdmCmd].pwszMajorOption,
|
|
g_asAdmCommands[m_sParsedCommand.eAdmCmd].pwszMinorOption);
|
|
if ( g_asAdmCommands[m_sParsedCommand.eAdmCmd].bShowSSTypes )
|
|
DumpSnapshotTypes();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Print out header
|
|
//
|
|
OutputMsg( MSG_USAGE );
|
|
|
|
//
|
|
// Figure out the maximum command length to help with formatting
|
|
//
|
|
INT idx;
|
|
INT iMaxLen = 0;
|
|
|
|
|
|
for ( idx = VSSADM_C_FIRST; idx < VSSADM_C_NUM_COMMANDS; ++idx )
|
|
{
|
|
if ( dCurrentSKU & g_asAdmCommands[idx].dwSKUs )
|
|
{
|
|
size_t cCmd;
|
|
cCmd = ::wcslen( g_asAdmCommands[idx].pwszMajorOption ) +
|
|
::wcslen( g_asAdmCommands[idx].pwszMinorOption ) + 2;
|
|
if ( iMaxLen < (INT)cCmd )
|
|
iMaxLen = (INT)cCmd;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get a string to hold the string
|
|
//
|
|
CVssAutoPWSZ awszCommand;
|
|
awszCommand.Allocate( iMaxLen );
|
|
LPWSTR pwszCommand = awszCommand; // will be automatically deleted
|
|
|
|
//
|
|
// Go through the list of commands and print the general information
|
|
// about each.
|
|
//
|
|
for ( idx = VSSADM_C_FIRST; idx < VSSADM_C_NUM_COMMANDS; ++idx )
|
|
{
|
|
if ( dCurrentSKU & g_asAdmCommands[idx].dwSKUs )
|
|
{
|
|
// stick both parts of the command together
|
|
::wcscpy( pwszCommand, g_asAdmCommands[idx].pwszMajorOption );
|
|
::wcscat( pwszCommand, L" " );
|
|
::wcscat( pwszCommand, g_asAdmCommands[idx].pwszMinorOption );
|
|
// pad with spaces at the end
|
|
for ( INT i = (INT) ::wcslen( pwszCommand); i < iMaxLen; ++i )
|
|
pwszCommand[i] = L' ';
|
|
pwszCommand[iMaxLen] = L'\0';
|
|
OutputMsg( g_asAdmCommands[idx].lMsgGen, pwszCommand );
|
|
}
|
|
}
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
void CVssAdminCLI::AddDiffArea(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::AddDiffArea" );
|
|
|
|
// grab all of the options
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
LPWSTR forVolume = GetOptionValueStr( VSSADM_O_FOR );
|
|
LPWSTR onVolume = GetOptionValueStr( VSSADM_O_ON );
|
|
|
|
LONGLONG llMaxSize;
|
|
if (!GetOptionValueNum( VSSADM_O_MAXSIZE, &llMaxSize ) )
|
|
llMaxSize = VSSADM_INFINITE_DIFFAREA;
|
|
|
|
// Verify the passed-in parameters
|
|
m_pVerifier->AddDiffArea (ProviderId, forVolume, onVolume, llMaxSize, ft);
|
|
|
|
// Create a Coordinator interface
|
|
CComPtr<IVssSnapshotMgmt> pIMgmt;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VssSnapshotMgmt,
|
|
L"VssSnapshotMgmt",
|
|
CLSCTX_ALL,
|
|
IID_IVssSnapshotMgmt,
|
|
(IUnknown**)&(pIMgmt));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Get the management object
|
|
CComPtr<IVssDifferentialSoftwareSnapshotMgmt> pIDiffSnapMgmt;
|
|
GetDifferentialSoftwareSnapshotMgmtInterface( ProviderId, pIMgmt, (IUnknown**)&pIDiffSnapMgmt );
|
|
|
|
// Now add the assocation
|
|
ft.hr = pIDiffSnapMgmt->AddDiffArea(forVolume, onVolume, llMaxSize );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
switch( ft.hr )
|
|
{
|
|
case VSS_E_OBJECT_ALREADY_EXISTS:
|
|
OutputErrorMsg( MSG_ERROR_ASSOCIATION_ALREADY_EXISTS );
|
|
break;
|
|
default:
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"AddDiffArea failed with hr = 0x%08lx", ft.hr);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Print results, if needed
|
|
//
|
|
OutputMsg( MSG_INFO_ADDED_DIFFAREA );
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
void CVssAdminCLI::CreateSnapshot(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::CreateSnapshot" );
|
|
|
|
// Grab all parameters to the function
|
|
LONG lSnapshotContext = (dCurrentSKU & SKU_INT) ?
|
|
DetermineSnapshotType( GetOptionValueStr( VSSADM_O_SNAPTYPE ) ) :
|
|
VSS_CTX_CLIENT_ACCESSIBLE;
|
|
|
|
BS_ASSERT( lSnapshotContext | VSS_VOLSNAP_ATTR_NO_WRITERS );
|
|
|
|
LPWSTR forVolume = GetOptionValueStr( VSSADM_O_FOR );
|
|
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
LONGLONG llTimeout = 0;
|
|
GetOptionValueNum (VSSADM_O_AUTORETRY, &llTimeout, false);
|
|
|
|
// Verify the passed-in parameters
|
|
m_pVerifier->CreateSnapshot (lSnapshotContext, forVolume, ProviderId, llTimeout, ft);
|
|
|
|
// Create the coordinator object
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VSSCoordinator,
|
|
L"Coordinator",
|
|
CLSCTX_ALL,
|
|
IID_IVssCoordinator,
|
|
(IUnknown**)&(pICoord));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
ft.hr = pICoord->SetContext(lSnapshotContext);
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Error from SetContext(0x%x) hr = 0x%08lx", lSnapshotContext, ft.hr);
|
|
|
|
CComPtr<IVssAsync> pAsync;
|
|
VSS_ID SnapshotSetId = GUID_NULL;
|
|
|
|
// Starting a new snapshot set. Note, if another process is creating snapshots, then
|
|
// this will fail. If AutoRetry was specified, then retry the start snapshot set for
|
|
// that the specified number of minutes.
|
|
if (llTimeout > 0)
|
|
{
|
|
LARGE_INTEGER liPerfCount;
|
|
(void)QueryPerformanceCounter( &liPerfCount );
|
|
::srand( liPerfCount.LowPart );
|
|
DWORD dwTickcountStart = ::GetTickCount();
|
|
do
|
|
{
|
|
ft.hr = pICoord->StartSnapshotSet(&SnapshotSetId);
|
|
if ( ft.HrFailed() )
|
|
{
|
|
if ( ft.hr == VSS_E_SNAPSHOT_SET_IN_PROGRESS &&
|
|
( (LONGLONG)( ::GetTickCount() - dwTickcountStart ) < ( llTimeout * 1000 * 60 ) ) )
|
|
{
|
|
static dwMSec = 250; // Starting retry time
|
|
if ( dwMSec < 10000 )
|
|
{
|
|
dwMSec += ::rand() % 750;
|
|
}
|
|
ft.Trace( VSSDBG_VSSADMIN, L"Snapshot already in progress, retrying in %u millisecs", dwMSec );
|
|
Sleep( dwMSec );
|
|
}
|
|
else
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Error from StartSnapshotSet hr = 0x%08lx", ft.hr);
|
|
}
|
|
}
|
|
} while ( ft.HrFailed() );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Error right away with out a timeout when there is another snapshot in progress.
|
|
//
|
|
ft.hr = pICoord->StartSnapshotSet(&SnapshotSetId);
|
|
if ( ft.HrFailed() )
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Error from StartSnapshotSet hr = 0x%08lx", ft.hr);
|
|
}
|
|
}
|
|
|
|
// Add the volume to the snapshot set
|
|
VSS_ID SnapshotId = GUID_NULL;
|
|
ft.hr = pICoord->AddToSnapshotSet(
|
|
forVolume,
|
|
ProviderId,
|
|
&SnapshotId);
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Error from AddToSnapshotSet hr = 0x%08lx", ft.hr);
|
|
|
|
ft.hr = S_OK;
|
|
pAsync = NULL;
|
|
ft.hr = pICoord->DoSnapshotSet(NULL, &pAsync);
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
L"Error from DoSnapshotSet hr = 0x%08lx", ft.hr);
|
|
|
|
ft.hr = pAsync->Wait();
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
L"Error from Wait hr = 0x%08lx", ft.hr);
|
|
|
|
HRESULT hrStatus;
|
|
ft.hr = pAsync->QueryStatus(&hrStatus, NULL);
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
L"Error from QueryStatus hr = 0x%08lx", ft.hr);
|
|
|
|
//
|
|
// If VSS failed to create the snapshot, it's result code is in hrStatus. Process
|
|
// it.
|
|
//
|
|
ft.hr = hrStatus;
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
L"QueryStatus hrStatus parameter returned error, hr = 0x%08lx", ft.hr);
|
|
|
|
//
|
|
// Print results
|
|
//
|
|
VSS_SNAPSHOT_PROP sSSProp;
|
|
ft.hr = pICoord->GetSnapshotProperties( SnapshotId, &sSSProp );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
L"Error from GetId hr = 0x%08lx", ft.hr);
|
|
|
|
CVssAutoPWSZ awszSnapshotId( ::GuidToString( SnapshotId ) );
|
|
|
|
OutputMsg( MSG_INFO_SNAPSHOT_CREATED, forVolume,
|
|
(LPWSTR)awszSnapshotId, sSSProp.m_pwszSnapshotDeviceObject );
|
|
|
|
::VssFreeSnapshotProperties(&sSSProp);
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
void CVssAdminCLI::DisplayDiffAreasPrivate(
|
|
IVssEnumMgmtObject *pIEnumMgmt
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DisplayDiffAreasPrivate" );
|
|
|
|
// For all diffareas do...
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_DIFF_AREA_PROP& DiffArea = Prop.Obj.DiffArea;
|
|
for(;;)
|
|
{
|
|
// Get next element
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumMgmt->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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;
|
|
}
|
|
|
|
|
|
CVssAutoPWSZ awszVolumeName( DiffArea.m_pwszVolumeName );
|
|
CVssAutoPWSZ awszDiffAreaVolumeName( DiffArea.m_pwszDiffAreaVolumeName );
|
|
CVssAutoPWSZ awszUsedSpace( FormatNumber( DiffArea.m_llUsedDiffSpace ) );
|
|
CVssAutoPWSZ awszAllocatedSpace( FormatNumber( DiffArea.m_llAllocatedDiffSpace ) );
|
|
CVssAutoPWSZ awszMaxSpace( FormatNumber( DiffArea.m_llMaximumDiffSpace ) );
|
|
LPCWSTR pwszVolumeDisplayName = GetVolumeDisplayName( awszVolumeName );
|
|
LPCWSTR pwszDiffAreaVolumeDisplayName = GetVolumeDisplayName( awszDiffAreaVolumeName );
|
|
|
|
OutputMsg( MSG_INFO_SNAPSHOT_STORAGE_CONTENTS,
|
|
pwszVolumeDisplayName,
|
|
(LPWSTR)awszVolumeName,
|
|
pwszDiffAreaVolumeDisplayName,
|
|
(LPWSTR)awszDiffAreaVolumeName,
|
|
(LPWSTR)awszUsedSpace,
|
|
(LPWSTR)awszAllocatedSpace,
|
|
(LPWSTR)awszMaxSpace
|
|
);
|
|
}
|
|
}
|
|
|
|
void CVssAdminCLI::ListDiffAreas(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ListDiffAreas" );
|
|
|
|
// Grab all parameters
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
LPWSTR forVolume = GetOptionValueStr (VSSADM_O_FOR);
|
|
LPWSTR onVolume = GetOptionValueStr (VSSADM_O_ON);
|
|
|
|
// Verify all parameters
|
|
m_pVerifier->ListDiffAreas (ProviderId, forVolume, onVolume, ft);
|
|
|
|
// Create a Coordinator interface
|
|
CComPtr<IVssSnapshotMgmt> pIMgmt;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VssSnapshotMgmt,
|
|
L"VssSnapshotMgmt",
|
|
CLSCTX_ALL,
|
|
IID_IVssSnapshotMgmt,
|
|
(IUnknown**)&(pIMgmt));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Get the management object
|
|
CComPtr<IVssDifferentialSoftwareSnapshotMgmt> pIDiffSnapMgmt;
|
|
GetDifferentialSoftwareSnapshotMgmtInterface( ProviderId, pIMgmt, (IUnknown**)&pIDiffSnapMgmt );
|
|
|
|
// See if query by for volume
|
|
if (forVolume != NULL )
|
|
{
|
|
// Query by For volume
|
|
CComPtr<IVssEnumMgmtObject> pIEnumMgmt;
|
|
ft.hr = pIDiffSnapMgmt->QueryDiffAreasForVolume(
|
|
forVolume,
|
|
&pIEnumMgmt );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"QueryDiffAreasForVolume failed, hr = 0x%08lx", ft.hr);
|
|
|
|
if ( ft.hr == S_FALSE )
|
|
// empty query
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::ListDiffareas: No diffareas found that satisfy the query" );
|
|
|
|
DisplayDiffAreasPrivate( pIEnumMgmt );
|
|
}
|
|
else if (onVolume != NULL )
|
|
{
|
|
// Query by On volume
|
|
CComPtr<IVssEnumMgmtObject> pIEnumMgmt;
|
|
ft.hr = pIDiffSnapMgmt->QueryDiffAreasOnVolume(
|
|
onVolume,
|
|
&pIEnumMgmt );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"QueryDiffAreasOnVolume failed, hr = 0x%08lx", ft.hr);
|
|
|
|
if ( ft.hr == S_FALSE )
|
|
// empty query
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::ListDiffareas: No diffareas found that satisfy the query" );
|
|
|
|
DisplayDiffAreasPrivate( pIEnumMgmt );
|
|
}
|
|
else
|
|
{
|
|
// Query all diff areas
|
|
|
|
BOOL bEmptyQuery = TRUE;
|
|
|
|
//
|
|
// Get the list of all volumes
|
|
//
|
|
CComPtr<IVssEnumMgmtObject> pIEnumMgmt;
|
|
ft.hr = pIMgmt->QueryVolumesSupportedForSnapshots(
|
|
ProviderId,
|
|
VSS_CTX_ALL,
|
|
&pIEnumMgmt );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"QueryVolumesSupportedForSnapshots failed, hr = 0x%08lx", ft.hr);
|
|
|
|
if ( ft.hr == S_FALSE )
|
|
// empty query
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::ListDiffareas: No diffareas found that satisfy the query" );
|
|
|
|
//
|
|
// Query each volume to see if diff areas exist.
|
|
//
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_VOLUME_PROP& VolProp = Prop.Obj.Vol;
|
|
for(;;)
|
|
{
|
|
// Get next element
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumMgmt->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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;
|
|
}
|
|
|
|
CVssAutoPWSZ awszVolumeName( VolProp.m_pwszVolumeName );
|
|
CVssAutoPWSZ awszVolumeDisplayName( VolProp.m_pwszVolumeDisplayName );
|
|
|
|
// For all volumes do...
|
|
CComPtr<IVssEnumMgmtObject> pIEnumMgmtDiffArea;
|
|
ft.hr = pIDiffSnapMgmt->QueryDiffAreasForVolume(
|
|
awszVolumeName,
|
|
&pIEnumMgmtDiffArea );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"QueryDiffAreasForVolume failed, hr = 0x%08lx", ft.hr);
|
|
}
|
|
|
|
if ( ft.hr == S_FALSE )
|
|
{
|
|
// empty query
|
|
continue;
|
|
}
|
|
|
|
DisplayDiffAreasPrivate( pIEnumMgmtDiffArea );
|
|
bEmptyQuery = FALSE;
|
|
}
|
|
if ( bEmptyQuery )
|
|
// empty query
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::ListDiffareas: No diffareas found that satisfy the query" );
|
|
}
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
void CVssAdminCLI::ListSnapshots(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ListSnapshots" );
|
|
|
|
// gather parameters
|
|
LONG lSnapshotContext = (dCurrentSKU & SKU_INT) ?
|
|
DetermineSnapshotType( GetOptionValueStr( VSSADM_O_SNAPTYPE ) ) :
|
|
VSS_CTX_ALL;
|
|
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
LPCWSTR forVolume = GetOptionValueStr( VSSADM_O_FOR );
|
|
|
|
bool bNonEmptyResult = false;
|
|
|
|
// --- get the set id
|
|
VSS_ID guidSSID = GUID_NULL;
|
|
if ( GetOptionValueStr( VSSADM_O_SET ) != NULL &&
|
|
!ScanGuid( GetOptionValueStr( VSSADM_O_SET ), guidSSID ))
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION_VALUE,
|
|
L"CVssAdminCLI::ListSnapshots: invalid snapshot set ID: %s",
|
|
GetOptionValueStr( VSSADM_O_SET ) );
|
|
}
|
|
|
|
// --- get the snapshot id
|
|
VSS_ID guidSnapID = GUID_NULL;
|
|
if ( GetOptionValueStr( VSSADM_O_SNAPSHOT ) != NULL &&
|
|
!ScanGuid( GetOptionValueStr( VSSADM_O_SNAPSHOT ), guidSnapID ))
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION_VALUE,
|
|
L"CVssAdminCLI::ListSnapshots: invalid snapshot ID: %s",
|
|
GetOptionValueStr( VSSADM_O_SNAPSHOT ) );
|
|
}
|
|
|
|
// verify the parameters
|
|
m_pVerifier->ListSnapshots (lSnapshotContext, ProviderId, forVolume, guidSnapID, guidSSID, ft);
|
|
|
|
// See if we have to filter by volume name
|
|
WCHAR wszVolumeNameInternal[x_nLengthOfVolMgmtVolumeName + 1] = L"";
|
|
if (forVolume != NULL )
|
|
{
|
|
// Calculate the unique volume name, just to make sure that we have the right path
|
|
// If FOR volume name starts with the '\', assume it is already in the correct volume name format.
|
|
// This is important for transported volumes since GetVolumeNameForVolumeMountPointW() won't work.
|
|
if ( forVolume[0] != L'\\' )
|
|
{
|
|
if (!::GetVolumeNameForVolumeMountPointW(forVolume,
|
|
wszVolumeNameInternal, ARRAY_LEN(wszVolumeNameInternal)))
|
|
ft.Throw( VSSDBG_COORD, VSS_E_OBJECT_NOT_FOUND,
|
|
L"GetVolumeNameForVolumeMountPoint(%s,...) "
|
|
L"failed with error code 0x%08lx", forVolume, ::GetLastError());
|
|
}
|
|
else
|
|
{
|
|
::wcsncpy( wszVolumeNameInternal, forVolume, STRING_LEN(wszVolumeNameInternal) );
|
|
wszVolumeNameInternal[x_nLengthOfVolMgmtVolumeName] = L'\0';
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we have to filter by provider
|
|
//
|
|
|
|
// Query the snapshots
|
|
CVssAdmSnapshotSets cVssAdmSS;
|
|
cVssAdmSS.Initialize( lSnapshotContext, guidSSID, guidSnapID, ProviderId, wszVolumeNameInternal );
|
|
|
|
INT iSnapshotSetCount = cVssAdmSS.GetSnapshotSetCount();
|
|
|
|
// If there are no present snapshots then display a message.
|
|
if (iSnapshotSetCount == 0) {
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::ListSnapshots: No snapshots found that satisfy the query");
|
|
}
|
|
|
|
// For all snapshot sets do...
|
|
for ( INT iSSS = 0; iSSS < iSnapshotSetCount; ++iSSS )
|
|
{
|
|
CVssAdmSnapshotSetEntry *pcSSE;
|
|
|
|
pcSSE = cVssAdmSS.GetSnapshotSetAt( iSSS );
|
|
BS_ASSERT( pcSSE != NULL );
|
|
|
|
CVssAutoPWSZ awszGuid( ::GuidToString( pcSSE->GetSnapshotSetId() ) ) ;
|
|
CVssAutoPWSZ awszDateTime( ::DateTimeToString( &( pcSSE->GetSnapshotAt( 0 )->m_tsCreationTimestamp ) ) );
|
|
|
|
// Print each snapshot set
|
|
OutputMsg(
|
|
MSG_INFO_SNAPSHOT_SET_HEADER,
|
|
(LPWSTR)awszGuid,
|
|
pcSSE->GetOriginalSnapshotCount(),
|
|
(LPWSTR)awszDateTime );
|
|
|
|
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( pSnap->m_ProviderId );
|
|
CVssAutoPWSZ awszAttributeStr( BuildSnapshotAttributeDisplayString( pSnap->m_lSnapshotAttributes ) );
|
|
CVssAutoPWSZ awszSnapshotType( DetermineSnapshotType( pSnap->m_lSnapshotAttributes ) );
|
|
|
|
// Print each snapshot
|
|
CVssAutoPWSZ awszSnapGuid( ::GuidToString( pSnap->m_SnapshotId ) );
|
|
LPCWSTR pwszVolumeDisplayName = GetVolumeDisplayName( pSnap->m_pwszOriginalVolumeName );
|
|
|
|
OutputMsg(
|
|
MSG_INFO_SNAPSHOT_CONTENTS,
|
|
(LPWSTR)awszSnapGuid,
|
|
pwszVolumeDisplayName ? pwszVolumeDisplayName : L"?",
|
|
pSnap->m_pwszOriginalVolumeName,
|
|
pSnap->m_pwszSnapshotDeviceObject,
|
|
pSnap->m_pwszOriginatingMachine ? pSnap->m_pwszOriginatingMachine : L"",
|
|
pSnap->m_pwszServiceMachine ? pSnap->m_pwszServiceMachine : L"", // fix this when the idl file changes
|
|
pwszProviderName ? pwszProviderName : L"?",
|
|
(LPWSTR)awszSnapshotType,
|
|
(LPWSTR)awszAttributeStr
|
|
);
|
|
|
|
bNonEmptyResult = true;
|
|
}
|
|
}
|
|
|
|
m_nReturnValue = bNonEmptyResult? VSS_CMDRET_SUCCESS: VSS_CMDRET_EMPTY_RESULT;
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::DumpSnapshotTypes(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DumpSnapshotTypes" );
|
|
|
|
//
|
|
// Dump list of snapshot types based on SKU
|
|
//
|
|
INT idx;
|
|
|
|
// Determine type of snapshot
|
|
for ( idx = 0; g_asAdmTypeNames[idx].pwszName != NULL; ++idx )
|
|
{
|
|
if ( dCurrentSKU & g_asAdmTypeNames[idx].dwSKUs )
|
|
{
|
|
OutputMsg (g_asAdmTypeNames[idx].pwszDescription,
|
|
g_asAdmTypeNames[idx].pwszName);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CVssAdminCLI::ListWriters(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ListWriters" );
|
|
|
|
// verify the parameters
|
|
m_pVerifier->ListWriters (ft);
|
|
|
|
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, ft.hr, L"CreateVssBackupComponents failed with hr = 0x%08lx", ft.hr);
|
|
|
|
ft.hr = pBackupComp->InitializeForBackup();
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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, ft.hr, 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 < x_nMaxRetriesCount; nRetries++ ) {
|
|
|
|
// Wait a little
|
|
::Sleep(x_nPollingInterval);
|
|
|
|
// Check if finished
|
|
INT nReserved = 0;
|
|
ft.hr = pAsync->QueryStatus(
|
|
&hrReturned,
|
|
&nReserved
|
|
);
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr,
|
|
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, ft.hr,
|
|
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) {
|
|
OutputMsg( MSG_INFO_WAITING_RESPONSES );
|
|
ft.hr = pAsync->Wait();
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"IVssAsync::Wait failed with hr = 0x%08lx", ft.hr);
|
|
}
|
|
|
|
pAsync = NULL;
|
|
|
|
// Free the writer metadata
|
|
ft.hr = pBackupComp->FreeWriterMetadata();
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"FreeWriterMetadata failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Gather the status of all writers
|
|
ft.hr = pBackupComp->GatherWriterStatus(&pAsync);
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"GatherWriterStatus failed with hr = 0x%08lx", ft.hr);
|
|
|
|
ft.hr = pAsync->Wait();
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"IVssAsync::Wait failed with hr = 0x%08lx", ft.hr);
|
|
|
|
pAsync = NULL;
|
|
|
|
ft.hr = pBackupComp->GetWriterStatusCount(&unWritersCount);
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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 = GUID_NULL;
|
|
VSS_ID idWriter = GUID_NULL;
|
|
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, ft.hr, L"GetWriterStatus failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Get the status description strings
|
|
LPCWSTR pwszStatusDescription;
|
|
switch (eStatus)
|
|
{
|
|
case VSS_WS_STABLE:
|
|
pwszStatusDescription = LoadString( IDS_WRITER_STATUS_STABLE);
|
|
break;
|
|
case VSS_WS_WAITING_FOR_FREEZE:
|
|
pwszStatusDescription = LoadString( IDS_WRITER_STATUS_WAITING_FOR_FREEZE);
|
|
break;
|
|
case VSS_WS_WAITING_FOR_THAW:
|
|
pwszStatusDescription = LoadString( IDS_WRITER_STATUS_FROZEN);
|
|
break;
|
|
case VSS_WS_WAITING_FOR_POST_SNAPSHOT:
|
|
pwszStatusDescription = LoadString( IDS_WRITER_STATUS_WAITING_FOR_POST_SNAPSHOT);
|
|
break;
|
|
case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
|
|
pwszStatusDescription = LoadString( 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:
|
|
case VSS_WS_FAILED_AT_POST_SNAPSHOT:
|
|
case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
|
|
case VSS_WS_FAILED_AT_PRE_RESTORE:
|
|
case VSS_WS_FAILED_AT_POST_RESTORE:
|
|
pwszStatusDescription = LoadString( IDS_WRITER_STATUS_FAILED);
|
|
break;
|
|
default:
|
|
pwszStatusDescription = LoadString( IDS_WRITER_STATUS_UNKNOWN);
|
|
break;
|
|
}
|
|
BS_ASSERT(pwszStatusDescription);
|
|
|
|
LPCWSTR pwszWriterError;
|
|
switch ( hrWriterFailure )
|
|
{
|
|
case S_OK:
|
|
pwszWriterError = LoadString ( IDS_WRITER_ERROR_SUCCESS );
|
|
break;
|
|
case VSS_E_WRITER_NOT_RESPONDING:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_NOT_RESPONDING );
|
|
break;
|
|
case VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_INCONSISTENTSNAPSHOT);
|
|
break;
|
|
case VSS_E_WRITERERROR_OUTOFRESOURCES:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_OUTOFRESOURCES);
|
|
break;
|
|
case VSS_E_WRITERERROR_TIMEOUT:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_TIMEOUT);
|
|
break;
|
|
case VSS_E_WRITERERROR_RETRYABLE:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_RETRYABLE);
|
|
break;
|
|
case VSS_E_WRITERERROR_NONRETRYABLE:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_NONRETRYABLE);
|
|
break;
|
|
default:
|
|
pwszWriterError = LoadString( IDS_WRITER_ERROR_UNEXPECTED);
|
|
ft.Trace( VSSDBG_VSSADMIN, L"Unexpected writer error failure: 0x%08x", hrWriterFailure );
|
|
break;
|
|
}
|
|
|
|
CVssAutoPWSZ awszWriterId( ::GuidToString( idWriter ) );
|
|
CVssAutoPWSZ awszInstanceId( ::GuidToString( idInstance ) );
|
|
|
|
OutputMsg( MSG_INFO_WRITER_CONTENTS,
|
|
(LPWSTR)bstrWriter ? (LPWSTR)bstrWriter : L"",
|
|
(LPWSTR)awszWriterId,
|
|
(LPWSTR)awszInstanceId,
|
|
(INT)eStatus,
|
|
pwszStatusDescription,
|
|
pwszWriterError
|
|
);
|
|
|
|
bNonEmptyResult = true;
|
|
}
|
|
|
|
ft.hr = pBackupComp->FreeWriterStatus();
|
|
if (ft.HrFailed())
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"FreeWriterStatus failed with hr = 0x%08lx", ft.hr);
|
|
|
|
m_nReturnValue = bNonEmptyResult? VSS_CMDRET_SUCCESS: VSS_CMDRET_EMPTY_RESULT;
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::ListProviders(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ListProviders" );
|
|
|
|
// verify the parameters
|
|
m_pVerifier->ListProviders (ft);
|
|
|
|
bool bNonEmptyResult = false;
|
|
|
|
// Create the coordinator object
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VSSCoordinator,
|
|
L"Coordinator",
|
|
CLSCTX_ALL,
|
|
IID_IVssCoordinator,
|
|
(IUnknown**)&(pICoord));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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, ft.hr, 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, ft.hr, 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( IDS_PROV_TYPE_SYSTEM);
|
|
break;
|
|
case VSS_PROV_SOFTWARE:
|
|
pwszProviderType = LoadString( IDS_PROV_TYPE_SOFTWARE);
|
|
break;
|
|
case VSS_PROV_HARDWARE:
|
|
pwszProviderType = LoadString( IDS_PROV_TYPE_HARDWARE);
|
|
break;
|
|
default:
|
|
pwszProviderType = LoadString( IDS_PROV_TYPE_UNKNOWN);
|
|
break;
|
|
}
|
|
BS_ASSERT(pwszProviderType);
|
|
|
|
// Print each snapshot set
|
|
CVssAutoPWSZ awszProviderId( ::GuidToString( Prov.m_ProviderId ) );
|
|
CVssAutoPWSZ awszProviderName( Prov.m_pwszProviderName );
|
|
CVssAutoPWSZ awszProviderVersion( Prov.m_pwszProviderVersion );
|
|
|
|
OutputMsg( MSG_INFO_PROVIDER_CONTENTS,
|
|
(LPWSTR)awszProviderName ? (LPWSTR)awszProviderName: L"",
|
|
pwszProviderType,
|
|
(LPWSTR)awszProviderId,
|
|
(LPWSTR)awszProviderVersion ? (LPWSTR)awszProviderVersion: L"");
|
|
|
|
bNonEmptyResult = true;
|
|
}
|
|
|
|
m_nReturnValue = bNonEmptyResult? VSS_CMDRET_SUCCESS: VSS_CMDRET_EMPTY_RESULT;
|
|
}
|
|
|
|
void CVssAdminCLI::ListVolumes(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ListVolumes" );
|
|
|
|
// gather the parameters
|
|
LONG lContext = (dCurrentSKU & SKU_INT) ?
|
|
DetermineSnapshotType( GetOptionValueStr( VSSADM_O_SNAPTYPE ) ) :
|
|
VSS_CTX_CLIENT_ACCESSIBLE;
|
|
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
// verify the parameters
|
|
m_pVerifier->ListVolumes (ProviderId, lContext, ft);
|
|
|
|
// Create a Coordinator interface
|
|
CComPtr<IVssSnapshotMgmt> pIMgmt;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VssSnapshotMgmt,
|
|
L"VssSnapshotMgmt",
|
|
CLSCTX_ALL,
|
|
IID_IVssSnapshotMgmt,
|
|
(IUnknown**)&(pIMgmt));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
//
|
|
// Get the list of all volumes
|
|
//
|
|
CComPtr<IVssEnumMgmtObject> pIEnumMgmt;
|
|
ft.hr = pIMgmt->QueryVolumesSupportedForSnapshots(
|
|
ProviderId,
|
|
lContext,
|
|
&pIEnumMgmt );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"QueryVolumesSupportedForSnapshots failed, hr = 0x%08lx", ft.hr);
|
|
|
|
if ( ft.hr == S_FALSE )
|
|
// empty query
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::ListVolumes: No volumes found that satisfy the query" );
|
|
|
|
//
|
|
// Query each volume to see if diff areas exist.
|
|
//
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_VOLUME_PROP& VolProp = Prop.Obj.Vol;
|
|
|
|
for(;;)
|
|
{
|
|
// Get next element
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumMgmt->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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;
|
|
}
|
|
|
|
CVssAutoPWSZ awszVolumeName( VolProp.m_pwszVolumeName );
|
|
CVssAutoPWSZ awszVolumeDisplayName( VolProp.m_pwszVolumeDisplayName );
|
|
OutputMsg( MSG_INFO_VOLUME_CONTENTS, (LPWSTR)awszVolumeDisplayName, (LPWSTR)awszVolumeName );
|
|
}
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
void CVssAdminCLI::ResizeDiffArea(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ResizeDiffArea" );
|
|
|
|
// gather the parameters
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
LPWSTR forVolume = GetOptionValueStr( VSSADM_O_FOR );
|
|
LPWSTR onVolume = GetOptionValueStr( VSSADM_O_ON );
|
|
LONGLONG llMaxSize = 0;
|
|
if (!GetOptionValueNum( VSSADM_O_MAXSIZE, &llMaxSize ))
|
|
{
|
|
llMaxSize = VSSADM_INFINITE_DIFFAREA;
|
|
}
|
|
|
|
// verify the parameters
|
|
m_pVerifier->ResizeDiffArea (ProviderId, forVolume, onVolume, llMaxSize, ft);
|
|
|
|
// Create a Coordinator interface
|
|
CComPtr<IVssSnapshotMgmt> pIMgmt;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VssSnapshotMgmt,
|
|
L"VssSnapshotMgmt",
|
|
CLSCTX_ALL,
|
|
IID_IVssSnapshotMgmt,
|
|
(IUnknown**)&(pIMgmt));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Get the management object
|
|
CComPtr<IVssDifferentialSoftwareSnapshotMgmt> pIDiffSnapMgmt;
|
|
GetDifferentialSoftwareSnapshotMgmtInterface( ProviderId, pIMgmt, (IUnknown**)&pIDiffSnapMgmt );
|
|
|
|
// Now add the assocation
|
|
ft.hr = pIDiffSnapMgmt->ChangeDiffAreaMaximumSize(forVolume, onVolume, llMaxSize );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
if ( ft.hr == VSS_E_OBJECT_NOT_FOUND ) // should be VSS_E_MAXIMUM_DIFFAREA_ASSOCIATIONS
|
|
{
|
|
// The associations was not found
|
|
OutputErrorMsg( MSG_ERROR_ASSOCIATION_NOT_FOUND );
|
|
return;
|
|
}
|
|
else
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"ResizeDiffArea failed with hr = 0x%08lx", ft.hr);
|
|
}
|
|
|
|
//
|
|
// Print results, if needed
|
|
//
|
|
OutputMsg( MSG_INFO_RESIZED_DIFFAREA );
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::DeleteDiffAreas(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DeleteDiffAreas" );
|
|
|
|
// gather the parameters
|
|
VSS_ID ProviderId = GUID_NULL;
|
|
GetProviderId( &ProviderId );
|
|
|
|
LPWSTR forVolume = GetOptionValueStr( VSSADM_O_FOR );
|
|
LPWSTR onVolume = GetOptionValueStr( VSSADM_O_ON );
|
|
|
|
// verify the parameters
|
|
m_pVerifier->DeleteDiffAreas (ProviderId, forVolume, onVolume, IsQuiet() == TRUE, ft);
|
|
|
|
// Create a Coordinator interface
|
|
CComPtr<IVssSnapshotMgmt> pIMgmt;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VssSnapshotMgmt,
|
|
L"VssSnapshotMgmt",
|
|
CLSCTX_ALL,
|
|
IID_IVssSnapshotMgmt,
|
|
(IUnknown**)&(pIMgmt));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Get the management object
|
|
CComPtr<IVssDifferentialSoftwareSnapshotMgmt> pIDiffSnapMgmt;
|
|
GetDifferentialSoftwareSnapshotMgmtInterface( ProviderId, pIMgmt, (IUnknown**)&pIDiffSnapMgmt );
|
|
|
|
//
|
|
// See if the on option was provided. If not, determine what the on value is:
|
|
//
|
|
CVssAutoPWSZ awszOnVol;
|
|
|
|
if (onVolume == NULL )
|
|
{
|
|
// Need to query the association to get the on value...
|
|
CComPtr<IVssEnumMgmtObject> pIEnumMgmt;
|
|
ft.hr = pIDiffSnapMgmt->QueryDiffAreasForVolume(
|
|
forVolume,
|
|
&pIEnumMgmt );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"QueryDiffAreasForVolume failed, hr = 0x%08lx", ft.hr);
|
|
|
|
if ( ft.hr == S_FALSE )
|
|
{
|
|
// empty query
|
|
OutputErrorMsg( MSG_ERROR_ASSOCIATION_NOT_FOUND );
|
|
return;
|
|
}
|
|
|
|
|
|
VSS_MGMT_OBJECT_PROP Prop;
|
|
VSS_DIFF_AREA_PROP& DiffArea = Prop.Obj.DiffArea;
|
|
// Get next element
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumMgmt->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Next failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Test if the cycle is finished
|
|
if (ft.hr == S_FALSE)
|
|
{
|
|
OutputErrorMsg( MSG_ERROR_ASSOCIATION_NOT_FOUND );
|
|
return;
|
|
}
|
|
|
|
::VssFreeString( DiffArea.m_pwszVolumeName );
|
|
|
|
CVssAutoPWSZ awszDiffAreaVolumeName( DiffArea.m_pwszDiffAreaVolumeName );
|
|
|
|
// Save it away in the auto delete object.
|
|
awszOnVol.CopyFrom( awszDiffAreaVolumeName );
|
|
onVolume = awszOnVol;
|
|
}
|
|
|
|
// Now delete the assocation by changing the size to zero
|
|
ft.hr = pIDiffSnapMgmt->ChangeDiffAreaMaximumSize(
|
|
forVolume,
|
|
onVolume,
|
|
0 );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
if ( ft.hr == VSS_E_OBJECT_NOT_FOUND ) // should be VSS_E_MAXIMUM_DIFFAREA_ASSOCIATIONS
|
|
{
|
|
// The associations was not found
|
|
OutputErrorMsg( MSG_ERROR_ASSOCIATION_NOT_FOUND );
|
|
return;
|
|
}
|
|
else if ( ft.hr == VSS_E_VOLUME_IN_USE )
|
|
{
|
|
// Can't delete associations that are in use
|
|
OutputErrorMsg( MSG_ERROR_ASSOCIATION_IS_IN_USE );
|
|
return;
|
|
}
|
|
else
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"ResizeDiffArea to 0 failed with hr = 0x%08lx", ft.hr);
|
|
}
|
|
|
|
//
|
|
// Print results, if needed
|
|
//
|
|
if ( !IsQuiet() )
|
|
{
|
|
OutputMsg( MSG_INFO_DELETED_DIFFAREAS );
|
|
}
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
void CVssAdminCLI::DeleteSnapshots(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DeleteSnapshots" );
|
|
|
|
// gather the parameters
|
|
LONG lContext = (dCurrentSKU & SKU_INT) ?
|
|
DetermineSnapshotType( GetOptionValueStr( VSSADM_O_SNAPTYPE ) ) :
|
|
VSS_CTX_CLIENT_ACCESSIBLE;
|
|
|
|
|
|
LPCWSTR forVolume = GetOptionValueStr( VSSADM_O_FOR );
|
|
BOOL oldest = GetOptionValueBool( VSSADM_O_OLDEST );
|
|
BOOL all = GetOptionValueBool(VSSADM_O_ALL);
|
|
|
|
VSS_ID SnapshotId = GUID_NULL;
|
|
if (GetOptionValueStr (VSSADM_O_SNAPSHOT) &&
|
|
!ScanGuid (GetOptionValueStr (VSSADM_O_SNAPSHOT), SnapshotId))
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION_VALUE,
|
|
L"CVssAdminCLI::DeleteSnapshots: Invalid snapshot id" );
|
|
}
|
|
|
|
// verify the parameters
|
|
m_pVerifier->DeleteSnapshots (lContext, forVolume, all == TRUE, oldest==TRUE, SnapshotId, IsQuiet()==TRUE, ft);
|
|
|
|
LONG lNumDeleted = 0;
|
|
|
|
if ( GetOptionValueStr( VSSADM_O_SNAPSHOT ) )
|
|
{
|
|
//
|
|
// Let's try to delete the snapshot
|
|
//
|
|
if ( PromptUserForConfirmation( MSG_INFO_PROMPT_USER_FOR_DELETE_SNAPSHOTS, 1 ) )
|
|
{
|
|
// Create the coordinator object
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VSSCoordinator,
|
|
L"Coordinator",
|
|
CLSCTX_ALL,
|
|
IID_IVssCoordinator,
|
|
(IUnknown**)&(pICoord));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Set all context
|
|
ft.hr = pICoord->SetContext( lContext );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"SetContext failed with hr = 0x%08lx", ft.hr);
|
|
|
|
VSS_ID NondeletedSnapshotId = GUID_NULL;
|
|
|
|
ft.hr = pICoord->DeleteSnapshots(
|
|
SnapshotId,
|
|
VSS_OBJECT_SNAPSHOT,
|
|
TRUE,
|
|
&lNumDeleted,
|
|
&NondeletedSnapshotId );
|
|
if ( ft.hr == VSS_E_OBJECT_NOT_FOUND )
|
|
{
|
|
OutputErrorMsg( MSG_ERROR_SNAPSHOT_NOT_FOUND, GetOptionValueStr( VSSADM_O_SNAPSHOT ) );
|
|
}
|
|
else if ( ft.HrFailed() )
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"DeleteSnapshots failed with hr = 0x%08lx", ft.hr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BS_ASSERT (GetOptionValueStr(VSSADM_O_SNAPSHOT) == NULL);
|
|
|
|
// Calculate the unique volume name, just to make sure that we have the right path
|
|
WCHAR wszVolumeNameInternal[x_nLengthOfVolMgmtVolumeName + 1];
|
|
memset (wszVolumeNameInternal, 0, sizeof(wszVolumeNameInternal));
|
|
|
|
// If FOR volume name starts with the '\', assume it is already in the correct volume name format.
|
|
// This is important for transported volumes since GetVolumeNameForVolumeMountPointW() won't work.
|
|
if (forVolume != NULL && forVolume[0] != L'\\' )
|
|
{
|
|
if (!::GetVolumeNameForVolumeMountPointW( forVolume,
|
|
wszVolumeNameInternal, ARRAY_LEN(wszVolumeNameInternal)))
|
|
ft.Throw( VSSDBG_COORD, VSS_E_OBJECT_NOT_FOUND,
|
|
L"GetVolumeNameForVolumeMountPoint(%s,...) "
|
|
L"failed with error code 0x%08lx", GetOptionValueStr( VSSADM_O_FOR ), ::GetLastError());
|
|
}
|
|
else if (forVolume != NULL)
|
|
{
|
|
::wcsncpy( wszVolumeNameInternal, forVolume, STRING_LEN(wszVolumeNameInternal) );
|
|
wszVolumeNameInternal[x_nLengthOfVolMgmtVolumeName] = L'\0';
|
|
}
|
|
|
|
// Create the coordinator object
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VSSCoordinator,
|
|
L"Coordinator",
|
|
CLSCTX_ALL,
|
|
IID_IVssCoordinator,
|
|
(IUnknown**)&(pICoord));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Set the context
|
|
ft.hr = pICoord->SetContext( lContext);
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"SetContext 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, ft.hr, L"Query failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// For all snapshots do...
|
|
VSS_ID OldestSnapshotId = GUID_NULL; // used if Oldest option is specified
|
|
VSS_TIMESTAMP OldestSnapshotTimestamp = 0x7FFFFFFFFFFFFFFF; // Used if Oldest option is specified
|
|
|
|
VSS_OBJECT_PROP Prop;
|
|
|
|
//
|
|
// If not asking to delete the oldest snapshot, this could possibly delete multiple snapshots
|
|
// Let's determine how many snapshots will be deleted. If one or more, ask the user if we
|
|
// should continue. If in quiet mode, don't bother the user and skip this step.
|
|
//
|
|
if ( !oldest && !IsQuiet() )
|
|
{
|
|
ULONG ulNumToBeDeleted = 0;
|
|
|
|
for (;;)
|
|
{
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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;
|
|
}
|
|
|
|
// Use auto delete class to manage the snapshot properties
|
|
CVssAutoSnapshotProperties cSnap( Prop );
|
|
|
|
if (::_wcsicmp( cSnap->m_pwszOriginalVolumeName, wszVolumeNameInternal ) == 0 ||
|
|
(forVolume == NULL && all))
|
|
++ulNumToBeDeleted;
|
|
}
|
|
|
|
if ( ulNumToBeDeleted == 0 )
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::DeleteSnapshots: No snapshots found that satisfy the query");
|
|
|
|
if ( !PromptUserForConfirmation( MSG_INFO_PROMPT_USER_FOR_DELETE_SNAPSHOTS, ulNumToBeDeleted ) )
|
|
return;
|
|
|
|
// Reset the enumerator to the beginning.
|
|
ft.hr = pIEnumSnapshots->Reset();
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Reset failed with hr = 0x%08lx", ft.hr);
|
|
}
|
|
|
|
//
|
|
// Now iterate through the list of snapshots looking for matches and delete them.
|
|
//
|
|
for(;;)
|
|
{
|
|
// Get next element
|
|
ULONG ulFetched;
|
|
ft.hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, 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;
|
|
}
|
|
|
|
// Use auto delete class to manage the snapshot properties
|
|
CVssAutoSnapshotProperties cSnap( Prop );
|
|
|
|
if (::_wcsicmp( cSnap->m_pwszOriginalVolumeName, wszVolumeNameInternal ) == 0 ||
|
|
(forVolume == NULL && all))
|
|
{
|
|
// We have a volume name match
|
|
if (oldest)
|
|
{
|
|
// Stow away snapshot info if this is the oldest one so far
|
|
if ( OldestSnapshotTimestamp > cSnap->m_tsCreationTimestamp )
|
|
{
|
|
OldestSnapshotId = cSnap->m_SnapshotId;
|
|
OldestSnapshotTimestamp = cSnap->m_tsCreationTimestamp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Delete the snapshot
|
|
VSS_ID NondeletedSnapshotId = GUID_NULL;
|
|
LONG lNumDeletedPrivate;
|
|
ft.hr = pICoord->DeleteSnapshots(
|
|
cSnap->m_SnapshotId,
|
|
VSS_OBJECT_SNAPSHOT,
|
|
TRUE,
|
|
&lNumDeletedPrivate,
|
|
&NondeletedSnapshotId );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
// If it is object not found, the snapshot must have gotten deleted by someone else
|
|
if ( ft.hr != VSS_E_OBJECT_NOT_FOUND )
|
|
{
|
|
// Print out an error message but keep going
|
|
CVssAutoPWSZ awszSnapshotId( ::GuidToString( cSnap->m_SnapshotId ) );
|
|
OutputErrorMsg( MSG_ERROR_UNABLE_TO_DELETE_SNAPSHOT, ft.hr, (LPWSTR)awszSnapshotId );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lNumDeleted += lNumDeletedPrivate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If in delete oldest mode, do the delete
|
|
if (oldest && OldestSnapshotId != GUID_NULL )
|
|
{
|
|
if ( PromptUserForConfirmation( MSG_INFO_PROMPT_USER_FOR_DELETE_SNAPSHOTS, 1 ) )
|
|
{
|
|
// Delete the snapshot
|
|
VSS_ID NondeletedSnapshotId = GUID_NULL;
|
|
ft.hr = pICoord->DeleteSnapshots(
|
|
OldestSnapshotId,
|
|
VSS_OBJECT_SNAPSHOT,
|
|
TRUE,
|
|
&lNumDeleted,
|
|
&NondeletedSnapshotId );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
|
|
CVssAutoPWSZ awszSnapshotId( ::GuidToString( OldestSnapshotId ) );
|
|
// If it is object not found, the snapshot must have gotten deleted by someone else
|
|
if ( ft.hr == VSS_E_OBJECT_NOT_FOUND )
|
|
{
|
|
OutputErrorMsg( MSG_ERROR_SNAPSHOT_NOT_FOUND, awszSnapshotId );
|
|
}
|
|
else
|
|
{
|
|
OutputErrorMsg( MSG_ERROR_UNABLE_TO_DELETE_SNAPSHOT, ft.hr, awszSnapshotId );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
if ( lNumDeleted == 0 )
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_NO_ITEMS_IN_QUERY,
|
|
L"CVssAdminCLI::DeleteSnapshots: No snapshots found that satisfy the query");
|
|
|
|
}
|
|
|
|
if ( !IsQuiet() && lNumDeleted > 0 )
|
|
OutputMsg( MSG_INFO_SNAPSHOTS_DELETED_SUCCESSFULLY, lNumDeleted );
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
|
|
void CVssAdminCLI::ExposeSnapshot(
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ExposeSnapshot" );
|
|
|
|
// gather the parameters
|
|
BOOL bExposeLocally = FALSE;
|
|
LPWSTR pwszExposeUsing = GetOptionValueStr( VSSADM_O_EXPOSE_USING );
|
|
LPWSTR pwszPathFromRoot = GetOptionValueStr( VSSADM_O_SHAREPATH );
|
|
|
|
if ( pwszExposeUsing != NULL && ::wcslen( pwszExposeUsing ) >= 2 && pwszExposeUsing[1] == L':' )
|
|
{
|
|
// User specified a mountpoint or a drive letter.
|
|
bExposeLocally = TRUE;
|
|
}
|
|
|
|
BS_ASSERT (GetOptionValueStr (VSSADM_O_SNAPSHOT) != NULL);
|
|
VSS_ID SnapshotId = GUID_NULL;
|
|
if (!ScanGuid (GetOptionValueStr (VSSADM_O_SNAPSHOT), SnapshotId))
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION_VALUE,
|
|
L"CVssAdminCLI::ExposeSnapshot: Invalid snapshot id" );
|
|
}
|
|
|
|
// verify the parameters
|
|
m_pVerifier->ExposeSnapshot (SnapshotId, pwszExposeUsing, pwszPathFromRoot, bExposeLocally==TRUE, ft);
|
|
|
|
LONG lAttributes;
|
|
if ( bExposeLocally )
|
|
lAttributes = VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY;
|
|
else
|
|
lAttributes = VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY;
|
|
|
|
// Create the coordinator object
|
|
CComPtr<IVssCoordinator> pICoord;
|
|
|
|
ft.CoCreateInstanceWithLog(
|
|
VSSDBG_VSSADMIN,
|
|
CLSID_VSSCoordinator,
|
|
L"Coordinator",
|
|
CLSCTX_ALL,
|
|
IID_IVssCoordinator,
|
|
(IUnknown**)&(pICoord));
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
|
|
|
|
// Set the context to all so that we don't have to specify a specific context which would require either
|
|
// the user to specify it on the command-line or for us to first query the snapshot to determine its
|
|
// context.
|
|
ft.hr = pICoord->SetContext( VSS_CTX_ALL );
|
|
if ( ft.HrFailed() )
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Error returned from IVssCoordinator::SetContext( CTX_ALL) hr = 0x%08x", ft.hr);
|
|
|
|
LPWSTR wszExposedAs = NULL;
|
|
|
|
// Now try to expose
|
|
ft.hr = pICoord->ExposeSnapshot( SnapshotId,
|
|
pwszPathFromRoot,
|
|
lAttributes,
|
|
pwszExposeUsing,
|
|
&wszExposedAs );
|
|
if ( ft.HrFailed() )
|
|
{
|
|
switch (ft.hr) {
|
|
case E_INVALIDARG:
|
|
OutputErrorMsg( MSG_ERROR_EXPOSE_INVALID_ARG);
|
|
return;
|
|
case VSS_E_OBJECT_ALREADY_EXISTS:
|
|
OutputErrorMsg(MSG_ERROR_EXPOSE_OBJECT_EXISTS);
|
|
return;
|
|
case VSS_E_OBJECT_NOT_FOUND:
|
|
OutputErrorMsg( MSG_ERROR_SNAPSHOT_NOT_FOUND, GetOptionValueStr( VSSADM_O_SNAPSHOT ) );
|
|
return;
|
|
default:
|
|
ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Error returned from ExposeSnapshot: hr = 0x%08x", ft.hr);
|
|
}
|
|
}
|
|
|
|
CVssAutoPWSZ awszExposedAs( wszExposedAs );
|
|
|
|
// The snapshot is exposed, print the results to the user
|
|
OutputMsg( MSG_INFO_EXPOSE_SNAPSHOT_SUCCESSFUL, awszExposedAs );
|
|
|
|
m_nReturnValue = VSS_CMDRET_SUCCESS;
|
|
}
|
|
|
|
|
|
LPWSTR CVssAdminCLI::BuildSnapshotAttributeDisplayString(
|
|
IN DWORD Attr
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::BuildSnapshotAttributeDisplayString" );
|
|
|
|
WCHAR pwszDisplayString[1024] = L"";
|
|
WORD wBit = 0;
|
|
|
|
// Go through the bits of the attribute
|
|
for ( ; wBit < (sizeof ( Attr ) * 8) ; ++wBit )
|
|
{
|
|
switch ( Attr & ( 1 << wBit ) )
|
|
{
|
|
case 0:
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_PERSISTENT:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_PERSISTENT, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_CLIENT_ACCESSIBLE, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_NO_AUTO_RELEASE, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_NO_WRITERS:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_NO_WRITERS, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_TRANSPORTABLE:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_TRANSPORTABLE, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_NOT_SURFACED:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_NOT_SURFACED, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_HARDWARE_ASSISTED:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_HARDWARE_ASSISTED, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_DIFFERENTIAL:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_DIFFERENTIAL, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_PLEX:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_PLEX, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_IMPORTED:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_IMPORTED, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_EXPOSED_LOCALLY, 0, L", " );
|
|
break;
|
|
case VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_EXPOSED_REMOTELY, 0, L", " );
|
|
break;
|
|
default:
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
0, Attr & ( 1 << wBit ), L", " );
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// If this is a backup snapshot, most like there will not be any attributes
|
|
if ( pwszDisplayString[0] == L'\0' )
|
|
{
|
|
AppendMessageToStr( pwszDisplayString, STRING_LEN( pwszDisplayString ),
|
|
MSG_INFO_SNAPSHOT_ATTR_NONE, 0, L", " );
|
|
}
|
|
|
|
LPWSTR pwszRetString = NULL;
|
|
::VssSafeDuplicateStr( ft, pwszRetString, pwszDisplayString );
|
|
return pwszRetString;
|
|
}
|
|
|
|
|
|
LONG CVssAdminCLI::DetermineSnapshotType(
|
|
IN LPCWSTR pwszType
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DetermineSnapshotType" );
|
|
|
|
// Determine the snapshot type based on the entered snapshot type string.
|
|
|
|
// See if the snapshot type was specified, if not, return all context
|
|
if ( pwszType == NULL || pwszType[0] == L'\0' )
|
|
{
|
|
return VSS_CTX_ALL;
|
|
}
|
|
|
|
INT idx;
|
|
|
|
// Determine type of snapshot
|
|
for ( idx = 0; g_asAdmTypeNames[idx].pwszName != NULL; ++idx )
|
|
{
|
|
if ( ( dCurrentSKU & g_asAdmTypeNames[idx].dwSKUs ) &&
|
|
( ::_wcsicmp( pwszType, g_asAdmTypeNames[idx].pwszName ) == 0 ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( g_asAdmTypeNames[idx].pwszName == NULL )
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION_VALUE,
|
|
L"DetermineSnapshotType: Invalid type specified: %s",
|
|
pwszType );
|
|
}
|
|
|
|
//
|
|
// Now return the context
|
|
//
|
|
return( g_asAdmTypeNames[idx].lSnapshotContext );
|
|
}
|
|
|
|
LPWSTR CVssAdminCLI::DetermineSnapshotType(
|
|
IN LONG lSnapshotAttributes
|
|
) throw(HRESULT)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DetermineSnapshotType" );
|
|
|
|
// Determine the snapshot type string based on the snapshot attributes
|
|
LPWSTR pwszType = NULL;
|
|
|
|
INT idx;
|
|
|
|
// Determine type of snapshot
|
|
for ( idx = 0; g_asAdmTypeNames[idx].pwszName != NULL; ++idx )
|
|
{
|
|
if ( g_asAdmTypeNames[idx].lSnapshotContext == ( lSnapshotAttributes & VSS_CTX_ATTRIB_MASK ) )
|
|
break;
|
|
}
|
|
|
|
if ( g_asAdmTypeNames[idx].pwszName == NULL )
|
|
{
|
|
ft.Trace( VSSDBG_VSSADMIN, L"DetermineSnapshotType: Invalid context in lSnapshotAttributes: 0x%08x",
|
|
lSnapshotAttributes );
|
|
LPWSTR pwszMsg = GetMsg( FALSE, MSG_UNKNOWN );
|
|
if ( pwszMsg == NULL )
|
|
{
|
|
ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED,
|
|
L"Error on loading the message string id %d. 0x%08lx",
|
|
MSG_UNKNOWN, ::GetLastError() );
|
|
}
|
|
return pwszMsg;
|
|
}
|
|
|
|
//
|
|
// Now return the context
|
|
//
|
|
::VssSafeDuplicateStr( ft, pwszType, g_asAdmTypeNames[idx].pwszName );
|
|
|
|
return pwszType;
|
|
}
|
|
|