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.
914 lines
31 KiB
914 lines
31 KiB
/*
|
|
**++
|
|
**
|
|
** Copyright (c) 2000-2001 Microsoft Corporation
|
|
**
|
|
**
|
|
** Module Name:
|
|
**
|
|
** mlutil.cpp
|
|
**
|
|
**
|
|
** Abstract:
|
|
**
|
|
** Utility functions for the VSML test.
|
|
**
|
|
** Author:
|
|
**
|
|
** Adi Oltean [aoltean] 03/05/2001
|
|
**
|
|
** The sample is based on the Metasnap test program written by Michael C. Johnson.
|
|
**
|
|
**
|
|
** Revision History:
|
|
**
|
|
**--
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
|
|
#include "ml.h"
|
|
#include "ntddsnap.h"
|
|
#include "ntddvol.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Command line parsing
|
|
|
|
|
|
bool CVssMultilayerTest::PrintUsage(bool bThrow /* = true */)
|
|
{
|
|
wprintf(
|
|
L"\nUsage:\n"
|
|
L" 1) For snapshot creation:\n"
|
|
L" vsml [-xt|-xa|-xp] [-s <seed_number>] <volumes>\n"
|
|
L" 2) For query:\n"
|
|
L" vsml [-xt|-xa|-xp|-xf] -qs [-P <ProviderID>]\n"
|
|
L" vsml [-xt|-xa|-xp|-xf] -qsv <volume> [-P <ProviderID>]\n"
|
|
L" vsml [-xt|-xa|-xp|-xf] -qv [-P <ProviderID>]\n"
|
|
L" vsml -qi <volume>\n"
|
|
L" vsml -is <volume>\n"
|
|
L" vsml -lw\n"
|
|
L" 3) For diff area:\n"
|
|
L" vsml -da <vol> <diff vol> <max size> [-P <ProviderID>]\n"
|
|
L" vsml -dr <vol> <diff vol> [-P <ProviderID>]\n"
|
|
L" vsml -ds <vol> <diff vol> <max size> [-P <ProviderID>]\n"
|
|
L" vsml -dqv [-v original_volume] [-P <ProviderID>]\n"
|
|
L" vsml -dqf <volume> [-P <ProviderID>]\n"
|
|
L" vsml -dqo <volume> [-P <ProviderID>]\n"
|
|
L" vsml -dqs {SnapshotID} [-P <ProviderID>]\n"
|
|
L" 4) For deleting snapshots:\n"
|
|
L" vsml [-xt|-xa|-xp] -r {snapshot id}\n"
|
|
L" vsml [-xt|-xa|-xp] -rs {snapshot set id}\n"
|
|
L" 5) For various tests:\n"
|
|
L" vsml [-xt|-xa|-xp] -sp {snapshot id} PropertyId string\n"
|
|
L" vsml -test_sc\n"
|
|
L" 6) For displaying various constants:\n"
|
|
L" vsml -const\n"
|
|
L" 7) For diagnosing writers:\n"
|
|
L" vsml -diag\n"
|
|
L" vsml -diag log\n"
|
|
L" vsml -diag csv\n"
|
|
L" vsml -diag on\n"
|
|
L" vsml -diag off\n"
|
|
L"\nOptions:\n"
|
|
L" -s Specifies a seed for the random number generator\n"
|
|
L" -xt Operates in the Timewarp context\n"
|
|
L" -xa Operates in the 'ALL' context\n"
|
|
L" -xp Operates in the 'Nas Rollback' context\n"
|
|
L" -xr Operates in the 'App Rollback' context\n"
|
|
L" -xf Operates in the File Share Backup context\n"
|
|
L" -qs Queries the existing snapshots\n"
|
|
L" -qi Queries the VOLSNAP snapshots (through ioctl)\n"
|
|
L" -is Checks if the volume is snapshotted (through C API)\n"
|
|
L" -qsv Queries the snapshots on the given volume\n"
|
|
L" -qv Queries the supported volumes.\n"
|
|
L" -P Specifies a provider Id\n"
|
|
L" -da Adds a diff area association.\n"
|
|
L" -dr Removes a diff area association.\n"
|
|
L" -ds Change diff area max size.\n"
|
|
L" -dqv Query the volumes supported for diff area.\n"
|
|
L" -dqf Query the diff area associations for volume.\n"
|
|
L" -dqo Query the diff area associations on volume.\n"
|
|
L" -dqs Query the diff area associations for snapshot.\n"
|
|
L" -r Remove the snapshot with that ID.\n"
|
|
L" -rs Remove the snapshots from the set with that ID.\n"
|
|
L" -sp Set snapshot properties.\n"
|
|
L" -test_sc Test SID collection.\n"
|
|
L" -const Prints out various constants.\n"
|
|
L" -? Displays this help.\n"
|
|
L" -D Pops up an assert for attaching a debugger.\n"
|
|
L" -diag Diagnose all writers. Print all writers.\n"
|
|
L" -diag log Diagnose all writers. Print only pending writers.\n"
|
|
L" -diag csv Diagnose all writers. Print information in CSV format.\n"
|
|
L" -diag on Turn on diagnose.\n"
|
|
L" -diag off Turn off diagnose.\n"
|
|
L" -lw List writers.\n"
|
|
L"\n"
|
|
L"\nExample:\n"
|
|
L" The following command will create a backup snapshot set\n"
|
|
L" on the volumes mounted under c:\\ and d:\\\n"
|
|
L"\n"
|
|
L" vsml c:\\ d:\\ \n"
|
|
L"\n"
|
|
);
|
|
|
|
if (bThrow)
|
|
throw(E_INVALIDARG);
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
#define VSS_PRINT_VALUE(x) wprintf(L" 0x%08lx - %S\n", x, #x);
|
|
|
|
#define VSS_PRINT_GUID(X) wprintf( L" {%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x} - %S\n", \
|
|
(X).Data1, \
|
|
(X).Data2, \
|
|
(X).Data3, \
|
|
(X).Data4[0], (X).Data4[1], (X).Data4[2], (X).Data4[3], \
|
|
(X).Data4[4], (X).Data4[5], (X).Data4[6], (X).Data4[7], \
|
|
#X);
|
|
|
|
bool CVssMultilayerTest::ParseCommandLine()
|
|
{
|
|
if (!TokensLeft() || Match(L"-?"))
|
|
return PrintUsage(false);
|
|
|
|
// Check for context options
|
|
if (Match(L"-D"))
|
|
m_bAttachYourDebuggerNow = true;
|
|
|
|
// displays all ioctls
|
|
if (Match(L"-const")) {
|
|
m_eTest = VSS_TEST_NONE;
|
|
|
|
wprintf (L"\nVolsnap ioctls:\n");
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_RELEASE_WRITES);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_PREPARE_FOR_SNAPSHOT);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_ABORT_PREPARED_SNAPSHOT);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_COMMIT_SNAPSHOT);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_END_COMMIT_SNAPSHOT);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_CLEAR_DIFF_AREA);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_ADD_VOLUME_TO_DIFF_AREA);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_QUERY_DIFF_AREA);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_SET_MAX_DIFF_AREA_SIZE);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_DELETE_OLDEST_SNAPSHOT);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_AUTO_CLEANUP);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_DELETE_SNAPSHOT);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_QUERY_ORIGINAL_VOLUME_NAME);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_QUERY_CONFIG_INFO);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_SET_APPLICATION_INFO);
|
|
VSS_PRINT_VALUE(IOCTL_VOLSNAP_QUERY_APPLICATION_INFO);
|
|
VSS_PRINT_VALUE(FSCTL_DISMOUNT_VOLUME);
|
|
VSS_PRINT_VALUE(IOCTL_VOLUME_OFFLINE);
|
|
|
|
wprintf (L"\n\nVolsnap contexes:\n");
|
|
VSS_PRINT_VALUE(VSS_CTX_BACKUP);
|
|
VSS_PRINT_VALUE(VSS_CTX_FILE_SHARE_BACKUP);
|
|
VSS_PRINT_VALUE(VSS_CTX_NAS_ROLLBACK);
|
|
VSS_PRINT_VALUE(VSS_CTX_APP_ROLLBACK);
|
|
VSS_PRINT_VALUE(VSS_CTX_CLIENT_ACCESSIBLE);
|
|
VSS_PRINT_VALUE(VSS_CTX_ALL);
|
|
|
|
wprintf (L"\n\nVolsnap guids:\n");
|
|
VSS_PRINT_GUID(VOLSNAP_APPINFO_GUID_BACKUP_CLIENT_SKU);
|
|
VSS_PRINT_GUID(VOLSNAP_APPINFO_GUID_BACKUP_SERVER_SKU);
|
|
VSS_PRINT_GUID(VOLSNAP_APPINFO_GUID_SYSTEM_HIDDEN);
|
|
VSS_PRINT_GUID(VOLSNAP_APPINFO_GUID_NAS_ROLLBACK);
|
|
VSS_PRINT_GUID(VOLSNAP_APPINFO_GUID_APP_ROLLBACK);
|
|
VSS_PRINT_GUID(VOLSNAP_APPINFO_GUID_FILE_SHARE_BACKUP);
|
|
|
|
wprintf(L"\n\nValid attributes for SetContext:\n");
|
|
wprintf(L" VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY = %d\n", VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY);
|
|
wprintf(L" VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY = %d\n", VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY);
|
|
wprintf(L" VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY | VSS_..._REMOTELY = %d\n",
|
|
VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY | VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY);
|
|
|
|
wprintf(L"\n\nValid property IDs:\n");
|
|
wprintf(L" VSS_SPROPID_SNAPSHOT_ATTRIBUTES = %d\n", VSS_SPROPID_SNAPSHOT_ATTRIBUTES);
|
|
wprintf(L" VSS_SPROPID_EXPOSED_NAME = %d\n", VSS_SPROPID_EXPOSED_NAME);
|
|
wprintf(L" VSS_SPROPID_EXPOSED_PATH = %d\n", VSS_SPROPID_EXPOSED_PATH);
|
|
wprintf(L" VSS_SPROPID_SERVICE_MACHINE = %d\n", VSS_SPROPID_SERVICE_MACHINE);
|
|
|
|
wprintf(L"\n");
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Test CSidCollection
|
|
if (Match(L"-test_sc")) {
|
|
m_eTest = VSS_TEST_ACCESS_CONTROL_SD;
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Diagnose writers
|
|
if (Match(L"-diag")) {
|
|
if (Match(L"on")) {
|
|
m_eTest = VSS_TEST_DIAG_WRITERS_ON;
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
if (Match(L"off")) {
|
|
m_eTest = VSS_TEST_DIAG_WRITERS_OFF;
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
if (Match(L"log")) {
|
|
m_eTest = VSS_TEST_DIAG_WRITERS_LOG;
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
if (Match(L"csv")) {
|
|
m_eTest = VSS_TEST_DIAG_WRITERS_CSV;
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
if (!TokensLeft()) {
|
|
m_eTest = VSS_TEST_DIAG_WRITERS;
|
|
return true;
|
|
}
|
|
|
|
return PrintUsage();
|
|
}
|
|
|
|
// Check for List Writers
|
|
if (Match(L"-lw"))
|
|
{
|
|
m_eTest = VSS_TEST_LIST_WRITERS;
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Query using the IOCTL
|
|
if (Match(L"-qi")) {
|
|
m_eTest = VSS_TEST_VOLSNAP_QUERY;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Query using the IOCTL
|
|
if (Match(L"-is")) {
|
|
m_eTest = VSS_TEST_IS_VOLUME_SNAPSHOTTED_C;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for context options
|
|
if (Match(L"-xt"))
|
|
m_lContext = VSS_CTX_CLIENT_ACCESSIBLE;
|
|
|
|
if (Match(L"-xa"))
|
|
m_lContext = VSS_CTX_ALL;
|
|
|
|
if (Match(L"-xp"))
|
|
m_lContext = VSS_CTX_NAS_ROLLBACK;
|
|
|
|
if (Match(L"-xr"))
|
|
m_lContext = VSS_CTX_APP_ROLLBACK;
|
|
|
|
if (Match(L"-xf"))
|
|
m_lContext = VSS_CTX_FILE_SHARE_BACKUP;
|
|
|
|
// Set the snapshot property
|
|
if (Match(L"-sp")) {
|
|
m_eTest = VSS_TEST_SET_SNAPSHOT_PROPERTIES;
|
|
|
|
// Extract the snapshot id
|
|
if (!Extract(m_SnapshotId))
|
|
return PrintUsage();
|
|
|
|
// Extract the property ID
|
|
Extract(m_uPropertyId);
|
|
|
|
UINT uNewAttributes = 0;
|
|
LPWSTR pwszString = NULL;
|
|
switch(m_uPropertyId)
|
|
{
|
|
case VSS_SPROPID_SNAPSHOT_ATTRIBUTES:
|
|
// Extract the snapshot attributes
|
|
Extract(uNewAttributes);
|
|
switch(uNewAttributes)
|
|
{
|
|
default:
|
|
wprintf(L"\nInvalid attributes ID (%lu). Valid ones:\n", uNewAttributes);
|
|
wprintf(L" VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY = %d\n", VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY);
|
|
wprintf(L" VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY = %d\n", VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY);
|
|
wprintf(L" VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY | VSS_..._REMOTELY = %d\n",
|
|
VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY | VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY);
|
|
return false;
|
|
|
|
case VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY:
|
|
case VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY:
|
|
case VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY | VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY:
|
|
break;
|
|
}
|
|
m_value = (LONG)uNewAttributes;
|
|
break;
|
|
|
|
case VSS_SPROPID_EXPOSED_NAME:
|
|
case VSS_SPROPID_EXPOSED_PATH:
|
|
case VSS_SPROPID_SERVICE_MACHINE:
|
|
// Extract the snapshot attributes
|
|
if (Extract(pwszString))
|
|
{
|
|
m_value = pwszString;
|
|
::VssFreeString(pwszString);
|
|
}
|
|
else
|
|
m_value = L"";
|
|
|
|
break;
|
|
|
|
default:
|
|
wprintf(L"\nInvalid property ID (%ld). Valid ones:\n", m_uPropertyId);
|
|
wprintf(L" VSS_SPROPID_SNAPSHOT_ATTRIBUTES = %d\n", VSS_SPROPID_SNAPSHOT_ATTRIBUTES);
|
|
wprintf(L" VSS_SPROPID_EXPOSED_NAME = %d\n", VSS_SPROPID_EXPOSED_NAME);
|
|
wprintf(L" VSS_SPROPID_EXPOSED_PATH = %d\n", VSS_SPROPID_EXPOSED_PATH);
|
|
wprintf(L" VSS_SPROPID_SERVICE_MACHINE = %d\n", VSS_SPROPID_SERVICE_MACHINE);
|
|
return false;
|
|
}
|
|
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Add the Diff Area
|
|
if (Match(L"-da")) {
|
|
m_eTest = VSS_TEST_ADD_DIFF_AREA;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
// Get the diff area volume
|
|
if (!Extract(m_pwszDiffAreaVolume) || !IsVolume(m_pwszDiffAreaVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a max diff area (i.e. -P is not present)
|
|
if (!Peek(L"-P"))
|
|
Extract(m_llMaxDiffArea);
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P")) {
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
Extract(m_llMaxDiffArea);
|
|
}
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Remove the Diff Area
|
|
if (Match(L"-dr")) {
|
|
m_eTest = VSS_TEST_REMOVE_DIFF_AREA;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
// Get the diff area volume
|
|
if (!Extract(m_pwszDiffAreaVolume) || !IsVolume(m_pwszDiffAreaVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Change Diff Area max size
|
|
if (Match(L"-ds")) {
|
|
m_eTest = VSS_TEST_CHANGE_DIFF_AREA_MAX_SIZE;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
// Get the diff area volume
|
|
if (!Extract(m_pwszDiffAreaVolume) || !IsVolume(m_pwszDiffAreaVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a max diff area (i.e. -P is not present)
|
|
if (!Peek(L"-P"))
|
|
Extract(m_llMaxDiffArea);
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P")) {
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
Extract(m_llMaxDiffArea);
|
|
}
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Query the volumes supported for Diff Area
|
|
if (Match(L"-dqv")) {
|
|
m_eTest = VSS_TEST_QUERY_SUPPORTED_VOLUMES_FOR_DIFF_AREA;
|
|
|
|
// Check to see if we specified a max diff area (i.e. -P is not present)
|
|
if (!Peek(L"-v"))
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Query the volumes supported for Diff Area
|
|
if (Match(L"-dqf")) {
|
|
m_eTest = VSS_TEST_QUERY_DIFF_AREAS_FOR_VOLUME;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Query the volumes supported for Diff Area
|
|
if (Match(L"-dqo")) {
|
|
m_eTest = VSS_TEST_QUERY_DIFF_AREAS_ON_VOLUME;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_pwszDiffAreaVolume) || !IsVolume(m_pwszDiffAreaVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Query the volumes supported for Diff Area
|
|
if (Match(L"-dqs")) {
|
|
m_eTest = VSS_TEST_QUERY_DIFF_AREAS_FOR_SNAPSHOT;
|
|
|
|
// Get the original volume
|
|
if (!Extract(m_SnapshotId))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for Query
|
|
if (Match(L"-qs")) {
|
|
m_eTest = VSS_TEST_QUERY_SNAPSHOTS;
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for Query
|
|
if (Match(L"-qsv")) {
|
|
m_eTest = VSS_TEST_QUERY_SNAPSHOTS_ON_VOLUME;
|
|
|
|
// Extract the volume volume
|
|
if (!Extract(m_pwszVolume) || !IsVolume(m_pwszVolume))
|
|
return PrintUsage();
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for Query Supported Volumes
|
|
if (Match(L"-qv")) {
|
|
m_eTest = VSS_TEST_QUERY_VOLUMES;
|
|
|
|
// Check to see if we specified a provider ID
|
|
if (Match(L"-P"))
|
|
if (!Extract(m_ProviderId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for Delete by snapshot Id
|
|
if (Match(L"-r")) {
|
|
m_eTest = VSS_TEST_DELETE_BY_SNAPSHOT_ID;
|
|
|
|
// Extract the snapshot id
|
|
if (!Extract(m_SnapshotId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for Delete by snapshot set Id
|
|
if (Match(L"-rs")) {
|
|
m_eTest = VSS_TEST_DELETE_BY_SNAPSHOT_SET_ID;
|
|
|
|
// Extract the snapshot id
|
|
if (!Extract(m_SnapshotSetId))
|
|
return PrintUsage();
|
|
|
|
return TokensLeft()? PrintUsage(): true;
|
|
}
|
|
|
|
// Check for Seed option
|
|
if (Match(L"-s"))
|
|
if (!Extract(m_uSeed))
|
|
return PrintUsage();
|
|
|
|
// We are in snapshot creation mode
|
|
if (!TokensLeft())
|
|
return PrintUsage();
|
|
|
|
bool bVolumeAdded = false;
|
|
VSS_PWSZ pwszVolumeName = NULL;
|
|
while (TokensLeft()) {
|
|
Extract(pwszVolumeName);
|
|
if (!AddVolume(pwszVolumeName, bVolumeAdded)) {
|
|
wprintf(L"\nError while parsing the command line:\n"
|
|
L"\t%s is not a valid option or a mount point [0x%08lx]\n\n",
|
|
GetCurrentToken(), GetLastError() );
|
|
return PrintUsage();
|
|
}
|
|
|
|
// Check if the same volume is added twice
|
|
if (!bVolumeAdded) {
|
|
wprintf(L"\nError while parsing the command line:\n"
|
|
L"\tThe volume %s is specified twice\n\n", GetCurrentToken() );
|
|
return PrintUsage();
|
|
}
|
|
|
|
::VssFreeString(pwszVolumeName);
|
|
}
|
|
|
|
m_eTest = VSS_TEST_CREATE;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Check if there are tokens left
|
|
bool CVssMultilayerTest::TokensLeft()
|
|
{
|
|
return (m_nCurrentArgsCount != 0);
|
|
}
|
|
|
|
|
|
// Returns the current token
|
|
VSS_PWSZ CVssMultilayerTest::GetCurrentToken()
|
|
{
|
|
return (*m_ppwszCurrentArgsArray);
|
|
}
|
|
|
|
|
|
// Go to next token
|
|
void CVssMultilayerTest::Shift()
|
|
{
|
|
BS_ASSERT(m_nCurrentArgsCount);
|
|
m_nCurrentArgsCount--;
|
|
m_ppwszCurrentArgsArray++;
|
|
}
|
|
|
|
|
|
// Check if the current command line token matches with the given pattern
|
|
// Do not shift to the next token
|
|
bool CVssMultilayerTest::Peek(
|
|
IN VSS_PWSZ pwszPattern
|
|
) throw(HRESULT)
|
|
{
|
|
if (!TokensLeft())
|
|
return false;
|
|
|
|
// Try to find a match
|
|
if (wcscmp(GetCurrentToken(), pwszPattern))
|
|
return false;
|
|
|
|
// Go to the next token
|
|
return true;
|
|
}
|
|
|
|
|
|
// Match the current command line token with the given pattern
|
|
// If succeeds, then switch to the next token
|
|
bool CVssMultilayerTest::Match(
|
|
IN VSS_PWSZ pwszPattern
|
|
) throw(HRESULT)
|
|
{
|
|
if (!Peek(pwszPattern))
|
|
return false;
|
|
|
|
// Go to the next token
|
|
Shift();
|
|
return true;
|
|
}
|
|
|
|
|
|
// Converts the current token to a guid
|
|
// If succeeds, then switch to the next token
|
|
bool CVssMultilayerTest::Extract(
|
|
IN OUT VSS_ID& Guid
|
|
) throw(HRESULT)
|
|
{
|
|
if (!TokensLeft())
|
|
return false;
|
|
|
|
// Try to extract the guid
|
|
if (!SUCCEEDED(::CLSIDFromString(W2OLE(const_cast<WCHAR*>(GetCurrentToken())), &Guid)))
|
|
return false;
|
|
|
|
// Go to the next token
|
|
Shift();
|
|
return true;
|
|
}
|
|
|
|
|
|
// Converts the current token to a string
|
|
// If succeeds, then switch to the next token
|
|
bool CVssMultilayerTest::Extract(
|
|
IN OUT VSS_PWSZ& pwsz
|
|
) throw(HRESULT)
|
|
{
|
|
if (!TokensLeft())
|
|
return false;
|
|
|
|
// Extract the string
|
|
::VssDuplicateStr(pwsz, GetCurrentToken());
|
|
if (!pwsz)
|
|
throw(E_OUTOFMEMORY);
|
|
|
|
// Go to the next token
|
|
Shift();
|
|
return true;
|
|
}
|
|
|
|
|
|
// Converts the current token to an UINT
|
|
// If succeeds, then switch to the next token
|
|
bool CVssMultilayerTest::Extract(
|
|
IN OUT UINT& uint
|
|
) throw(HRESULT)
|
|
{
|
|
if (!TokensLeft())
|
|
return false;
|
|
|
|
// Extract the unsigned value
|
|
uint = ::_wtoi(GetCurrentToken());
|
|
|
|
// Go to the next token
|
|
Shift();
|
|
return true;
|
|
}
|
|
|
|
|
|
// Converts the current token to an UINT
|
|
// If succeeds, then switch to the next token
|
|
bool CVssMultilayerTest::Extract(
|
|
IN OUT LONGLONG& llValue
|
|
) throw(HRESULT)
|
|
{
|
|
if (!TokensLeft())
|
|
return false;
|
|
|
|
// Extract the unsigned value
|
|
llValue = ::_wtoi64(GetCurrentToken());
|
|
|
|
// Go to the next token
|
|
Shift();
|
|
return true;
|
|
}
|
|
|
|
|
|
// Returns true if the given string is a volume
|
|
bool CVssMultilayerTest::IsVolume(
|
|
IN WCHAR* pwszVolumeDisplayName
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::IsVolume");
|
|
|
|
// Check if the volume represents a real mount point
|
|
WCHAR wszVolumeName[MAX_TEXT_BUFFER];
|
|
if (!GetVolumeNameForVolumeMountPoint(pwszVolumeDisplayName, wszVolumeName, MAX_TEXT_BUFFER))
|
|
return false; // Invalid volume
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Add the given volume in the list of potential candidates for snapshots
|
|
// - Returns "false" if the volume does not correspond to a real mount point
|
|
// (and GetLastError() will contain the correct Win32 error code)
|
|
// - Sets "true" in the bAdded parameter if the volume is actually added
|
|
bool CVssMultilayerTest::AddVolume(
|
|
IN WCHAR* pwszVolumeDisplayName,
|
|
OUT bool & bAdded
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSTEST, L"CVssMultilayerTest::AddVolume");
|
|
|
|
// Initialize [out] parameters
|
|
bAdded = false;
|
|
|
|
// Check if the volume represents a real mount point
|
|
WCHAR wszVolumeName[MAX_TEXT_BUFFER];
|
|
if (!GetVolumeNameForVolumeMountPoint(pwszVolumeDisplayName, wszVolumeName, MAX_TEXT_BUFFER))
|
|
return false; // Invalid volume
|
|
|
|
// Check if the volume is already added.
|
|
WCHAR* pwszVolumeNameToBeSearched = wszVolumeName;
|
|
if (m_mapVolumes.FindKey(pwszVolumeNameToBeSearched) != -1)
|
|
return true; // Volume already added. Stop here.
|
|
|
|
// Create the volume info object
|
|
CVssVolumeInfo* pVolInfo = new CVssVolumeInfo(wszVolumeName, pwszVolumeDisplayName);
|
|
if (pVolInfo == NULL)
|
|
ft.Err(VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allcation error");
|
|
|
|
// Add the volume in our internal list of snapshotted volumes
|
|
if (!m_mapVolumes.Add(pVolInfo->GetVolumeDisplayName(), pVolInfo)) {
|
|
delete pVolInfo;
|
|
ft.Err(VSSDBG_VSSTEST, E_OUTOFMEMORY, L"Memory allcation error");
|
|
}
|
|
|
|
bAdded = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Utility functions
|
|
|
|
|
|
// Convert a failure type into a string
|
|
LPCWSTR CVssMultilayerTest::GetStringFromFailureType( IN HRESULT hrStatus )
|
|
{
|
|
static WCHAR wszBuffer[MAX_TEXT_BUFFER];
|
|
|
|
switch (hrStatus)
|
|
{
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITERERROR_OUTOFRESOURCES)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITERERROR_TIMEOUT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITERERROR_NONRETRYABLE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITERERROR_RETRYABLE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_BAD_STATE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_PROVIDER_ALREADY_REGISTERED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_PROVIDER_NOT_REGISTERED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_PROVIDER_VETO)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_PROVIDER_IN_USE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_OBJECT_NOT_FOUND)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_S_ASYNC_PENDING)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_S_ASYNC_FINISHED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_S_ASYNC_CANCELLED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_VOLUME_NOT_SUPPORTED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_OBJECT_ALREADY_EXISTS)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_UNEXPECTED_PROVIDER_ERROR)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_CORRUPT_XML_DOCUMENT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_INVALID_XML_DOCUMENT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_FLUSH_WRITES_TIMEOUT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_HOLD_WRITES_TIMEOUT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_UNEXPECTED_WRITER_ERROR)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_SNAPSHOT_SET_IN_PROGRESS)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITER_INFRASTRUCTURE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITER_NOT_RESPONDING)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_WRITER_ALREADY_SUBSCRIBED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_UNSUPPORTED_CONTEXT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_VOLUME_IN_USE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_MAXIMUM_DIFFAREA_ASSOCIATIONS_REACHED)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_E_INSUFFICIENT_STORAGE)
|
|
|
|
case NOERROR:
|
|
break;
|
|
|
|
default:
|
|
::FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, hrStatus, 0, (LPWSTR)&wszBuffer, MAX_TEXT_BUFFER - 1, NULL);
|
|
break;
|
|
}
|
|
|
|
return (wszBuffer);
|
|
}
|
|
|
|
|
|
// Convert a writer status into a string
|
|
LPCWSTR CVssMultilayerTest::GetStringFromWriterState( IN VSS_WRITER_STATE state )
|
|
{
|
|
static WCHAR wszBuffer[MAX_TEXT_BUFFER];
|
|
|
|
switch (state)
|
|
{
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_UNKNOWN)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_STABLE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_WAITING_FOR_FREEZE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_WAITING_FOR_THAW)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_WAITING_FOR_POST_SNAPSHOT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_WAITING_FOR_BACKUP_COMPLETE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_PREPARE_BACKUP)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_PREPARE_SNAPSHOT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_FREEZE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_THAW)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_POST_SNAPSHOT)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_BACKUP_COMPLETE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_PRE_RESTORE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_POST_RESTORE)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_FAILED_AT_BACKUPSHUTDOWN)
|
|
VSS_ERROR_CASE(wszBuffer, MAX_TEXT_BUFFER, VSS_WS_COUNT)
|
|
|
|
default:
|
|
swprintf(wszBuffer, L" Unknown state %d", state);
|
|
break;
|
|
}
|
|
|
|
return (wszBuffer);
|
|
}
|
|
|
|
|
|
INT CVssMultilayerTest::RndDecision(
|
|
IN INT nVariants /* = 2 */
|
|
)
|
|
{
|
|
return (rand() % nVariants);
|
|
}
|
|
|
|
|
|
LPWSTR CVssMultilayerTest::DateTimeToString(
|
|
IN LONGLONG llTimestamp
|
|
)
|
|
{
|
|
CVssFunctionTracer ft( VSSDBG_VSSTEST, L"CVssMultilayerTest::DateTimeToString" );
|
|
|
|
SYSTEMTIME stLocal;
|
|
FILETIME ftLocal;
|
|
WCHAR pwszDate[ 64 ];
|
|
WCHAR pwszTime[ 64 ];
|
|
|
|
BS_ASSERT(sizeof(FILETIME) == sizeof(LONGLONG));
|
|
|
|
// Compensate for local TZ
|
|
::FileTimeToLocalFileTime( (FILETIME *) &llTimestamp, &ftLocal );
|
|
|
|
// Finally convert it to system time
|
|
::FileTimeToSystemTime( &ftLocal, &stLocal );
|
|
|
|
// Convert timestamp to a date string
|
|
::GetDateFormatW( GetThreadLocale( ),
|
|
DATE_SHORTDATE,
|
|
&stLocal,
|
|
NULL,
|
|
pwszDate,
|
|
sizeof( pwszDate ) / sizeof( pwszDate[0] ));
|
|
|
|
// Convert timestamp to a time string
|
|
::GetTimeFormatW( GetThreadLocale( ),
|
|
0,
|
|
&stLocal,
|
|
NULL,
|
|
pwszTime,
|
|
sizeof( pwszTime ) / sizeof( pwszTime[0] ));
|
|
|
|
// Now combine the strings and return it
|
|
CVssAutoLocalString pwszDateTime;
|
|
pwszDateTime.Append(pwszDate);
|
|
pwszDateTime.Append(L" ");
|
|
pwszDateTime.Append(pwszTime);
|
|
|
|
return pwszDateTime.Detach();
|
|
}
|
|
|
|
|