/*++ Copyright (c) 1999 Microsoft Corporation Abstract: @doc @module VsWriter.cpp | Implementation of Writer @end Author: Adi Oltean [aoltean] 02/02/2000 TBD: Add comments. Revision History: Name Date Comments brianb 03/28/2000 Created mikejohn 05/18/2000 ~CVssWriter() should check that wrapper exists before calling it mikejohn 06/23/2000 Add external entry point for SetWriterFailure() mikejohn 09/01/2000 Add extra tracing to identify writers in trace output mikejohn 09/18/2000 176860: Added calling convention methods where missing ssteiner 02/14/2001 Changed class interface to version 2. --*/ #include #include "vs_inc.hxx" #include "vs_sec.hxx" #include "vs_idl.hxx" #include "vs_reg.hxx" #include "comadmin.hxx" #include "vswriter.h" #include "vsevent.h" #include "vsbackup.h" #include "vswrtimp.h" #include "vs_wmxml.hxx" #include "vs_cmxml.hxx" extern WCHAR g_ComponentMetadataXML[]; static LPCWSTR x_wszElementRoot = L"root"; static LPCWSTR x_wszElementSnapshotSetDescription = L"SNAPSHOT_SET_DESCRIPTION"; static LPCWSTR x_wszAttrSnapshotSetId = L"snapshotSetId"; static LPCWSTR x_wszAttrXmlns = L"xmlns"; static LPCWSTR x_wszValueXmlns = L"x-schema:#VssComponentMetadata"; static LPCWSTR x_wszAttrContext = L"context"; //////////////////////////////////////////////////////////////////////// // 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 "WSHVWRTC" // //////////////////////////////////////////////////////////////////////// static 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); } static 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); } static LPCWSTR GetStringFromAlternateWriterState (VSS_ALTERNATE_WRITER_STATE aws) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (aws) { case VSS_AWS_UNDEFINED: pwszRetString = L"Undefined"; break; case VSS_AWS_NO_ALTERNATE_WRITER: pwszRetString = L"No alternate writer"; break; case VSS_AWS_ALTERNATE_WRITER_EXISTS: pwszRetString = L"Alternate writer exists"; break; case VSS_AWS_THIS_IS_ALTERNATE_WRITER: pwszRetString = L"This is the alternate writer"; break; default: break; } return (pwszRetString); } static LPCWSTR GetStringFromApplicationLevel (VSS_APPLICATION_LEVEL eApplicationLevel) { LPCWSTR pwszRetString = L"UNDEFINED"; switch (eApplicationLevel) { case VSS_APP_UNKNOWN: pwszRetString = L"Unknown"; break; case VSS_APP_SYSTEM: pwszRetString = L"System"; break; case VSS_APP_BACK_END: pwszRetString = L"BackEnd"; break; case VSS_APP_FRONT_END: pwszRetString = L"FrontEnd"; break; case VSS_APP_AUTO: pwszRetString = L"Automatic"; break; default: break; } return (pwszRetString); } // constructor __declspec(dllexport) STDMETHODCALLTYPE CVssWriter::CVssWriter() : m_pWrapper(NULL) { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::CVssWriter"); ft.Trace(VSSDBG_GEN, L"**** Constructor: THIS = %p", this); } // destructor __declspec(dllexport) STDMETHODCALLTYPE CVssWriter::~CVssWriter() { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::CVssWriter"); ft.Trace(VSSDBG_GEN, L"**** Destructor: THIS = %p", this); if (NULL != m_pWrapper) { ft.Trace(VSSDBG_GEN, L"**** Calling CVssWriter::Uninitialize() [%p]", this); m_pWrapper->Uninitialize(); #ifdef _DEBUG LONG cRef = #endif m_pWrapper->Release(); #ifdef _DEBUG ft.Trace(VSSDBG_GEN, L"**** Final reference count for Wrapper = %ld - [%p]", cRef, this); #endif // disable for now // BS_ASSERT(cRef == 0); } } // default OnPrepareBackup method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnPrepareBackup(IN IVssWriterComponents *pComponent) { UNREFERENCED_PARAMETER(pComponent); return true; } // default OnIdentify method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnIdentify(IN IVssCreateWriterMetadata *pMetadata) { UNREFERENCED_PARAMETER(pMetadata); return true; } // default OnBackupComplete method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnBackupComplete(IN IVssWriterComponents *pComponent) { UNREFERENCED_PARAMETER(pComponent); return true; } // default OnBackupShutdown method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnBackupShutdown(IN VSS_ID SnapshotSetId) { UNREFERENCED_PARAMETER(SnapshotSetId); return true; } // default OnPreRestore method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnPreRestore(IN IVssWriterComponents *pComponent) { UNREFERENCED_PARAMETER(pComponent); return true; } // default OnPostRestore method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnPostRestore(IN IVssWriterComponents *pComponent) { UNREFERENCED_PARAMETER(pComponent); return true; } // default OnPostSnapshot method __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnPostSnapshot(IN IVssWriterComponents *pComponent) { UNREFERENCED_PARAMETER(pComponent); return true; } // default OnBackOffIOOnVolume __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnBackOffIOOnVolume ( IN VSS_PWSZ wszVolumeName, IN VSS_ID snapshotId, IN VSS_ID providerId ) { UNREFERENCED_PARAMETER(wszVolumeName); UNREFERENCED_PARAMETER(snapshotId); UNREFERENCED_PARAMETER(providerId); return true; } // default OnContinueIOOnVolume __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnContinueIOOnVolume ( IN VSS_PWSZ wszVolumeName, IN VSS_ID snapshotId, IN VSS_ID providerId ) { UNREFERENCED_PARAMETER(wszVolumeName); UNREFERENCED_PARAMETER(snapshotId); UNREFERENCED_PARAMETER(providerId); return true; } // default OnVSSShutdown __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnVSSShutdown() { return true; } // default OnVSSApplicationStartup __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::OnVSSApplicationStartup() { return true; } // initialize the writer // This function returns S_FALSE when the writer is inactive (setup or safe mode) __declspec(dllexport) HRESULT STDMETHODCALLTYPE CVssWriter::Initialize ( IN VSS_ID WriterID, IN LPCWSTR wszWriterName, IN VSS_USAGE_TYPE ut, IN VSS_SOURCE_TYPE st, IN VSS_APPLICATION_LEVEL nLevel, IN DWORD dwTimeoutFreeze, IN VSS_ALTERNATE_WRITER_STATE aws, IN bool bIOThrottlingOnly, IN LPCWSTR wszReserved ) { UNREFERENCED_PARAMETER(wszReserved); CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::Initialize"); try { ft.Trace (VSSDBG_SHIM, L"Called CVssWriter::Initialize() with:"); ft.Trace (VSSDBG_SHIM, L" WriterId = " WSTR_GUID_FMT, GUID_PRINTF_ARG (WriterID)); ft.Trace (VSSDBG_SHIM, L" WriterName = %s", (NULL == wszWriterName) ? L"(NULL)" : wszWriterName); ft.Trace (VSSDBG_SHIM, L" UsageType = %s", GetStringFromUsageType (ut)); ft.Trace (VSSDBG_SHIM, L" SourceType = %s", GetStringFromSourceType (st)); ft.Trace (VSSDBG_SHIM, L" AppLevel = %s", GetStringFromApplicationLevel (nLevel)); ft.Trace (VSSDBG_SHIM, L" FreezeTimeout = %d (ms)", dwTimeoutFreeze); ft.Trace (VSSDBG_SHIM, L" AlternateWriterState = %s", GetStringFromAlternateWriterState(aws)); ft.Trace (VSSDBG_SHIM, L" IOThrottlingOnly = %s", bIOThrottlingOnly ? L"True" : L"False"); // The V2 parameters can only be set with default values if (aws != VSS_AWS_NO_ALTERNATE_WRITER || bIOThrottlingOnly != false) return E_INVALIDARG; if (ut != VSS_UT_BOOTABLESYSTEMSTATE && ut != VSS_UT_SYSTEMSERVICE && ut != VSS_UT_USERDATA && ut != VSS_UT_OTHER) return E_INVALIDARG; // [aoltean] Previous comment was: // return S_OK for now since there is a bug in the iis writer // return S_OK; if (st != VSS_ST_NONTRANSACTEDDB && st != VSS_ST_TRANSACTEDDB && st != VSS_ST_OTHER) return E_INVALIDARG; // [aoltean] Previous comment was: // return S_OK for now since there is a bug in the IIS writer // return S_OK; CVssWriterImpl::CreateWriter(this, &m_pWrapper); BS_ASSERT(m_pWrapper); // call Initialize method on core instance m_pWrapper->Initialize ( WriterID, wszWriterName, ut, st, nLevel, dwTimeoutFreeze ); } VSS_STANDARD_CATCH(ft) return ft.hr; } // This function returns S_FALSE when the writer is inactive (setup or safe mode) __declspec(dllexport) HRESULT STDMETHODCALLTYPE CVssWriter::Subscribe ( IN DWORD dwEventFlags ) { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::Subscribe"); try { ft.Trace (VSSDBG_GEN, L"**** Called CVssWriter::Subscribe(%p) with:", this); ft.Trace (VSSDBG_GEN, L" dwEventFlags = 0x%08x ", dwEventFlags); // Only the default parameter setting is supported in V1 if ( dwEventFlags != ( VSS_SM_BACKUP_EVENTS_FLAG | VSS_SM_RESTORE_EVENTS_FLAG ) ) return E_INVALIDARG; if (m_pWrapper == NULL) ft.Throw(VSSDBG_GEN, E_FAIL, L"CVssWriter class was not initialized."); m_pWrapper->Subscribe(); } VSS_STANDARD_CATCH(ft) return ft.hr; } // This function returns S_FALSE when the writer is inactive (setup or safe mode) __declspec(dllexport) HRESULT STDMETHODCALLTYPE CVssWriter::Unsubscribe() { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::Unsubscribe"); try { if (m_pWrapper == NULL) ft.Throw(VSSDBG_GEN, E_FAIL, L"CVssWriter class was not initialized."); ft.Trace (VSSDBG_GEN, L"**** Called CVssWriter::Unsubscribe(%p):", this); m_pWrapper->Unsubscribe(); } VSS_STANDARD_CATCH(ft) return ft.hr; } __declspec(dllexport) HRESULT STDMETHODCALLTYPE CVssWriter::InstallAlternateWriter ( IN VSS_ID writerId, IN CLSID persistentWriterClassId ) { UNREFERENCED_PARAMETER(writerId); UNREFERENCED_PARAMETER(persistentWriterClassId); CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::InstallAlternateWriter"); // Not supported in V1 ft.hr = E_NOTIMPL; return ft.hr; } __declspec(dllexport) LPCWSTR* STDMETHODCALLTYPE CVssWriter::GetCurrentVolumeArray() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetCurrentVolumeArray"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return NULL; else return m_pWrapper->GetCurrentVolumeArray(); } __declspec(dllexport) UINT STDMETHODCALLTYPE CVssWriter::GetCurrentVolumeCount() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetCurrentVolumeCount"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return 0; else return m_pWrapper->GetCurrentVolumeCount(); } __declspec(dllexport) HRESULT STDMETHODCALLTYPE CVssWriter::GetSnapshotDeviceName ( IN LPCWSTR wszOriginalVolume, OUT LPCWSTR* ppwszSnapshotDevice ) const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetSnapshotDeviceName"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return E_FAIL; else return m_pWrapper->GetSnapshotDeviceName(wszOriginalVolume, ppwszSnapshotDevice); } __declspec(dllexport) VSS_ID STDMETHODCALLTYPE CVssWriter::GetCurrentSnapshotSetId() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetCurrentSnapshotSetId"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return GUID_NULL; else return m_pWrapper->GetCurrentSnapshotSetId(); } __declspec(dllexport) LONG STDMETHODCALLTYPE CVssWriter::GetContext() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetContext"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return 0; else return m_pWrapper->GetContext(); } __declspec(dllexport) VSS_APPLICATION_LEVEL STDMETHODCALLTYPE CVssWriter::GetCurrentLevel() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetCurrentLevel"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return VSS_APP_AUTO; else return m_pWrapper->GetCurrentLevel(); } __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::IsPathAffected(IN LPCWSTR wszPath) const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::IsPathAffected"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return NULL; else return m_pWrapper->IsPathAffected(wszPath); } // determine if bootable state is backed up __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::IsBootableSystemStateBackedUp() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::IsBootableSystemStateBackedUp"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return false; else return m_pWrapper->IsBootableSystemStateBackedUp(); } // determine if bootable state is backed up __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::IsPartialFileSupportEnabled() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::IsPartialFileSupportEnabled"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return false; else return m_pWrapper->IsPartialFileSupportEnabled(); } // determine if the backup application is selecting components __declspec(dllexport) bool STDMETHODCALLTYPE CVssWriter::AreComponentsSelected() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::AreComponentsSelected"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return false; else return m_pWrapper->AreComponentsSelected(); } __declspec(dllexport) VSS_BACKUP_TYPE STDMETHODCALLTYPE CVssWriter::GetBackupType() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetBackupType"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return VSS_BT_UNDEFINED; else return m_pWrapper->GetBackupType(); } __declspec(dllexport) VSS_RESTORE_TYPE STDMETHODCALLTYPE CVssWriter::GetRestoreType() const { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::GetBackupType"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return VSS_RTYPE_UNDEFINED; else return m_pWrapper->GetRestoreType(); } __declspec(dllexport) HRESULT STDMETHODCALLTYPE CVssWriter::SetWriterFailure(IN HRESULT hrStatus) { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssWriter::SetWriterFailure"); BS_ASSERT(m_pWrapper); if (m_pWrapper == NULL) return VSS_BT_UNDEFINED; else return m_pWrapper->SetWriterFailure(hrStatus); } // create backup components // // Returns: // S_OK if the operation is successful // E_INVALIDARG if ppBackup is NULL // E_ACCESSDENIED if the caller does not have backup privileges or // is an administrator __declspec(dllexport) HRESULT STDAPICALLTYPE CreateVssBackupComponents(IVssBackupComponents **ppBackup) { CVssFunctionTracer ft(VSSDBG_XML, L"CreateVssBackupComponents"); try { if (ppBackup == NULL) ft.Throw(VSSDBG_XML, E_INVALIDARG, L"NULL output pointer"); *ppBackup = NULL; if (!IsProcessBackupOperator()) ft.Throw ( VSSDBG_XML, E_ACCESSDENIED, L"The client process is not running under an administrator account or does not have backup privilege enabled" ); CComObject *pvbc; CComObject::CreateInstance(&pvbc); pvbc->GetUnknown()->AddRef(); *ppBackup = (IVssBackupComponents *) pvbc; } VSS_STANDARD_CATCH(ft) return ft.hr; } __declspec(dllexport) HRESULT STDAPICALLTYPE CreateVssExamineWriterMetadata ( IN BSTR bstrXML, OUT IVssExamineWriterMetadata **ppMetadata ) { CVssFunctionTracer ft(VSSDBG_GEN, L"CreateVssExamineWriterMetadata"); CVssExamineWriterMetadata *pMetadata = NULL; try { if (ppMetadata == NULL) ft.Throw(VSSDBG_GEN, E_INVALIDARG, L"NULL output pointer"); *ppMetadata = NULL; pMetadata = new CVssExamineWriterMetadata; if (pMetadata == NULL) ft.Throw(VSSDBG_GEN, E_OUTOFMEMORY, L"Cannot allocate CVssExamineWriterMetadata"); if (!pMetadata->Initialize(bstrXML)) ft.Throw ( VSSDBG_GEN, VSS_E_INVALID_XML_DOCUMENT, L"XML passed to CreateVssExamineWriterMetdata was invalid" ); *ppMetadata = (IVssExamineWriterMetadata *) pMetadata; pMetadata->AddRef(); } VSS_STANDARD_CATCH(ft) if (ft.HrFailed()) delete pMetadata; return ft.hr; } // create a snapshot set description // // Returns: // S_OK if it is successful // E_OUTOFMEMORY if memory could not be allocated __declspec(dllexport) HRESULT STDAPICALLTYPE CreateVssSnapshotSetDescription ( VSS_ID idSnapshotSet, LONG lContext, OUT IVssSnapshotSetDescription **ppSnapshotSet ) { CVssFunctionTracer ft(VSSDBG_XML, L"CreateVssSnapshotSsetDescription"); CVssSnapshotSetDescription *pSnapshotSetTemp = NULL; try { CXMLDocument doc; if (ppSnapshotSet == NULL) ft.Throw(VSSDBG_XML, E_INVALIDARG, L"NULL output parameter."); // intialize document with doc.LoadFromXML(g_ComponentMetadataXML); // find toplevel element if (!doc.FindElement(x_wszElementRoot, true)) ft.Throw(VSSDBG_XML, VSS_E_INVALID_XML_DOCUMENT, L"Missing root element"); // create BACKUP_COMPONENTS element under element CXMLNode nodeRoot(doc.GetCurrentNode(), doc.GetInterface()); CXMLNode nodeSnapshotSet = doc.CreateNode ( x_wszElementSnapshotSetDescription, NODE_ELEMENT ); nodeSnapshotSet.SetAttribute(x_wszAttrSnapshotSetId, idSnapshotSet); nodeSnapshotSet.SetAttribute(x_wszAttrContext, lContext); nodeSnapshotSet.SetAttribute(x_wszAttrXmlns, x_wszValueXmlns); CXMLNode nodeToplevel = nodeRoot.InsertNode(nodeSnapshotSet); doc.SetToplevelNode(nodeSnapshotSet); pSnapshotSetTemp = new CVssSnapshotSetDescription ( doc.GetCurrentNode(), doc.GetInterface() ); if (pSnapshotSetTemp == NULL) ft.Throw(VSSDBG_XML, E_OUTOFMEMORY, L"Can't allocate snapshot set description."); pSnapshotSetTemp->Initialize(ft); *ppSnapshotSet = (IVssSnapshotSetDescription *) pSnapshotSetTemp; ((IVssSnapshotSetDescription *) pSnapshotSetTemp)->AddRef(); pSnapshotSetTemp = NULL; } VSS_STANDARD_CATCH(ft) delete pSnapshotSetTemp; return ft.hr; } __declspec(dllexport) HRESULT STDAPICALLTYPE LoadVssSnapshotSetDescription ( IN LPCWSTR wszXML, OUT IVssSnapshotSetDescription **ppSnapshotSet ) { CVssFunctionTracer ft(VSSDBG_XML, L"LoadVssSnapshotSetDescription"); try { CVssSnapshotSetDescription *pSnapshotSetDescription = new CVssSnapshotSetDescription; if (pSnapshotSetDescription == NULL) ft.Throw(VSSDBG_XML, E_OUTOFMEMORY, L"Cannot allocate snapshot set description."); pSnapshotSetDescription->Initialize(ft); pSnapshotSetDescription->LoadFromXML(wszXML); ((IVssSnapshotSetDescription *) pSnapshotSetDescription)->AddRef(); *ppSnapshotSet = (IVssSnapshotSetDescription *) pSnapshotSetDescription; } VSS_STANDARD_CATCH(ft) return ft.hr; }