/* **++ ** ** Copyright (c) 2000-2001 Microsoft Corporation ** ** ** Module Name: ** ** simsnap.cpp ** ** ** Abstract: ** ** Test program to drive the VSS Writer Shim contained in VssAPI.DLL ** ** ** Author: ** ** Michael C. Johnson [mikejohn] 24-May-2000 ** ** ** Revision History: ** ** X-5 MCJ Michael C. Johnson 18-Sep-2000 ** 176860: Add the missing calling convention specifiers ** ** X-4 MCJ Michael C. Johnson 23-Jun-2000 ** Set the writer failure status. ** ** X-3 MCJ Michael C. Johnson 15-Jun-2000 ** Add some additional event routines and the ability to act ** as various types of writer. ** ** X-2 MCJ Michael C. Johnson 26-May-2000 ** Add some extra tests to validate shim is properly sensitive ** to volume name array contents. **-- */ /* ** Defines ** ** ** C4290: C++ Exception Specification ignored ** warning C4511: 'CVssCOMApplication' : copy constructor could not be generated ** warning C4127: conditional expression is constant */ #pragma warning(disable:4290) #pragma warning(disable:4511) #pragma warning(disable:4127) /* ** Includes */ #include #include #include #include #include #include #include #include #include #define GET_STATUS_FROM_BOOL(_bSucceeded) ((_bSucceeded) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError())) #define GET_STATUS_FROM_HANDLE(_handle) ((NULL != (_handle)) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError())) #define GET_STATUS_FROM_POINTER(_ptr) ((NULL != (_ptr)) ? NOERROR : E_OUTOFMEMORY) #define SIZEOF_ARRAY(_aBase) (sizeof (_aBase) / sizeof ((_aBase)[0])) typedef enum FAIL_PHASE { PHASE_UNDEFINED = 0, PHASE_IDENTIFY, PHASE_PREPARE_FOR_BACKUP, PHASE_PREPARE_FOR_SNAPSHOT, PHASE_FREEZE, PHASE_THAW, PHASE_ABORT, PHASE_BACKUP_COMPLETE, PHASE_RESTORE } FAIL_PHASE; HRESULT SelectFailureStatus (VOID) { HRESULT hrStatus; switch (rand () / (RAND_MAX / 5)) { case 0: hrStatus = VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT; break; case 1: hrStatus = VSS_E_WRITERERROR_OUTOFRESOURCES; break; case 2: hrStatus = VSS_E_WRITERERROR_TIMEOUT; break; case 3: hrStatus = VSS_E_WRITERERROR_NONRETRYABLE; break; case 4: hrStatus = VSS_E_WRITERERROR_RETRYABLE; break; default: assert (FALSE); break; } return (hrStatus); } 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); } LPCWSTR GetStringFromWriterType (VSS_USAGE_TYPE wtWriterType) { LPCWSTR pwszWriterType; switch (wtWriterType) { case VSS_UT_BOOTABLESYSTEMSTATE: pwszWriterType = L"BootableSystemState"; break; case VSS_UT_SYSTEMSERVICE: pwszWriterType = L"SystemServiceState"; break; case VSS_UT_USERDATA: pwszWriterType = L"UserData"; break; case VSS_UT_OTHER: pwszWriterType = L"Other"; break; default: pwszWriterType = L"UNDEFINED"; break; } return (pwszWriterType); } LPCWSTR GetStringFromFailPhase (FAIL_PHASE fpFailPhase) { LPCWSTR pwszFailPhase; switch (fpFailPhase) { case PHASE_IDENTIFY: pwszFailPhase = L"Identify"; break; case PHASE_PREPARE_FOR_BACKUP: pwszFailPhase = L"PrepareForBackup"; break; case PHASE_PREPARE_FOR_SNAPSHOT: pwszFailPhase = L"PrepareForSnapshot"; break; case PHASE_FREEZE: pwszFailPhase = L"Freeze"; break; case PHASE_THAW: pwszFailPhase = L"Thaw"; break; case PHASE_ABORT: pwszFailPhase = L"Abort"; break; case PHASE_BACKUP_COMPLETE: pwszFailPhase = L"BackupComplete"; break; case PHASE_RESTORE: pwszFailPhase = L"Restore"; break; default: pwszFailPhase = L"UNDEFINED"; break; } return (pwszFailPhase); } static volatile BOOL bContinue = TRUE; static volatile FAIL_PHASE fpFailPhase = PHASE_FREEZE; class CVssWriterFailSnap : public CVssWriter { public: bool STDMETHODCALLTYPE OnIdentify (IVssCreateWriterMetadata *pIVssCreateWriterMetadata); bool STDMETHODCALLTYPE OnPrepareBackup (IVssWriterComponents *pIVssWriterComponents); bool STDMETHODCALLTYPE OnPrepareSnapshot (); bool STDMETHODCALLTYPE OnFreeze (); bool STDMETHODCALLTYPE OnThaw (); bool STDMETHODCALLTYPE OnAbort (); bool STDMETHODCALLTYPE OnBackupComplete (IVssWriterComponents *pIVssWriterComponents); bool STDMETHODCALLTYPE OnPostRestore (IVssWriterComponents *pIVssWriterComponents); }; bool STDMETHODCALLTYPE CVssWriterFailSnap::OnIdentify (IVssCreateWriterMetadata *pIVssCreateWriterMetadata) { bool bPhaseSucceeded = (PHASE_IDENTIFY != fpFailPhase); HRESULT hrStatus = SelectFailureStatus (); if (bPhaseSucceeded) { hrStatus = pIVssCreateWriterMetadata->AddComponent (VSS_CT_FILEGROUP, NULL, L"Failsnap Writer Component", L"Failsnap Writer Caption", NULL, // icon 0, true, false, false); bPhaseSucceeded = SUCCEEDED (hrStatus); } wprintf (L"\nThreadId 0x%04x - Received event - OnIdentify ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnPrepareBackup (IVssWriterComponents *pIVssWriterComponents) { bool bPhaseSucceeded = (PHASE_PREPARE_FOR_BACKUP != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnPrepareBackup ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnPrepareSnapshot () { bool bPhaseSucceeded = (PHASE_PREPARE_FOR_SNAPSHOT != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnPrepareSnapshot ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnFreeze () { bool bPhaseSucceeded = (PHASE_FREEZE != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnFreeze ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnThaw () { bool bPhaseSucceeded = (PHASE_THAW != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnThaw ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnAbort () { bool bPhaseSucceeded = (PHASE_ABORT != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnAbort ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnBackupComplete (IVssWriterComponents *pIVssWriterComponents) { bool bPhaseSucceeded = (PHASE_BACKUP_COMPLETE != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnBackupComplete ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } bool STDMETHODCALLTYPE CVssWriterFailSnap::OnPostRestore (IVssWriterComponents *pIVssWriterComponents) { bool bPhaseSucceeded = (PHASE_RESTORE != fpFailPhase); HRESULT hrStatus = bPhaseSucceeded ? NOERROR : SelectFailureStatus (); wprintf (L"\nThreadId 0x%04x - Received event - OnPostRestore ()%s%s", GetCurrentThreadId (), bPhaseSucceeded ? L"" : L" - FAILED ", GetStringFromFailureType (hrStatus)); if (!bPhaseSucceeded) { SetWriterFailure (hrStatus); } return (bPhaseSucceeded); } static BOOL AssertPrivilege (LPCWSTR privName) { HANDLE tokenHandle; BOOL stat = FALSE; if (OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES, &tokenHandle)) { LUID value; if (LookupPrivilegeValue (NULL, privName, &value)) { TOKEN_PRIVILEGES newState; DWORD error; newState.PrivilegeCount = 1; newState.Privileges[0].Luid = value; newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; /* ** We will always call GetLastError below, so clear ** any prior error values on this thread. */ SetLastError (ERROR_SUCCESS); stat = 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. */ if ((error = GetLastError()) != ERROR_SUCCESS) { stat = FALSE; } if (!stat) { wprintf (L"AdjustTokenPrivileges for %s failed with 0x%08X", privName, error); } } CloseHandle (tokenHandle); } return stat; } BOOL WINAPI CtrlC_HandlerRoutine (IN DWORD /* dwType */) { bContinue = FALSE; // Mark that the break was handled. return TRUE; } extern "C" int __cdecl wmain (int argc, WCHAR *argv[]) { HRESULT hrStatus = NOERROR; CVssWriterFailSnap *pCVssWriterFailSnap = NULL; BOOL bSucceeded = FALSE; BOOL bComInitialized = FALSE; BOOL bSubscribed = FALSE; VSS_USAGE_TYPE wtWriterType = VSS_UT_USERDATA; const GUID guidIdWriter = {0xd335a99e, 0x57fb, 0x4b80, {0x85, 0xb1, 0x15, 0xda, 0xa7, 0xc7, 0x4e, 0x14}}; srand ((unsigned)time (NULL)); SetConsoleCtrlHandler(CtrlC_HandlerRoutine, TRUE); if ((argc >= 2) && (wcslen (argv[1]) > 0)) { switch (*argv[1]) { case L'I': case L'i': fpFailPhase = PHASE_IDENTIFY; break; case L'B': case L'b': fpFailPhase = PHASE_PREPARE_FOR_BACKUP; break; case L'S': case L's': fpFailPhase = PHASE_PREPARE_FOR_SNAPSHOT; break; case L'F': case L'f': fpFailPhase = PHASE_FREEZE; break; case L'T': case L't': fpFailPhase = PHASE_THAW; break; case L'A': case L'a': fpFailPhase = PHASE_ABORT; break; case L'C': case L'c': fpFailPhase = PHASE_BACKUP_COMPLETE; break; case L'R': case L'r': fpFailPhase = PHASE_RESTORE; break; default: wprintf (L"\nFAILSNAP [phase] [writer type]" L"\n\n\tFailPhases" L"\n\t\ti - Identify" L"\n\t\tb - PrepareForBackup" L"\n\t\ts - PrepareForSnapshot" L"\n\t\tf - Freeze (default)" L"\n\t\tt - Thaw" L"\n\t\ta - Abort" L"\n\t\tc - BackupComplete" L"\n\t\tr - PostRestore" L"\n\n\tWriterTypes" L"\n\t\tb - BootableState writer" L"\n\t\ts - ServiceState writer" L"\n\t\tu - UserData writer (default)" L"\n\t\to - Other writer" L"\n"); bContinue = FALSE; break; } } if ((argc >= 3) && (wcslen (argv[2]) > 0)) { switch (*argv[2]) { case L'B': case L'b': wtWriterType = VSS_UT_BOOTABLESYSTEMSTATE; break; case L'S': case L's': wtWriterType = VSS_UT_SYSTEMSERVICE; break; case L'U': case L'u': wtWriterType = VSS_UT_USERDATA; break; case L'O': case L'o': wtWriterType = VSS_UT_OTHER; break; default: bContinue = FALSE; break; } } if (bContinue) { wprintf (L"\nSetting up %s writer to fail %s requests (ProcessId 0x%04x)", GetStringFromWriterType (wtWriterType), GetStringFromFailPhase (fpFailPhase), GetCurrentProcessId ()); wprintf (L"\nChecking privileges"); bSubscribed = AssertPrivilege (SE_BACKUP_NAME); hrStatus = GET_STATUS_FROM_BOOL (bSucceeded); if (FAILED (hrStatus)) { wprintf (L"\nAssertPrivilege returned error 0x%08X", hrStatus); } } if (bContinue && SUCCEEDED (hrStatus)) { wprintf (L"\nInitializing COM"); hrStatus = CoInitializeEx (NULL, COINIT_MULTITHREADED); if (FAILED (hrStatus)) { wprintf (L"\nCoInitialize() returned error 0x%08X", hrStatus); } else { bComInitialized = TRUE; } } if (bContinue && SUCCEEDED (hrStatus)) { wprintf (L"\nConstructing Writer"); pCVssWriterFailSnap = new CVssWriterFailSnap; if (NULL == pCVssWriterFailSnap) { hrStatus = HRESULT_FROM_WIN32 (ERROR_NOT_ENOUGH_MEMORY); wprintf (L"\nFailed to allocate CVssWriterFailSnap : 0x%08X", hrStatus); } } if (bContinue && SUCCEEDED (hrStatus)) { WCHAR awchWriterName [256]; wprintf (L"\nInitialising the writer"); _snwprintf (awchWriterName, SIZEOF_ARRAY (awchWriterName), L"Microsoft Test Writer - FailSnap (%s/%s/0x%04x)", GetStringFromWriterType (wtWriterType), GetStringFromFailPhase (fpFailPhase), GetCurrentProcessId ()); hrStatus = pCVssWriterFailSnap->Initialize (guidIdWriter, awchWriterName, wtWriterType, VSS_ST_OTHER); if (FAILED (hrStatus)) { wprintf (L"\nFailed to initialize the writer : 0x%08X", hrStatus); } } if (bContinue && SUCCEEDED (hrStatus)) { wprintf (L"\nSubscribing to snapshot events"); hrStatus = pCVssWriterFailSnap->Subscribe (); if (FAILED (hrStatus)) { wprintf (L"\nFailed to subscribe to snapshot events : 0x%08X", hrStatus); } else { bSubscribed = TRUE; } } if (bContinue && SUCCEEDED (hrStatus)) { wprintf (L"\nWaiting for snapshot events (or Ctrl-C)"); while (bContinue) { Sleep (100); } } if (bSubscribed) { wprintf (L"\nUn-Subscribing from snapshot events"); pCVssWriterFailSnap->Unsubscribe (); } if (NULL != pCVssWriterFailSnap) { wprintf (L"\nDeconstructing Writer"); delete pCVssWriterFailSnap; } if (bComInitialized) { wprintf (L"\nUnInitialising COM"); CoUninitialize(); } return (hrStatus); }