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.
1440 lines
37 KiB
1440 lines
37 KiB
/*
|
|
**++
|
|
**
|
|
** Copyright (c) 2000-2001 Microsoft Corporation
|
|
**
|
|
**
|
|
** Module Name:
|
|
**
|
|
** SnapCp.cpp
|
|
**
|
|
**
|
|
** Abstract:
|
|
**
|
|
** Test program to accept commands and drive the snapshot stuff
|
|
**
|
|
**
|
|
** Author:
|
|
**
|
|
** Michael C. Johnson [mikejohn] 15-Mar-2001
|
|
**
|
|
** Based in part on test programs :-
|
|
** BETEST by Brian Berkowitz
|
|
** metasnap by Michael C. Johnson
|
|
**
|
|
**
|
|
** Revision History:
|
|
**
|
|
** X-3 Michael C. Johnson 7-May-2001
|
|
** Still more updates needed to keep up.
|
|
**
|
|
** X-2 Michael C. Johnson 11-Apr-2001
|
|
** Update to cater for recent changes to AddToSnapshotSet() API
|
|
** Also clean up a few 64 bit compilation troubles.
|
|
**
|
|
**
|
|
**
|
|
** ToDo:
|
|
** Allow for multiple (simultaneous) snapshot sets
|
|
** Assign drive letters (manual and automatically) (mapping?)
|
|
** Proper error handling
|
|
** Better user feedback for operation in progress...
|
|
** Logging
|
|
** Default drive list
|
|
** Comma separated drive list
|
|
** Command line prompt
|
|
** auto add all local hard drives
|
|
**
|
|
**--
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <wtypes.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
|
|
#include <vss.h>
|
|
#include <vswriter.h>
|
|
#include <vsbackup.h>
|
|
|
|
|
|
#include <oleauto.h>
|
|
|
|
#define ATLASSERT(_condition)
|
|
|
|
#include <atlconv.h>
|
|
#include <atlbase.h>
|
|
|
|
extern CComModule _Module;
|
|
#include <atlcom.h>
|
|
|
|
|
|
|
|
#define PROGRAM_TITLE L"SnapCp - Snapshot Control Program V0.3"
|
|
|
|
|
|
#if !defined (SIZEOF_ARRAY)
|
|
#define SIZEOF_ARRAY(_arrayname) (sizeof (_arrayname) / sizeof ((_arrayname)[0]))
|
|
#endif
|
|
|
|
#define MAX_COMMAND (SIZEOF_ARRAY (CommandTable))
|
|
#define MAX_COMMAND_LINE_LENGTH (1024)
|
|
#define MAX_VOLUMES_IN_SNAPSHOT_SET (64)
|
|
#define VolumeNameTemplate "\\\\?\\Volume{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\\"
|
|
|
|
|
|
|
|
#define HandleInvalid(_Handle) ((NULL == (_Handle)) || (INVALID_HANDLE_VALUE == (_Handle)))
|
|
|
|
#define GET_STATUS_FROM_BOOL(_bSucceeded) ((_bSucceeded) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError()))
|
|
#define GET_STATUS_FROM_HANDLE(_handle) ((!HandleInvalid(_handle)) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError()))
|
|
#define GET_STATUS_FROM_POINTER(_ptr) ((NULL != (_ptr)) ? NOERROR : E_OUTOFMEMORY)
|
|
|
|
|
|
|
|
typedef IVssBackupComponents *PIVssBackupComponents;
|
|
typedef IVssExamineWriterMetadata *PIVssExamineWriterMetadata;
|
|
typedef IVssWMComponent *PIVssWMComponent;
|
|
typedef IVssAsync *PIVssAsync;
|
|
|
|
|
|
|
|
typedef enum _SnapshotSetState
|
|
{
|
|
STATE_MIN_STATE = 50
|
|
,STATE_INITIALISED
|
|
,STATE_SNAPSHOT_SET_CREATED
|
|
,STATE_SNAPSHOT_CREATED
|
|
,STATE_SNAPSHOT_BEING_DESTROYED
|
|
,STATE_UNKNOWN
|
|
,STATE_MAX_STATE
|
|
} SNAPSHOTSET_STATE, *PSNAPSHOTSET_STATE;
|
|
|
|
typedef enum _CommandCode
|
|
{
|
|
COMMAND_MIN_COMMAND = 20
|
|
,COMMAND_QUIT
|
|
,COMMAND_EXIT
|
|
,COMMAND_HELP
|
|
,COMMAND_SHOW_METADATA
|
|
,COMMAND_SHOW_WRITERS
|
|
,COMMAND_ADD_VOLUME
|
|
,COMMAND_CREATE_SNAPSHOT_SET
|
|
,COMMAND_CREATE_SNAPSHOT
|
|
,COMMAND_DELETE_SNAPSHOT_SET
|
|
,COMMAND_SET_DEFAULT_VOLUME_LIST
|
|
,COMMAND_SET_BACKUP_TYPE
|
|
,COMMAND_SET_LOGGING_LEVEL
|
|
,COMMAND_SET_LOGGING_FILE
|
|
,COMMAND_NOT_IMPLEMENTED
|
|
,COMMAND_UNKNOWN
|
|
,COMMAND_MAX_COMMAND
|
|
} COMMAND_CODE, *PCOMMAND_CODE;
|
|
|
|
|
|
typedef struct _CommandDescriptor
|
|
{
|
|
COMMAND_CODE eCommandCode;
|
|
PWCHAR pwszCommandString;
|
|
} COMMANDDESCRIPTOR, *PCOMMANDDESCRIPTOR;
|
|
|
|
|
|
|
|
typedef struct _ContextSnapshotSet
|
|
{
|
|
COMMAND_CODE eCommand;
|
|
SNAPSHOTSET_STATE eState;
|
|
bool bIncludeBootableState;
|
|
ULONG ulVolumesInSnapshotSet;
|
|
PWSTR pwszVolumeArgument [MAX_VOLUMES_IN_SNAPSHOT_SET];
|
|
PWSTR pwszVolumeName [MAX_VOLUMES_IN_SNAPSHOT_SET];
|
|
PWSTR pwszVolumeDevice [MAX_VOLUMES_IN_SNAPSHOT_SET];
|
|
PWSTR pwszSnapshotDevice [MAX_VOLUMES_IN_SNAPSHOT_SET];
|
|
VSS_ID SnapshotId [MAX_VOLUMES_IN_SNAPSHOT_SET];
|
|
VSS_SNAPSHOT_PROP SnapshotProperties [MAX_VOLUMES_IN_SNAPSHOT_SET];
|
|
|
|
PIVssBackupComponents pIVssBackupComponents;
|
|
PIVssAsync pIVssAsyncDoSnapshotSet;
|
|
|
|
GUID guidSnapshotSetId;
|
|
} CONTEXTSNAPSHOTSET, *PCONTEXTSNAPSHOTSET;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline void CHECK_SUCCESS (HRESULT hr);
|
|
inline void CHECK_NOFAIL (HRESULT hr);
|
|
|
|
|
|
BOOL WINAPI CtrlC_HandlerRoutine (DWORD dwCtrlType);
|
|
|
|
HRESULT AssertPrivilege (LPCWSTR privName);
|
|
|
|
ULONG FormatGUID (GUID guidValue, PWCHAR pszFormattedGUID, ULONG ulBufferLength);
|
|
void PrintFiledesc (IVssWMFiledesc *pFiledesc, LPCWSTR wszDescription);
|
|
|
|
LPCWSTR GetStringFromUsageType (VSS_USAGE_TYPE eUsageType);
|
|
LPCWSTR GetStringFromSourceType (VSS_SOURCE_TYPE eSourceType);
|
|
LPCWSTR GetStringFromRestoreMethod (VSS_RESTOREMETHOD_ENUM eRestoreMethod);
|
|
LPCWSTR GetStringFromWriterRestoreMethod (VSS_WRITERRESTORE_ENUM eWriterRestoreMethod);
|
|
LPCWSTR GetStringFromComponentType (VSS_COMPONENT_TYPE eComponentType);
|
|
LPCWSTR GetStringFromFailureType (HRESULT hrStatus);
|
|
|
|
|
|
HRESULT GetNextCommandLine (PWSTR pwszCommandLineBuffer, ULONG ulCommandLineBufferLength);
|
|
HRESULT ParseCommandLine (PWSTR pwszCommandLineBuffer, PCOMMAND_CODE peReturnedCommandCode);
|
|
|
|
HRESULT InitialiseSnapshotSetContext (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
|
|
HRESULT GetVolumeNameFromArgument (LPCWSTR pwszVolumeArgument, LPWSTR *ppwszReturnedVolumeName);
|
|
|
|
|
|
HRESULT ShowAnnouncement (void);
|
|
HRESULT ShowHelp (void);
|
|
HRESULT ShowMetadata (void);
|
|
HRESULT ShowWriters (void);
|
|
HRESULT AddVolume (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
|
|
HRESULT CreateSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
|
|
HRESULT CreateSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
|
|
HRESULT DeleteSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
|
|
HRESULT CleanupSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMMANDDESCRIPTOR CommandTable [] =
|
|
{
|
|
{ COMMAND_QUIT, L"Quit" },
|
|
{ COMMAND_EXIT, L"Exit" },
|
|
{ COMMAND_HELP, L"Help" },
|
|
{ COMMAND_SHOW_METADATA, L"Metadata" },
|
|
{ COMMAND_SHOW_WRITERS, L"Writers" },
|
|
{ COMMAND_ADD_VOLUME, L"Add" },
|
|
{ COMMAND_CREATE_SNAPSHOT_SET, L"Set" },
|
|
{ COMMAND_CREATE_SNAPSHOT, L"Create" },
|
|
{ COMMAND_DELETE_SNAPSHOT_SET, L"Delete" },
|
|
{ COMMAND_SET_DEFAULT_VOLUME_LIST, L"Default" },
|
|
{ COMMAND_SET_BACKUP_TYPE, L"Type" },
|
|
{ COMMAND_SET_LOGGING_LEVEL, L"Level" },
|
|
{ COMMAND_SET_LOGGING_FILE, L"File" }
|
|
};
|
|
|
|
|
|
WCHAR g_awchCommandLine [MAX_COMMAND_LINE_LENGTH];
|
|
PWCHAR g_pwchNextArgument = NULL;
|
|
PCONTEXTSNAPSHOTSET g_pctxSnapshotSet = NULL;
|
|
BOOL g_bCoInitializeSucceeded = false;
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" __cdecl wmain(int argc, WCHAR **argv)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
PCONTEXTSNAPSHOTSET pctxSnapshotSet = NULL;
|
|
CONTEXTSNAPSHOTSET ctxSnapshotSet;
|
|
|
|
|
|
UNREFERENCED_PARAMETER (argc);
|
|
UNREFERENCED_PARAMETER (argv);
|
|
|
|
|
|
|
|
InitialiseSnapshotSetContext (&ctxSnapshotSet);
|
|
|
|
g_pctxSnapshotSet = &ctxSnapshotSet;
|
|
|
|
|
|
SetConsoleCtrlHandler (CtrlC_HandlerRoutine, TRUE);
|
|
|
|
|
|
|
|
ShowAnnouncement ();
|
|
|
|
hrStatus = CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
|
|
|
g_bCoInitializeSucceeded = SUCCEEDED (hrStatus);
|
|
|
|
if (FAILED (hrStatus))
|
|
{
|
|
wprintf (L"SnapCp (wmain) - CoInitializeEx() returned error 0x%08X\n", hrStatus);
|
|
}
|
|
|
|
|
|
|
|
if (SUCCEEDED (hrStatus))
|
|
{
|
|
hrStatus = AssertPrivilege (SE_BACKUP_NAME);
|
|
|
|
if (FAILED (hrStatus))
|
|
{
|
|
wprintf (L"SnapCp (wmain) - AssertPrivilege() returned error 0x%08X\n", hrStatus);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Parse command loop here
|
|
*/
|
|
while (SUCCEEDED (hrStatus) &&
|
|
(COMMAND_EXIT != ctxSnapshotSet.eCommand) &&
|
|
(COMMAND_QUIT != ctxSnapshotSet.eCommand))
|
|
{
|
|
hrStatus = GetNextCommandLine (g_awchCommandLine, sizeof (g_awchCommandLine));
|
|
hrStatus = ParseCommandLine (g_awchCommandLine, &ctxSnapshotSet.eCommand);
|
|
|
|
switch (ctxSnapshotSet.eCommand)
|
|
{
|
|
case COMMAND_EXIT: break;
|
|
case COMMAND_QUIT: break;
|
|
case COMMAND_HELP: hrStatus = ShowHelp (); break;
|
|
case COMMAND_SHOW_METADATA: hrStatus = ShowMetadata (); break;
|
|
case COMMAND_SHOW_WRITERS: hrStatus = ShowWriters (); break;
|
|
case COMMAND_CREATE_SNAPSHOT_SET: hrStatus = CreateSnapshotSet (&ctxSnapshotSet); break;
|
|
case COMMAND_ADD_VOLUME: hrStatus = AddVolume (&ctxSnapshotSet); break;
|
|
case COMMAND_CREATE_SNAPSHOT: hrStatus = CreateSnapshot (&ctxSnapshotSet); break;
|
|
case COMMAND_DELETE_SNAPSHOT_SET: hrStatus = DeleteSnapshot (&ctxSnapshotSet); break;
|
|
|
|
case COMMAND_SET_DEFAULT_VOLUME_LIST:
|
|
case COMMAND_SET_BACKUP_TYPE:
|
|
case COMMAND_SET_LOGGING_LEVEL:
|
|
case COMMAND_SET_LOGGING_FILE:
|
|
|
|
default:
|
|
ctxSnapshotSet.eCommand = COMMAND_UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pctxSnapshotSet = (PCONTEXTSNAPSHOTSET) InterlockedExchangePointer ((PVOID *)&g_pctxSnapshotSet, NULL);
|
|
|
|
if (NULL != pctxSnapshotSet) CleanupSnapshotSet (pctxSnapshotSet);
|
|
if (g_bCoInitializeSucceeded) CoUninitialize ();
|
|
if (FAILED(hrStatus)) wprintf (L"Failed with 0x%08X.\n", hrStatus);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI CtrlC_HandlerRoutine (DWORD dwCtrlType)
|
|
{
|
|
PCONTEXTSNAPSHOTSET pctxSnapshotSet = NULL;
|
|
|
|
|
|
UNREFERENCED_PARAMETER (dwCtrlType);
|
|
|
|
|
|
pctxSnapshotSet = (PCONTEXTSNAPSHOTSET) InterlockedExchangePointer ((PVOID *)&g_pctxSnapshotSet, NULL);
|
|
|
|
if (NULL != pctxSnapshotSet) CleanupSnapshotSet (pctxSnapshotSet);
|
|
if (g_bCoInitializeSucceeded) CoUninitialize ();
|
|
|
|
|
|
return (false);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT AssertPrivilege (LPCWSTR privName)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
BOOL bSucceeded = FALSE;
|
|
TOKEN_PRIVILEGES *pTokens = NULL;
|
|
TOKEN_PRIVILEGES newState;
|
|
HANDLE tokenHandle;
|
|
LUID value;
|
|
DWORD cbTokens;
|
|
|
|
|
|
if (OpenProcessToken (GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
|
|
&tokenHandle))
|
|
{
|
|
if (LookupPrivilegeValue (NULL, privName, &value))
|
|
{
|
|
newState.PrivilegeCount = 1;
|
|
newState.Privileges [0].Luid = value;
|
|
newState.Privileges [0].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
|
|
|
|
|
|
/*
|
|
** We will always call GetLastError below, so clear
|
|
** any prior error values on this thread.
|
|
*/
|
|
SetLastError (ERROR_SUCCESS);
|
|
|
|
bSucceeded = AdjustTokenPrivileges (tokenHandle,
|
|
FALSE,
|
|
&newState,
|
|
(DWORD)0,
|
|
NULL,
|
|
NULL);
|
|
|
|
/*
|
|
** Supposedly, AdjustTokenPriveleges always returns TRUE
|
|
** (even when it fails). So, call GetLastError to be
|
|
** extra sure everything's cool.
|
|
*/
|
|
hrStatus = GET_STATUS_FROM_BOOL (FALSE);
|
|
|
|
|
|
if (FAILED (hrStatus))
|
|
{
|
|
wprintf (L"AdjustTokenPrivileges for %s failed with 0x%08X",
|
|
privName,
|
|
hrStatus);
|
|
}
|
|
}
|
|
|
|
|
|
if (SUCCEEDED (hrStatus))
|
|
{
|
|
GetTokenInformation (tokenHandle,
|
|
TokenPrivileges,
|
|
NULL,
|
|
0,
|
|
&cbTokens);
|
|
|
|
|
|
pTokens = (TOKEN_PRIVILEGES *) new BYTE[cbTokens];
|
|
|
|
GetTokenInformation (tokenHandle,
|
|
TokenPrivileges,
|
|
pTokens,
|
|
cbTokens,
|
|
&cbTokens);
|
|
}
|
|
|
|
delete pTokens;
|
|
CloseHandle (tokenHandle);
|
|
}
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void CHECK_SUCCESS (HRESULT hr)
|
|
{
|
|
if (hr != S_OK)
|
|
{
|
|
wprintf(L"operation failed with HRESULT =0x%08x\n", hr);
|
|
DebugBreak();
|
|
}
|
|
}
|
|
|
|
|
|
inline void CHECK_NOFAIL (HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"operation failed with HRESULT =0x%08x\n", hr);
|
|
DebugBreak();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
LPCWSTR GetStringFromUsageType (VSS_USAGE_TYPE eUsageType)
|
|
{
|
|
LPCWSTR pwszRetString = L"UNDEFINED";
|
|
|
|
switch (eUsageType)
|
|
{
|
|
case VSS_UT_BOOTABLESYSTEMSTATE: pwszRetString = L"BootableSystemState"; break;
|
|
case VSS_UT_SYSTEMSERVICE: pwszRetString = L"SystemService"; break;
|
|
case VSS_UT_USERDATA: pwszRetString = L"UserData"; break;
|
|
case VSS_UT_OTHER: pwszRetString = L"Other"; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
return (pwszRetString);
|
|
}
|
|
|
|
|
|
LPCWSTR GetStringFromSourceType (VSS_SOURCE_TYPE eSourceType)
|
|
{
|
|
LPCWSTR pwszRetString = L"UNDEFINED";
|
|
|
|
switch (eSourceType)
|
|
{
|
|
case VSS_ST_TRANSACTEDDB: pwszRetString = L"TransactionDb"; break;
|
|
case VSS_ST_NONTRANSACTEDDB: pwszRetString = L"NonTransactionDb"; break;
|
|
case VSS_ST_OTHER: pwszRetString = L"Other"; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
return (pwszRetString);
|
|
}
|
|
|
|
|
|
LPCWSTR GetStringFromRestoreMethod (VSS_RESTOREMETHOD_ENUM eRestoreMethod)
|
|
{
|
|
LPCWSTR pwszRetString = L"UNDEFINED";
|
|
|
|
switch (eRestoreMethod)
|
|
{
|
|
case VSS_RME_RESTORE_IF_NOT_THERE: pwszRetString = L"RestoreIfNotThere"; break;
|
|
case VSS_RME_RESTORE_IF_CAN_REPLACE: pwszRetString = L"RestoreIfCanReplace"; break;
|
|
case VSS_RME_STOP_RESTORE_START: pwszRetString = L"StopRestoreStart"; break;
|
|
case VSS_RME_RESTORE_TO_ALTERNATE_LOCATION: pwszRetString = L"RestoreToAlternateLocation"; break;
|
|
case VSS_RME_RESTORE_AT_REBOOT: pwszRetString = L"RestoreAtReboot"; break;
|
|
case VSS_RME_CUSTOM: pwszRetString = L"Custom"; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
return (pwszRetString);
|
|
}
|
|
|
|
|
|
LPCWSTR GetStringFromWriterRestoreMethod (VSS_WRITERRESTORE_ENUM eWriterRestoreMethod)
|
|
{
|
|
LPCWSTR pwszRetString = L"UNDEFINED";
|
|
|
|
switch (eWriterRestoreMethod)
|
|
{
|
|
case VSS_WRE_NEVER: pwszRetString = L"RestoreNever"; break;
|
|
case VSS_WRE_IF_REPLACE_FAILS: pwszRetString = L"RestoreIfReplaceFailsI"; break;
|
|
case VSS_WRE_ALWAYS: pwszRetString = L"RestoreAlways"; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
return (pwszRetString);
|
|
}
|
|
|
|
|
|
LPCWSTR GetStringFromComponentType (VSS_COMPONENT_TYPE eComponentType)
|
|
{
|
|
LPCWSTR pwszRetString = L"UNDEFINED";
|
|
|
|
switch (eComponentType)
|
|
{
|
|
case VSS_CT_DATABASE: pwszRetString = L"Database"; break;
|
|
case VSS_CT_FILEGROUP: pwszRetString = L"FileGroup"; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
return (pwszRetString);
|
|
}
|
|
|
|
|
|
LPCWSTR GetStringFromFailureType (HRESULT hrStatus)
|
|
{
|
|
LPCWSTR pwszFailureType;
|
|
|
|
switch (hrStatus)
|
|
{
|
|
case NOERROR: pwszFailureType = L""; break;
|
|
case VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT: pwszFailureType = L"InconsistentSnapshot"; break;
|
|
case VSS_E_WRITERERROR_OUTOFRESOURCES: pwszFailureType = L"OutOfResources"; break;
|
|
case VSS_E_WRITERERROR_TIMEOUT: pwszFailureType = L"Timeout"; break;
|
|
case VSS_E_WRITERERROR_NONRETRYABLE: pwszFailureType = L"Non-Retryable"; break;
|
|
case VSS_E_WRITERERROR_RETRYABLE: pwszFailureType = L"Retryable"; break;
|
|
default: pwszFailureType = L"UNDEFINED"; break;
|
|
}
|
|
|
|
return (pwszFailureType);
|
|
}
|
|
|
|
|
|
/*
|
|
** {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
|
|
*/
|
|
ULONG FormatGUID (GUID guidValue, PWCHAR pszFormattedGUID, ULONG ulBufferLength)
|
|
{
|
|
DWORD dwStatus = 0;
|
|
|
|
|
|
if (sizeof (L"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}") > ulBufferLength)
|
|
{
|
|
dwStatus = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
|
|
if (0 == dwStatus)
|
|
{
|
|
_snwprintf (pszFormattedGUID,
|
|
ulBufferLength / sizeof (WCHAR),
|
|
L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
|
|
guidValue.Data1,
|
|
guidValue.Data2,
|
|
guidValue.Data3,
|
|
guidValue.Data4[0],
|
|
guidValue.Data4[1],
|
|
guidValue.Data4[2],
|
|
guidValue.Data4[3],
|
|
guidValue.Data4[4],
|
|
guidValue.Data4[5],
|
|
guidValue.Data4[6],
|
|
guidValue.Data4[7]);
|
|
}
|
|
|
|
|
|
return (dwStatus);
|
|
}
|
|
|
|
|
|
void PrintFiledesc (IVssWMFiledesc *pFiledesc, LPCWSTR wszDescription)
|
|
{
|
|
CComBSTR bstrPath;
|
|
CComBSTR bstrFilespec;
|
|
CComBSTR bstrAlternate;
|
|
bool bRecursive;
|
|
|
|
|
|
CHECK_SUCCESS (pFiledesc->GetPath (&bstrPath));
|
|
CHECK_SUCCESS (pFiledesc->GetFilespec (&bstrFilespec));
|
|
CHECK_NOFAIL (pFiledesc->GetRecursive (&bRecursive));
|
|
CHECK_NOFAIL (pFiledesc->GetAlternateLocation (&bstrAlternate));
|
|
|
|
wprintf (L"%s\n Path = %s, Filespec = %s, Recursive = %s\n",
|
|
wszDescription,
|
|
bstrPath,
|
|
bstrFilespec,
|
|
bRecursive ? L"yes" : L"no");
|
|
|
|
if (bstrAlternate && wcslen (bstrAlternate) > 0)
|
|
{
|
|
wprintf(L" Alternate Location = %s\n", bstrAlternate);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT GetNextCommandLine (PWSTR pwszCommandLineBuffer, ULONG ulCommandLineBufferLength)
|
|
{
|
|
UNREFERENCED_PARAMETER (pwszCommandLineBuffer);
|
|
UNREFERENCED_PARAMETER (ulCommandLineBufferLength);
|
|
|
|
|
|
g_pwchNextArgument = NULL;
|
|
|
|
_getws (pwszCommandLineBuffer);
|
|
|
|
|
|
return (NOERROR);
|
|
}
|
|
|
|
|
|
|
|
HRESULT ParseCommandLine (PWSTR pwszCommandLineBuffer, PCOMMAND_CODE peReturnedCommandCode)
|
|
{
|
|
ULONG ulIndexCommandTable;
|
|
COMMAND_CODE eCommandCode = COMMAND_UNKNOWN;
|
|
|
|
|
|
for (ulIndexCommandTable = 0;
|
|
(ulIndexCommandTable < MAX_COMMAND) && (COMMAND_UNKNOWN == eCommandCode);
|
|
ulIndexCommandTable++)
|
|
{
|
|
if (0 == _wcsnicmp (pwszCommandLineBuffer,
|
|
CommandTable [ulIndexCommandTable].pwszCommandString,
|
|
wcslen (CommandTable [ulIndexCommandTable].pwszCommandString)))
|
|
{
|
|
size_t ulCommandStringLength = wcslen (CommandTable [ulIndexCommandTable].pwszCommandString);
|
|
|
|
eCommandCode = CommandTable [ulIndexCommandTable].eCommandCode;
|
|
|
|
if ((pwszCommandLineBuffer [ulCommandStringLength + 0] == ' ') &&
|
|
(pwszCommandLineBuffer [ulCommandStringLength + 1] != '\0'))
|
|
{
|
|
g_pwchNextArgument = &pwszCommandLineBuffer [ulCommandStringLength + 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
*peReturnedCommandCode = eCommandCode;
|
|
|
|
return (NOERROR);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT InitialiseSnapshotSetContext (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
ULONG ulIndex;
|
|
|
|
|
|
pctxSnapshotSet->eCommand = COMMAND_UNKNOWN;
|
|
pctxSnapshotSet->bIncludeBootableState = false;
|
|
pctxSnapshotSet->ulVolumesInSnapshotSet = 0;
|
|
pctxSnapshotSet->pIVssBackupComponents = NULL;
|
|
pctxSnapshotSet->pIVssAsyncDoSnapshotSet = NULL;
|
|
pctxSnapshotSet->guidSnapshotSetId = GUID_NULL;
|
|
|
|
for (ulIndex = 0; ulIndex < SIZEOF_ARRAY (pctxSnapshotSet->pwszVolumeName); ulIndex++)
|
|
{
|
|
pctxSnapshotSet->pwszVolumeArgument [ulIndex] = NULL;
|
|
pctxSnapshotSet->pwszVolumeName [ulIndex] = NULL;
|
|
pctxSnapshotSet->pwszVolumeDevice [ulIndex] = NULL;
|
|
pctxSnapshotSet->pwszSnapshotDevice [ulIndex] = NULL;
|
|
pctxSnapshotSet->SnapshotProperties [ulIndex].m_SnapshotId = GUID_NULL;
|
|
pctxSnapshotSet->SnapshotId [ulIndex] = GUID_NULL;
|
|
}
|
|
|
|
|
|
pctxSnapshotSet->eState = STATE_INITIALISED;
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
|
|
HRESULT CleanupSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
ULONG ulIndex;
|
|
|
|
|
|
pctxSnapshotSet->eState = STATE_SNAPSHOT_BEING_DESTROYED;
|
|
|
|
|
|
if (GUID_NULL != pctxSnapshotSet->guidSnapshotSetId)
|
|
{
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->AbortBackup ();
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->DeleteSnapshots (pctxSnapshotSet->guidSnapshotSetId,
|
|
VSS_OBJECT_SNAPSHOT_SET,
|
|
true,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
for (ulIndex = 0; ulIndex < pctxSnapshotSet->ulVolumesInSnapshotSet; ulIndex++)
|
|
{
|
|
if (NULL != pctxSnapshotSet->pwszVolumeArgument [ulIndex])
|
|
{
|
|
free (pctxSnapshotSet->pwszVolumeArgument [ulIndex]);
|
|
}
|
|
|
|
if (NULL != pctxSnapshotSet->pwszVolumeName [ulIndex])
|
|
{
|
|
free (pctxSnapshotSet->pwszVolumeName [ulIndex]);
|
|
}
|
|
|
|
if (NULL != pctxSnapshotSet->pwszVolumeDevice [ulIndex])
|
|
{
|
|
free (pctxSnapshotSet->pwszVolumeDevice [ulIndex]);
|
|
}
|
|
|
|
if (NULL != pctxSnapshotSet->pwszSnapshotDevice [ulIndex])
|
|
{
|
|
CoTaskMemFree (pctxSnapshotSet->pwszSnapshotDevice [ulIndex]);
|
|
}
|
|
|
|
if (GUID_NULL != pctxSnapshotSet->SnapshotProperties [ulIndex].m_SnapshotId)
|
|
{
|
|
VssFreeSnapshotProperties (&pctxSnapshotSet->SnapshotProperties [ulIndex]);
|
|
}
|
|
}
|
|
|
|
|
|
if (NULL != pctxSnapshotSet->pIVssBackupComponents) pctxSnapshotSet->pIVssBackupComponents->Release ();
|
|
if (NULL != pctxSnapshotSet->pIVssAsyncDoSnapshotSet) pctxSnapshotSet->pIVssAsyncDoSnapshotSet->Release ();
|
|
|
|
|
|
InitialiseSnapshotSetContext (pctxSnapshotSet);
|
|
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
|
|
HRESULT GetVolumeNameFromArgument (LPCWSTR pwszVolumeArgument, LPWSTR *ppwszReturnedVolumeName)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
PWCHAR pwszPath = NULL;
|
|
PWCHAR pwszMountPointName = NULL;
|
|
PWCHAR pwszVolumeName = NULL;
|
|
ULONG ulPathLength = 0;
|
|
ULONG ulMountpointBufferLength = 0;
|
|
BOOL bSucceeded = FALSE;
|
|
ULONG ulVolumeNameCharacterCount = sizeof (VolumeNameTemplate);
|
|
|
|
|
|
|
|
pwszVolumeName = (PWCHAR) calloc (ulVolumeNameCharacterCount, sizeof (WCHAR));
|
|
|
|
bSucceeded = (NULL != pwszVolumeName);
|
|
|
|
|
|
if (bSucceeded)
|
|
{
|
|
ulPathLength = ExpandEnvironmentStringsW (pwszVolumeArgument, NULL, 0);
|
|
|
|
pwszPath = (PWCHAR) calloc (ulPathLength, sizeof (WCHAR));
|
|
|
|
bSucceeded = (NULL != pwszPath);
|
|
}
|
|
|
|
|
|
if (bSucceeded)
|
|
{
|
|
ulPathLength = ExpandEnvironmentStringsW (pwszVolumeArgument, pwszPath, ulPathLength);
|
|
|
|
ulMountpointBufferLength = GetFullPathName (pwszPath, 0, NULL, NULL);
|
|
|
|
pwszMountPointName = (PWCHAR) calloc (ulMountpointBufferLength, sizeof (WCHAR));
|
|
|
|
bSucceeded = (NULL != pwszMountPointName);
|
|
}
|
|
|
|
|
|
if (bSucceeded)
|
|
{
|
|
bSucceeded = GetVolumePathNameW (pwszPath, pwszMountPointName, ulMountpointBufferLength);
|
|
}
|
|
|
|
|
|
if (bSucceeded)
|
|
{
|
|
bSucceeded = GetVolumeNameForVolumeMountPointW (pwszMountPointName,
|
|
pwszVolumeName,
|
|
ulVolumeNameCharacterCount);
|
|
}
|
|
|
|
|
|
if (bSucceeded)
|
|
{
|
|
*ppwszReturnedVolumeName = pwszVolumeName;
|
|
pwszVolumeName = NULL;
|
|
}
|
|
|
|
|
|
hrStatus = GET_STATUS_FROM_BOOL (bSucceeded);
|
|
|
|
if (NULL != pwszPath) free (pwszPath);
|
|
if (NULL != pwszMountPointName) free (pwszMountPointName);
|
|
if (NULL != pwszVolumeName) free (pwszVolumeName);
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT ShowMetadata (void)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
try
|
|
{
|
|
unsigned cWriters;
|
|
CComBSTR bstrXML;
|
|
CComBSTR bstrXMLOut;
|
|
CComBSTR strSnapshotSetId = "12345678-1234-1234-1234-1234567890ab";
|
|
CComPtr<IVssBackupComponents> pvbc;
|
|
CComPtr<IVssAsync> pAsync;
|
|
|
|
|
|
CHECK_SUCCESS (CreateVssBackupComponents (&pvbc));
|
|
|
|
CHECK_SUCCESS (pvbc->InitializeForBackup ());
|
|
CHECK_SUCCESS (pvbc->SetBackupState (true, false, VSS_BT_FULL));
|
|
CHECK_NOFAIL (pvbc->GatherWriterMetadata (&pAsync));
|
|
CHECK_NOFAIL (pAsync->Wait ());
|
|
CHECK_NOFAIL (pvbc->GetWriterMetadataCount (&cWriters));
|
|
|
|
|
|
for (unsigned iWriter = 0; iWriter < cWriters; iWriter++)
|
|
{
|
|
CComPtr<IVssExamineWriterMetadata> pMetadata;
|
|
|
|
VSS_ID idInstance;
|
|
VSS_ID idInstanceT;
|
|
VSS_ID idWriter;
|
|
CComBSTR bstrWriterName;
|
|
VSS_USAGE_TYPE usage;
|
|
VSS_SOURCE_TYPE source;
|
|
WCHAR *pwszInstanceId;
|
|
WCHAR *pwszWriterId;
|
|
unsigned cIncludeFiles, cExcludeFiles, cComponents;
|
|
CComBSTR bstrPath;
|
|
CComBSTR bstrFilespec;
|
|
CComBSTR bstrAlternate;
|
|
CComBSTR bstrDestination;
|
|
|
|
|
|
|
|
CHECK_SUCCESS (pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
|
|
|
|
CHECK_SUCCESS (pMetadata->GetIdentity (&idInstanceT,
|
|
&idWriter,
|
|
&bstrWriterName,
|
|
&usage,
|
|
&source));
|
|
|
|
wprintf (L"\n\n");
|
|
|
|
if (memcmp (&idInstance, &idInstanceT, sizeof(VSS_ID)) != 0)
|
|
{
|
|
wprintf(L"Instance id mismatch\n");
|
|
DebugBreak();
|
|
}
|
|
|
|
|
|
UuidToString (&idInstance, &pwszInstanceId);
|
|
UuidToString (&idWriter, &pwszWriterId);
|
|
|
|
wprintf (L"WriterName = %s\n\n"
|
|
L" WriterId = %s\n"
|
|
L" InstanceId = %s\n"
|
|
L" UsageType = %d (%s)\n"
|
|
L" SourceType = %d (%s)\n",
|
|
bstrWriterName,
|
|
pwszWriterId,
|
|
pwszInstanceId,
|
|
usage,
|
|
GetStringFromUsageType (usage),
|
|
source,
|
|
GetStringFromSourceType (source));
|
|
|
|
RpcStringFree (&pwszInstanceId);
|
|
RpcStringFree (&pwszWriterId);
|
|
|
|
CHECK_SUCCESS(pMetadata->GetFileCounts (&cIncludeFiles,
|
|
&cExcludeFiles,
|
|
&cComponents));
|
|
|
|
for(unsigned i = 0; i < cIncludeFiles; i++)
|
|
{
|
|
CComPtr<IVssWMFiledesc> pFiledesc;
|
|
|
|
CHECK_SUCCESS (pMetadata->GetIncludeFile (i, &pFiledesc));
|
|
|
|
PrintFiledesc(pFiledesc, L"\n Include File");
|
|
}
|
|
|
|
|
|
for(i = 0; i < cExcludeFiles; i++)
|
|
{
|
|
CComPtr<IVssWMFiledesc> pFiledesc;
|
|
|
|
CHECK_SUCCESS (pMetadata->GetExcludeFile (i, &pFiledesc));
|
|
|
|
PrintFiledesc (pFiledesc, L"\n Exclude File");
|
|
}
|
|
|
|
|
|
for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
|
|
{
|
|
CComPtr<IVssWMComponent> pComponent;
|
|
PVSSCOMPONENTINFO pInfo;
|
|
|
|
CHECK_SUCCESS (pMetadata->GetComponent (iComponent, &pComponent));
|
|
CHECK_SUCCESS (pComponent->GetComponentInfo (&pInfo));
|
|
|
|
wprintf (L"\n"
|
|
L" Component %d, type = %d (%s)\n"
|
|
L" LogicalPath = %s\n"
|
|
L" Name = %s\n"
|
|
L" Caption = %s\n",
|
|
iComponent,
|
|
pInfo->type,
|
|
GetStringFromComponentType (pInfo->type),
|
|
pInfo->bstrLogicalPath,
|
|
pInfo->bstrComponentName,
|
|
pInfo->bstrCaption);
|
|
|
|
|
|
|
|
if (pInfo->cbIcon > 0)
|
|
{
|
|
if (pInfo->cbIcon != 10 ||
|
|
pInfo->pbIcon[0] != 1 ||
|
|
pInfo->pbIcon[1] != 2 ||
|
|
pInfo->pbIcon[2] != 3 ||
|
|
pInfo->pbIcon[3] != 4 ||
|
|
pInfo->pbIcon[4] != 5 ||
|
|
pInfo->pbIcon[5] != 6 ||
|
|
pInfo->pbIcon[6] != 7 ||
|
|
pInfo->pbIcon[7] != 8 ||
|
|
pInfo->pbIcon[8] != 9 ||
|
|
pInfo->pbIcon[9] != 10)
|
|
{
|
|
wprintf(L" Icon is not valid.\n");
|
|
DebugBreak();
|
|
}
|
|
else
|
|
wprintf(L" Icon is valid.\n");
|
|
}
|
|
|
|
wprintf (L" RestoreMetadata = %s\n"
|
|
L" NotifyOnBackupComplete = %s\n"
|
|
L" Selectable = %s\n",
|
|
pInfo->bRestoreMetadata ? L"yes" : L"no",
|
|
pInfo->bNotifyOnBackupComplete ? L"yes" : L"no",
|
|
pInfo->bSelectable ? L"yes" : L"no");
|
|
|
|
|
|
if (pInfo->cFileCount > 0)
|
|
{
|
|
for(i = 0; i < pInfo->cFileCount; i++)
|
|
{
|
|
CComPtr<IVssWMFiledesc> pFiledesc;
|
|
|
|
CHECK_SUCCESS (pComponent->GetFile (i, &pFiledesc));
|
|
|
|
PrintFiledesc (pFiledesc, L" FileGroupFile");
|
|
}
|
|
}
|
|
|
|
if (pInfo->cDatabases > 0)
|
|
{
|
|
for(i = 0; i < pInfo->cDatabases; i++)
|
|
{
|
|
CComPtr<IVssWMFiledesc> pFiledesc;
|
|
|
|
CHECK_SUCCESS (pComponent->GetDatabaseFile (i, &pFiledesc));
|
|
|
|
PrintFiledesc (pFiledesc, L" DatabaseFile");
|
|
}
|
|
}
|
|
|
|
|
|
if (pInfo->cLogFiles > 0)
|
|
{
|
|
for(i = 0; i < pInfo->cLogFiles; i++)
|
|
{
|
|
CComPtr<IVssWMFiledesc> pFiledesc;
|
|
|
|
CHECK_SUCCESS (pComponent->GetDatabaseLogFile (i, &pFiledesc));
|
|
|
|
PrintFiledesc (pFiledesc, L" DatabaseLogFile");
|
|
}
|
|
}
|
|
|
|
pComponent->FreeComponentInfo (pInfo);
|
|
}
|
|
|
|
|
|
|
|
VSS_RESTOREMETHOD_ENUM method;
|
|
CComBSTR bstrUserProcedure;
|
|
CComBSTR bstrService;
|
|
VSS_WRITERRESTORE_ENUM writerRestore;
|
|
unsigned cMappings;
|
|
bool bRebootRequired;
|
|
|
|
CHECK_NOFAIL (pMetadata->GetRestoreMethod (&method,
|
|
&bstrService,
|
|
&bstrUserProcedure,
|
|
&writerRestore,
|
|
&bRebootRequired,
|
|
&cMappings));
|
|
|
|
|
|
wprintf (L"\n"
|
|
L" Restore method = %d (%s)\n"
|
|
L" Service = %d\n"
|
|
L" User Procedure = %s\n"
|
|
L" WriterRestore = %d (%s)\n"
|
|
L" RebootRequired = %s\n",
|
|
method,
|
|
GetStringFromRestoreMethod (method),
|
|
bstrService,
|
|
bstrUserProcedure,
|
|
writerRestore,
|
|
GetStringFromWriterRestoreMethod (writerRestore),
|
|
bRebootRequired ? L"yes" : L"no");
|
|
|
|
for(i = 0; i < cMappings; i++)
|
|
{
|
|
CComPtr<IVssWMFiledesc> pFiledesc;
|
|
|
|
CHECK_SUCCESS (pMetadata->GetAlternateLocationMapping (i, &pFiledesc));
|
|
|
|
PrintFiledesc (pFiledesc, L" AlternateMapping");
|
|
}
|
|
}
|
|
|
|
|
|
CHECK_SUCCESS (pvbc->FreeWriterMetadata());
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
if (FAILED(hr)) wprintf (L"Failed with 0x%08X.\n", hr);
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT ShowWriters (void)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
try
|
|
{
|
|
unsigned cWriters;
|
|
CComBSTR bstrXML;
|
|
CComBSTR bstrXMLOut;
|
|
CComBSTR strSnapshotSetId = "12345678-1234-1234-1234-1234567890ab";
|
|
CComPtr<IVssBackupComponents> pvbc;
|
|
CComPtr<IVssAsync> pIVssAsync;
|
|
|
|
|
|
CHECK_SUCCESS (CreateVssBackupComponents (&pvbc));
|
|
|
|
CHECK_SUCCESS (pvbc->InitializeForBackup ());
|
|
CHECK_SUCCESS (pvbc->SetBackupState (true, false, VSS_BT_FULL));
|
|
CHECK_NOFAIL (pvbc->GatherWriterMetadata (&pIVssAsync));
|
|
CHECK_NOFAIL (pIVssAsync->Wait ());
|
|
CHECK_NOFAIL (pvbc->GetWriterMetadataCount (&cWriters));
|
|
|
|
|
|
for (unsigned iWriter = 0; iWriter < cWriters; iWriter++)
|
|
{
|
|
CComPtr<IVssExamineWriterMetadata> pMetadata;
|
|
|
|
VSS_ID idInstance;
|
|
VSS_ID idInstanceT;
|
|
VSS_ID idWriter;
|
|
CComBSTR bstrWriterName;
|
|
VSS_USAGE_TYPE usage;
|
|
VSS_SOURCE_TYPE source;
|
|
WCHAR *pwszInstanceId;
|
|
WCHAR *pwszWriterId;
|
|
CComBSTR bstrPath;
|
|
CComBSTR bstrFilespec;
|
|
CComBSTR bstrAlternate;
|
|
CComBSTR bstrDestination;
|
|
|
|
|
|
|
|
CHECK_SUCCESS (pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
|
|
|
|
CHECK_SUCCESS (pMetadata->GetIdentity (&idInstanceT,
|
|
&idWriter,
|
|
&bstrWriterName,
|
|
&usage,
|
|
&source));
|
|
|
|
wprintf (L"\n\n");
|
|
|
|
if (memcmp (&idInstance, &idInstanceT, sizeof(VSS_ID)) != 0)
|
|
{
|
|
wprintf(L"Instance id mismatch\n");
|
|
DebugBreak();
|
|
}
|
|
|
|
|
|
UuidToString (&idInstance, &pwszInstanceId);
|
|
UuidToString (&idWriter, &pwszWriterId);
|
|
|
|
wprintf (L"WriterName = %s\n\n"
|
|
L" WriterId = %s\n"
|
|
L" InstanceId = %s\n"
|
|
L" UsageType = %d (%s)\n"
|
|
L" SourceType = %d (%s)\n",
|
|
bstrWriterName,
|
|
pwszWriterId,
|
|
pwszInstanceId,
|
|
usage,
|
|
GetStringFromUsageType (usage),
|
|
source,
|
|
GetStringFromSourceType (source));
|
|
|
|
RpcStringFree (&pwszInstanceId);
|
|
RpcStringFree (&pwszWriterId);
|
|
}
|
|
|
|
|
|
CHECK_SUCCESS (pvbc->FreeWriterMetadata());
|
|
}
|
|
catch(...)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
if (FAILED(hr)) wprintf (L"Failed with 0x%08X.\n", hr);
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT ShowAnnouncement (void)
|
|
{
|
|
wprintf (L"\n"
|
|
L"\t%s\n\n"
|
|
L"\t\n",
|
|
PROGRAM_TITLE);
|
|
|
|
|
|
return (NOERROR);
|
|
}
|
|
|
|
|
|
|
|
HRESULT ShowHelp (void)
|
|
{
|
|
wprintf (L"\n\n"
|
|
L"\t%s\n\n"
|
|
L"\t\n"
|
|
L"\t Commands:\n"
|
|
L"\t\n"
|
|
L"\t help\n"
|
|
L"\t exit\n"
|
|
L"\t quit\n"
|
|
L"\t metadata\n"
|
|
L"\t writers\n"
|
|
L"\t set\n"
|
|
L"\t add\n"
|
|
L"\t create\n"
|
|
L"\t delete\n"
|
|
L"\t\n"
|
|
L"\t\n"
|
|
L"\tOnce the snapshots are created use DosDev to map a drive letter to\n"
|
|
L"\tthe snapshot devices for convenient access\n"
|
|
L"\t\n"
|
|
L"\te.g. DosDev u: \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeSnapshot1\n"
|
|
L"\t\n",
|
|
PROGRAM_TITLE);
|
|
|
|
|
|
return (NOERROR);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT CreateSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
PIVssAsync pIVssAsync;
|
|
|
|
|
|
hrStatus = CreateVssBackupComponents (&pctxSnapshotSet->pIVssBackupComponents);
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->InitializeForBackup ();
|
|
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->GatherWriterMetadata (&pIVssAsync);
|
|
hrStatus = pIVssAsync->Wait ();
|
|
hrStatus = pIVssAsync->QueryStatus (&hrStatus, NULL);
|
|
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->SetBackupState (true,
|
|
pctxSnapshotSet->bIncludeBootableState,
|
|
VSS_BT_FULL);
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->StartSnapshotSet (&pctxSnapshotSet->guidSnapshotSetId);
|
|
|
|
|
|
if (SUCCEEDED (hrStatus))
|
|
{
|
|
WCHAR awchGuidBuffer [65];
|
|
|
|
|
|
FormatGUID (pctxSnapshotSet->guidSnapshotSetId,
|
|
awchGuidBuffer,
|
|
sizeof (awchGuidBuffer));
|
|
|
|
wprintf (L"Created snapshot set %s\n\n", awchGuidBuffer);
|
|
|
|
pctxSnapshotSet->eState = STATE_SNAPSHOT_SET_CREATED;
|
|
}
|
|
|
|
else
|
|
{
|
|
wprintf (L"ERROR - Unable to create snapshot set (0x%08X)\n\n", hrStatus);
|
|
}
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
|
|
HRESULT AddVolume (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
size_t ulArgumentLength = 0;
|
|
ULONG ulIndexVolume = 0;
|
|
BOOL bSupported = FALSE;
|
|
|
|
|
|
if (STATE_SNAPSHOT_SET_CREATED != pctxSnapshotSet->eState)
|
|
{
|
|
wprintf (L"ERROR - Unable to add volumes add this time (%d)\n\n", pctxSnapshotSet->eState);
|
|
}
|
|
|
|
|
|
else if (pctxSnapshotSet->ulVolumesInSnapshotSet >= SIZEOF_ARRAY (pctxSnapshotSet->pwszVolumeArgument))
|
|
{
|
|
wprintf (L"ERROR - Maximum number of volumes already present in snapshot set\n\n");
|
|
}
|
|
|
|
|
|
else if ((NULL != g_pwchNextArgument) && (ulArgumentLength = wcslen (g_pwchNextArgument)) > 0)
|
|
{
|
|
ulIndexVolume = pctxSnapshotSet->ulVolumesInSnapshotSet;
|
|
|
|
pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume] = (PWSTR) calloc (ulArgumentLength + 1, sizeof (WCHAR));
|
|
|
|
wcscpy (pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume], g_pwchNextArgument);
|
|
|
|
hrStatus = GetVolumeNameFromArgument (pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume],
|
|
&pctxSnapshotSet->pwszVolumeName [ulIndexVolume]);
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->IsVolumeSupported (GUID_NULL,
|
|
pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
|
|
&bSupported);
|
|
|
|
if (bSupported)
|
|
{
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->AddToSnapshotSet (pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
|
|
GUID_NULL,
|
|
&pctxSnapshotSet->SnapshotId [ulIndexVolume]);
|
|
|
|
if (SUCCEEDED (hrStatus))
|
|
{
|
|
pctxSnapshotSet->ulVolumesInSnapshotSet++;
|
|
|
|
wprintf (L"Added volume '%s' (%s) to snapshot set\n\n",
|
|
pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
|
|
pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume]);
|
|
}
|
|
|
|
else
|
|
{
|
|
wprintf (L"ERROR - Unable to add volume '%s' (%s) to snapshot set (0x%08X)\n\n",
|
|
pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
|
|
pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume],
|
|
hrStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
else
|
|
{
|
|
wprintf (L"ERROR - Missing argument\n\n");
|
|
}
|
|
|
|
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
HRESULT CreateSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
ULONG ulIndexVolume = 0;
|
|
PIVssAsync pIVssAsync;
|
|
|
|
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->PrepareForBackup (&pIVssAsync);
|
|
hrStatus = pIVssAsync->Wait ();
|
|
hrStatus = pIVssAsync->QueryStatus (&hrStatus, NULL);
|
|
|
|
|
|
/*
|
|
** Could check the status of all the writers at this point but we choose to press on regardless.
|
|
*/
|
|
|
|
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->DoSnapshotSet (&pctxSnapshotSet->pIVssAsyncDoSnapshotSet);
|
|
hrStatus = pctxSnapshotSet->pIVssAsyncDoSnapshotSet->Wait ();
|
|
hrStatus = pctxSnapshotSet->pIVssAsyncDoSnapshotSet->QueryStatus (&hrStatus, NULL);
|
|
|
|
|
|
/*
|
|
** Could check the status of all the writers at this point but we choose to press on regardless.
|
|
*/
|
|
|
|
|
|
for (ulIndexVolume = 0; ulIndexVolume < pctxSnapshotSet->ulVolumesInSnapshotSet; ulIndexVolume++)
|
|
{
|
|
hrStatus = pctxSnapshotSet->pIVssBackupComponents->GetSnapshotProperties (pctxSnapshotSet->SnapshotId [ulIndexVolume],
|
|
&pctxSnapshotSet->SnapshotProperties [ulIndexVolume]);
|
|
}
|
|
|
|
|
|
|
|
wprintf (L"Created snapshots for the following volume%s:\n",
|
|
pctxSnapshotSet->ulVolumesInSnapshotSet > 1 ? "s" : "");
|
|
|
|
for (ulIndexVolume = 0; ulIndexVolume < pctxSnapshotSet->ulVolumesInSnapshotSet; ulIndexVolume++)
|
|
{
|
|
wprintf (L" %s for volume %s (%s)\n",
|
|
pctxSnapshotSet->SnapshotProperties [ulIndexVolume].m_pwszSnapshotDeviceObject,
|
|
pctxSnapshotSet->pwszVolumeName [ulIndexVolume], // or SnapshotProperties [ulIndexVolume].m_pwszSnapshotOriginalVolumeName
|
|
pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume]);
|
|
}
|
|
|
|
|
|
wprintf (L"\n");
|
|
|
|
|
|
return (hrStatus);
|
|
}
|
|
|
|
|
|
HRESULT DeleteSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
|
|
{
|
|
HRESULT hrStatus = NOERROR;
|
|
|
|
CleanupSnapshotSet (pctxSnapshotSet);
|
|
|
|
|
|
return (hrStatus);
|
|
}
|