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.
519 lines
13 KiB
519 lines
13 KiB
f/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Abstract:
|
|
|
|
@doc
|
|
@module evtlogwriter.cxx | Implementation of the Event Log Writer
|
|
@end
|
|
|
|
Author:
|
|
|
|
Stefan Steiner [SSteiner] 07/26/2001
|
|
|
|
TBD:
|
|
|
|
|
|
Revision History:
|
|
|
|
Name Date Comments
|
|
ssteiner 07/26/2001 created
|
|
|
|
--*/
|
|
#include "stdafx.h"
|
|
#include "vs_idl.hxx"
|
|
#include "vs_hash.hxx"
|
|
|
|
#include <vswriter.h>
|
|
#include <Sddl.h>
|
|
|
|
#include "vs_seh.hxx"
|
|
#include "vs_trace.hxx"
|
|
#include "vs_debug.hxx"
|
|
#include "vs_reg.hxx"
|
|
#include "evtlogwriter.hxx"
|
|
#include "allerror.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Standard foo for file name aliasing. This code block must be after
|
|
// all includes of VSS header files.
|
|
//
|
|
#ifdef VSS_FILE_ALIAS
|
|
#undef VSS_FILE_ALIAS
|
|
#endif
|
|
#define VSS_FILE_ALIAS "WRTEVTRC"
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static GUID s_writerId =
|
|
{
|
|
0xeee8c692, 0x67ed, 0x4250, 0x8d, 0x86, 0x39, 0x6, 0x3, 0x7, 0xd, 0x00
|
|
};
|
|
|
|
// The display name of the Event Log writer.
|
|
static LPCWSTR s_wszWriterName = L"Event Log Writer";
|
|
|
|
// The file group component name for the Event Log
|
|
static LPCWSTR s_wszComponentName = L"Event Logs";
|
|
|
|
// The Registry key that contains event-log information
|
|
static LPCWSTR s_wszLogKey = L"SYSTEM\\CurrentControlSet\\Services\\Eventlog";
|
|
|
|
// The value field that contains the the event-log file
|
|
static LPCWSTR s_wszLogFile = L"File";
|
|
|
|
// The location of where the Event Log will be copied.
|
|
static CBsString s_cwsEventLogsTargetDir = ROOT_BACKUP_DIR SERVICE_STATE_SUBDIR L"\\EventLogs";
|
|
|
|
// The location of the Event Log
|
|
static CBsString s_cwsSystemEventLogDir = L"%SystemRoot%\\system32\\config";
|
|
|
|
// The mask specifying which files to exclude from backup
|
|
static CBsString s_cwsSystemEventLogFiles = L"*.evt";
|
|
|
|
// Class wide member variables
|
|
CEventLogWriter *CEventLogWriter::sm_pWriter;
|
|
HRESULT CEventLogWriter::sm_hrInitialize;
|
|
|
|
HRESULT STDMETHODCALLTYPE CEventLogWriter::Initialize()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::Initialize");
|
|
|
|
try
|
|
{
|
|
ft.hr = CVssWriter::Initialize
|
|
(
|
|
s_writerId,
|
|
s_wszWriterName,
|
|
VSS_UT_SYSTEMSERVICE,
|
|
VSS_ST_OTHER,
|
|
VSS_APP_SYSTEM,
|
|
60000
|
|
);
|
|
|
|
if (ft.HrFailed())
|
|
ft.Throw
|
|
(
|
|
VSSDBG_WRITER,
|
|
E_UNEXPECTED,
|
|
L"Failed to initialize the Event Log writer. hr = 0x%08lx",
|
|
ft.hr
|
|
);
|
|
|
|
ft.hr = Subscribe();
|
|
if (ft.HrFailed())
|
|
ft.Throw
|
|
(
|
|
VSSDBG_WRITER,
|
|
E_UNEXPECTED,
|
|
L"Subscribing the Event Log server writer failed. hr = %0x08lx",
|
|
ft.hr
|
|
);
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CEventLogWriter::Uninitialize()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::Uninitialize");
|
|
|
|
return Unsubscribe();
|
|
}
|
|
|
|
|
|
// handle request for WRITER_METADATA
|
|
// implements CVssWriter::OnIdentify
|
|
bool STDMETHODCALLTYPE CEventLogWriter::OnIdentify(IVssCreateWriterMetadata *pMetadata)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnIdentify");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Set the restore method for the writer
|
|
//
|
|
ft.hr = pMetadata->SetRestoreMethod
|
|
(
|
|
VSS_RME_RESTORE_AT_REBOOT,
|
|
NULL,
|
|
NULL,
|
|
VSS_WRE_NEVER,
|
|
true
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::SetRestoreMethod");
|
|
|
|
//
|
|
// Add the one file component
|
|
//
|
|
ft.hr = pMetadata->AddComponent
|
|
(
|
|
VSS_CT_FILEGROUP,
|
|
NULL,
|
|
s_wszComponentName,
|
|
s_wszComponentName,
|
|
NULL, // icon
|
|
0,
|
|
false,
|
|
false,
|
|
true
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddComponent");
|
|
|
|
AddExcludes(pMetadata);
|
|
ScanLogs();
|
|
AddLogs(pMetadata);
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CEventLogWriter::OnPrepareSnapshot()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnPrepareSnapshot");
|
|
|
|
try
|
|
{
|
|
CBsString cwsExpanded;
|
|
if (!cwsExpanded.ExpandEnvironmentStrings(s_cwsEventLogsTargetDir))
|
|
{
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"CBsString::ExpandEnvironmentStrings");
|
|
}
|
|
|
|
// make sure that we don't backup up old stuff in the event log backup dir
|
|
ft.hr = ::RemoveDirectoryTree(cwsExpanded);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"::RemoveDirectoryTree");
|
|
|
|
ft.hr = ::CreateTargetPath(cwsExpanded);
|
|
ft.CheckForError(VSSDBG_WRITER, L"::CreateTargetPath");
|
|
|
|
if (IsPathAffected(s_cwsSystemEventLogDir))
|
|
BackupLogs();
|
|
}
|
|
VSS_STANDARD_CATCH( ft );
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
ft.Trace(VSSDBG_WRITER, L"CEventLogWriter returning with hresult 0x%08lx", ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CEventLogWriter::OnFreeze()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnFreeze");
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CEventLogWriter::OnThaw()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnThaw");
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CEventLogWriter::OnAbort()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::OnAbort");
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
bool CEventLogWriter::IsPathInSnapshot(const WCHAR *wszPath) throw()
|
|
{
|
|
return IsPathAffected(wszPath);
|
|
}
|
|
|
|
// translate a sql writer error code into a writer error
|
|
void CEventLogWriter::TranslateWriterError( HRESULT hr )
|
|
{
|
|
switch(hr)
|
|
{
|
|
default:
|
|
SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
|
|
break;
|
|
|
|
case S_OK:
|
|
break;
|
|
|
|
case E_OUTOFMEMORY:
|
|
case HRESULT_FROM_WIN32(ERROR_DISK_FULL):
|
|
case HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES):
|
|
case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
|
|
case HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES):
|
|
SetWriterFailure(VSS_E_WRITERERROR_OUTOFRESOURCES);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Creates one instance of the Event Log writer class. If one already exists, it simple returns.
|
|
// static
|
|
HRESULT CEventLogWriter::CreateWriter()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::CreateWriter");
|
|
|
|
if ( sm_pWriter != NULL )
|
|
return S_OK;
|
|
|
|
//
|
|
// OK, spin up a thread to do the subscription in.
|
|
//
|
|
try
|
|
{
|
|
sm_pWriter = new CEventLogWriter;
|
|
if (sm_pWriter == NULL)
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Allocation of CEventLogWriter object failed.");
|
|
|
|
DWORD tid;
|
|
|
|
HANDLE hThread = ::CreateThread
|
|
(
|
|
NULL,
|
|
256* 1024,
|
|
InitializeThreadFunc,
|
|
NULL,
|
|
0,
|
|
&tid
|
|
);
|
|
|
|
if (hThread == NULL)
|
|
ft.Throw
|
|
(
|
|
VSSDBG_WRITER,
|
|
E_UNEXPECTED,
|
|
L"CreateThread failed with error %d",
|
|
::GetLastError()
|
|
);
|
|
|
|
// wait for thread to complete
|
|
::WaitForSingleObject( hThread, INFINITE );
|
|
::CloseHandle( hThread );
|
|
ft.hr = sm_hrInitialize;
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
if (ft.HrFailed() && sm_pWriter)
|
|
{
|
|
delete sm_pWriter;
|
|
sm_pWriter = NULL;
|
|
}
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
void CEventLogWriter::FreeLogs()
|
|
{
|
|
// free event-log information
|
|
for (int x = 0; x < m_eventLogs.GetSize(); x++)
|
|
{
|
|
::VssFreeString(m_eventLogs[x].m_pwszName);
|
|
::VssFreeString(m_eventLogs[x].m_pwszFileName);
|
|
}
|
|
|
|
m_eventLogs.RemoveAll();
|
|
}
|
|
|
|
void CEventLogWriter::ScanLogs()
|
|
{
|
|
CVssFunctionTracer ft (VSSDBG_WRITER, L"CEventLogWriter::ScanLogs");
|
|
|
|
FreeLogs();
|
|
|
|
// open the main registry key
|
|
CVssRegistryKey hkeyEventLogList (KEY_READ);
|
|
if (!hkeyEventLogList.Open(HKEY_LOCAL_MACHINE, s_wszLogKey))
|
|
{
|
|
ft.Trace (VSSDBG_WRITER, L"Failed to open registry key: %s", s_wszLogKey);
|
|
return;
|
|
}
|
|
|
|
CVssRegistryKeyIterator iterator;
|
|
iterator.Attach (hkeyEventLogList);
|
|
|
|
// for each subkey corresponding to a log
|
|
while (!iterator.IsEOF())
|
|
{
|
|
EventLog currentLog;
|
|
|
|
// --- get the file entry
|
|
CVssRegistryKey hkeyEventLog(KEY_QUERY_VALUE);
|
|
if (!hkeyEventLog.Open(hkeyEventLogList.GetHandle(), iterator.GetCurrentKeyName()))
|
|
{
|
|
ft.Throw(VSSDBG_WRITER, E_UNEXPECTED,
|
|
L"Failed to open registry entry for event log %s", iterator.GetCurrentKeyName());
|
|
}
|
|
|
|
CVssAutoPWSZ pwszFileName;
|
|
hkeyEventLog.GetValue(s_wszLogFile, pwszFileName.GetRef(), false);
|
|
if (pwszFileName.GetRef() == NULL)
|
|
{
|
|
ft.Trace(VSSDBG_WRITER,
|
|
L"Error reading File value for event log %s", iterator.GetCurrentKeyName());
|
|
iterator.MoveNext();
|
|
continue;
|
|
}
|
|
|
|
// ensure that the name has at least a single \ in it
|
|
if (wcschr(pwszFileName, DIR_SEP_CHAR) == NULL)
|
|
{
|
|
ft.Trace(VSSDBG_WRITER,
|
|
L"Error in the File value for event log %s", iterator.GetCurrentKeyName());
|
|
iterator.MoveNext();
|
|
continue;
|
|
}
|
|
|
|
// --- get the name of the log
|
|
CVssAutoPWSZ pwszName;
|
|
if (!pwszName.CopyFrom(iterator.GetCurrentKeyName()))
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Failed to allocate memory for event log name");
|
|
|
|
|
|
// -- add the information to the list
|
|
currentLog.m_pwszFileName = pwszFileName;
|
|
currentLog.m_pwszName = pwszName;
|
|
if (!m_eventLogs.Add(currentLog))
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Failed to add entry to list");
|
|
|
|
pwszFileName.Detach();
|
|
pwszName.Detach();
|
|
|
|
iterator.MoveNext();
|
|
}
|
|
}
|
|
|
|
void CEventLogWriter::AddExcludes(IVssCreateWriterMetadata* pMetadata)
|
|
{
|
|
CVssFunctionTracer ft (VSSDBG_WRITER, L"CEventLogWriter::AddExcludes");
|
|
|
|
pMetadata->AddExcludeFiles(s_cwsSystemEventLogDir, s_cwsSystemEventLogFiles,
|
|
false);
|
|
}
|
|
|
|
void CEventLogWriter::AddLogs(IVssCreateWriterMetadata* pMetadata)
|
|
{
|
|
CVssFunctionTracer ft (VSSDBG_WRITER, L"CEventLogWriter::AddLogs");
|
|
|
|
// add each log file to the component
|
|
for (int x = 0; x < m_eventLogs.GetSize(); x++)
|
|
{
|
|
CVssAutoPWSZ pwszEventPath;
|
|
if (!pwszEventPath.CopyFrom(m_eventLogs[x].m_pwszFileName))
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Failed to allocate memory for event log name");
|
|
|
|
// --- seperate out the path, and add to the component
|
|
VSS_PWSZ pwszEventFile = wcsrchr(pwszEventPath, DIR_SEP_CHAR);
|
|
BS_ASSERT(pwszEventFile != NULL);
|
|
|
|
*pwszEventFile = L'\0';
|
|
++pwszEventFile;
|
|
|
|
ft.hr = pMetadata->AddFilesToFileGroup
|
|
(NULL,
|
|
s_wszComponentName,
|
|
pwszEventPath,
|
|
pwszEventFile,
|
|
false,
|
|
s_cwsEventLogsTargetDir
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup");
|
|
}
|
|
}
|
|
|
|
void CEventLogWriter::BackupLogs()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::BackupLogs");
|
|
|
|
// back up each event log
|
|
for (int x = 0; x < m_eventLogs.GetSize(); x++)
|
|
{
|
|
BS_ASSERT(m_eventLogs[x].m_pwszName != NULL);
|
|
BS_ASSERT(m_eventLogs[x].m_pwszName != NULL);
|
|
|
|
CVssAutoWin32EventLogHandle hLog =
|
|
::OpenEventLog(NULL, m_eventLogs[x].m_pwszName);
|
|
if (hLog == NULL)
|
|
{
|
|
ft.Throw(VSSDBG_WRITER, E_UNEXPECTED,
|
|
L"Failed to open event log %s. [0x%08lx]", m_eventLogs[x].m_pwszName, ::GetLastError());
|
|
}
|
|
|
|
// --- build up the path that we will back up to
|
|
VSS_PWSZ pwszBackupFile = ::wcsrchr(m_eventLogs[x].m_pwszFileName, DIR_SEP_CHAR);
|
|
BS_ASSERT(pwszBackupFile != NULL);
|
|
|
|
CBsString cwsBackupPath;
|
|
cwsBackupPath.ExpandEnvironmentStrings(s_cwsEventLogsTargetDir);
|
|
cwsBackupPath += pwszBackupFile;
|
|
|
|
// --- NOTE: There's a potential failure scenario here. If two different event logs have the same filename
|
|
// --- in different directories, they will overwrite each other in the spit directory. This will be fixed when the
|
|
// --- writer is altered to be an in-place writer
|
|
if (::BackupEventLog(hLog, cwsBackupPath) == FALSE)
|
|
{
|
|
ft.Throw(VSSDBG_WRITER, E_UNEXPECTED,
|
|
L"Failed to backup event log %s to %s. [0x%08lx]", m_eventLogs[x].m_pwszName,
|
|
cwsBackupPath, ::GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
// static
|
|
DWORD CEventLogWriter::InitializeThreadFunc(VOID *pv)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::InitializeThreadFunc");
|
|
|
|
BOOL fCoinitializeSucceeded = false;
|
|
|
|
try
|
|
{
|
|
// intialize MTA thread
|
|
ft.hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
if (ft.HrFailed())
|
|
ft.Throw
|
|
(
|
|
VSSDBG_WRITER,
|
|
E_UNEXPECTED,
|
|
L"CoInitializeEx failed 0x%08lx", ft.hr
|
|
);
|
|
|
|
fCoinitializeSucceeded = true;
|
|
|
|
// Now initialize the base class and subscribe
|
|
ft.hr = sm_pWriter->Initialize();
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
if (fCoinitializeSucceeded)
|
|
CoUninitialize();
|
|
|
|
sm_hrInitialize = ft.hr;
|
|
return 0;
|
|
|
|
UNREFERENCED_PARAMETER( pv );
|
|
}
|
|
|
|
// static
|
|
void CEventLogWriter::DestroyWriter()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CEventLogWriter::DestroyWriter");
|
|
|
|
if (sm_pWriter)
|
|
{
|
|
sm_pWriter->Uninitialize();
|
|
delete sm_pWriter;
|
|
sm_pWriter = NULL;
|
|
}
|
|
}
|
|
|
|
|