Leaked source code of windows server 2003
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.
 
 
 
 
 
 

605 lines
22 KiB

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
writer.h
Abstract:
Implementation file for FRS writer
Author:
Reuven Lax 17-Sep-2002
--*/
#include "writer.h"
CFrsWriter* CFrsWriter::m_pWriterInstance = NULL;
DWORD InitializeFrsWriter()
/*++
Routine Description:
This routine is called by the FRS service to initialize the writer.
Return Value:
DWORD
--*/
{
#undef DEBSUB
#define DEBSUB "InitializeFrsWriter:"
DPRINT(4, "Initializing the FRS Writer\n");
// initialize COM
HRESULT hr = S_OK;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) {
DPRINT1(1, "CoInitializeEx failed with hresult 0x%08lx\n", hr);
return HRESULT_CODE(hr);
}
// create the writer
hr = CFrsWriter::CreateWriter();
if (FAILED(hr))
DPRINT1(1, "CFrsWriter::CreateWriter failed with hresult 0x%08lx\n", hr);
CoUninitialize();
return HRESULT_CODE(hr);
}
void ShutDownFrsWriter()
/*++
Routine Description:
This routine is called by the FRS service to shutdown the writer.
--*/
{
#undef DEBSUB
#define DEBSUB "ShutDownFrsWriter:"
DPRINT(4, "Shutting down the FRS writer\n");
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
DPRINT1(1, "CoInitializeEx failed with hresult 0x%08lx\n", hr);
CFrsWriter::DestroyWriter();
if (SUCCEEDED(hr))
CoUninitialize();
}
bool STDMETHODCALLTYPE CFrsWriter::OnIdentify(IN IVssCreateWriterMetadata *pMetadata)
/*++
Routine Description:
This routine is called in response to an Identify event being sent to this writer. The writer
is responsible for reporting on all of its metadata in this routine.
Arguments:
pMetadata - Interface used to report on metadata
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::OnIdentify:"
DPRINT(4, "Writer received OnIdentify event\n");
HRESULT hr = S_OK;
// set the restore method
hr = pMetadata->SetRestoreMethod(VSS_RME_CUSTOM, // method
NULL, // wszService
NULL, // wszUserProcedure
VSS_WRE_NEVER, // writerRestore
false // bRebootRequired
);
if (FAILED(hr)) {
DPRINT1(1, "IVssCreateWriterMetadata::SetRestoreMethod failed with hresult 0x%08lx\n", hr);
return false;
}
// initialize FRS backup API
DWORD winStatus = 0;
void* context = NULL;
winStatus = ::NtFrsApiInitializeBackupRestore(NULL,
NTFRSAPI_BUR_FLAGS_BACKUP | NTFRSAPI_BUR_FLAGS_NORMAL,
&context);
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "NtFrsApiInitializeBackupRestore failed with status 0x%08lx\n", winStatus);
return false;
}
FRS_ASSERT(context != NULL);
// stick the backup context into an auto object to ensure that it's always destroyed
CAutoFrsBackupRestore autoContext(context);
// get an enumeration for all the replica sets
winStatus = ::NtFrsApiGetBackupRestoreSets(autoContext.m_context);
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "NtFrsApiGetBackupRestoreSets failed with status 0x%08lx\n", winStatus);
return false;
}
// process each replica set
DWORD index = 0;
void* replicaSet = NULL;
winStatus = ::NtFrsApiEnumBackupRestoreSets(autoContext.m_context, index, &replicaSet);
while (WIN_SUCCESS(winStatus)) {
FRS_ASSERT(replicaSet != NULL);
// each replica set reports the same excludes. only add them once.
CAutoFrsPointer<WCHAR> filters = NULL;
if (!ProcessReplicaSet(autoContext.m_context, replicaSet, pMetadata, filters.GetAddress()))
return false;
if (filters != NULL && index == 0) {
if (!AddExcludes(pMetadata, filters)) {
DPRINT(1, "failed to add filtered exclude files\n");
return false;
}
}
++index;
winStatus = ::NtFrsApiEnumBackupRestoreSets(autoContext.m_context, index, &replicaSet);
}
if (winStatus != ERROR_NO_MORE_ITEMS) {
DPRINT1(1, "NtFrsApiEnumBackupRestoreSets failed with status 0x%08lx\n", winStatus);
return false;
}
return true;
}
bool CFrsWriter::AddExcludes(IVssCreateWriterMetadata* pMetadata, WCHAR* filters)
/*++
Routine Description:
This is a helper routine used by ProcessReplicaSet to create the exclude-file list.
Arguments:
pMetadata - Interface used to report on metadata
filters - list of exclude files
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::AddExcludes:"
WCHAR* currentFilter = filters;
// for each filtered filespec, add an exclude specification to the writer metadata
while (*currentFilter) {
WCHAR* path = NULL;
WCHAR* filespec = NULL;
bool recursive = false;
size_t excludeLength = wcslen(currentFilter); // --- grab size before we modify the string
if (!ParseExclude(currentFilter, &path, &filespec, &recursive)) {
DPRINT(1, "filtered exclude file has an incorrect format\n");
return false;
}
HRESULT hr = pMetadata->AddExcludeFiles(path, filespec, recursive);
if (FAILED(hr)) {
DPRINT1(1, "IVssBackupComponents::AddExcludeFiles failed with hresult 0x%08lx\n", hr);
return false;
}
currentFilter += excludeLength + 1;
}
return true;
}
bool CFrsWriter::ParseExclude(WCHAR* exclude, WCHAR** path, WCHAR** filespec, bool* recursive)
/*++
Routine Description:
This is a helper routine used to parse an exclude specification.
Arguments:
exclude - the specification for the exclude file
path -OUT the root path of the exclude file
filespec - OUT the exclude filespec
recursive - OUT whether this is a recursive specification or not
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::ParseExclude:"
const WCHAR* RecursionSpec = L" /s";
const WCHAR DirSeperator = L'\\';
//verify parameters
FRS_ASSERT(exclude && path && filespec && recursive);
*path = *filespec = NULL;
*recursive = false;
// find the last wack in the path
WCHAR* loc = wcsrchr(exclude, DirSeperator);
if (loc == NULL)
return false;
// setup the return values
*loc = L'\0';
*path = exclude;
*filespec = loc + 1;
// check to see if this is a recursive specification
loc = wcsstr(*filespec, RecursionSpec);
if (loc != NULL) {
*loc = L'\0';
*recursive = true;
}
return (wcslen(*path) > 0) && (wcslen(*filespec) > 0);
}
bool CFrsWriter::ProcessReplicaSet(void* context, void* replicaSet, IVssCreateWriterMetadata* pMetadata, WCHAR** retFilters)
/*++
Routine Description:
This is a helper routine used by OnIdentify to create the writer metadata.
Arguments:
context - The context that identifies us to FRS.
replicaSet - The indentifier for the current replica set
pMetadata - Interface used to report on metadata
filters - return the list of filtered files
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::ProcessReplicaSet:"
FRS_ASSERT(retFilters);
*retFilters = NULL;
// constants that determine component names
const WCHAR* SysvolLogicalPath = L"SYSVOL";
DWORD winStatus = 0;
// all of these need to be defined here, since otherwise destructors don't get called when
// and SEH exception is thrown
CAutoFrsPointer<WCHAR> setType;
DWORD typeSize = 0;
CAutoFrsPointer<WCHAR> setGuid;
DWORD guidSize = 0;
CAutoFrsPointer<WCHAR> directory;
DWORD dirSize = 0;
CAutoFrsPointer<WCHAR> paths;
DWORD pathSize = 0;
CAutoFrsPointer<WCHAR> filters;
DWORD filterSize = 0;
__try {
// figure out what type of replica set this is
winStatus = ::NtFrsApiGetBackupRestoreSetType(context, replicaSet, NULL, &typeSize);
FRS_ASSERT(winStatus == ERROR_MORE_DATA);
setType = (WCHAR*)::FrsAlloc(typeSize);
winStatus = ::NtFrsApiGetBackupRestoreSetType(context, replicaSet, setType, &typeSize);
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "NtFrsApiGetBackupRestoreSetType failed with status 0x%08lx\n", winStatus);
return false;
}
// figure out what the name of this replica set is
winStatus = ::NtFrsApiGetBackupRestoreSetGuid(context, replicaSet, NULL, &guidSize);
FRS_ASSERT(winStatus == ERROR_MORE_DATA);
setGuid = (WCHAR*)::FrsAlloc(guidSize);
winStatus = ::NtFrsApiGetBackupRestoreSetGuid(context, replicaSet, setGuid, &guidSize);
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "NtFrsApiGetBackupRestoreSetGuid failed with status 0x%08lx\n", winStatus);
return false;
}
const WCHAR* logicalPath = NULL;
HRESULT hr = S_OK;
if (wcscmp(setType, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) == 0 ||
wcscmp(setType, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN) == 0) {
// if this is a SYSVOL replica set, add a component with the SYSVOL logical path
logicalPath = SysvolLogicalPath;
hr = pMetadata->AddComponent(VSS_CT_FILEGROUP, // type
logicalPath, // wszLogicalPath
setGuid, // wszComponentName
NULL, // wszCaption
NULL, // pbIcon
0, // cbIcon
false, // bRestoreMetadata
true, // bNotifyOnBackupComplete
true, // bSelectable
true // bSelectableForRestore
);
if (FAILED(hr)) {
DPRINT1(1, "IVssCreateWriterMetadata::AddComponent failed with hresult 0x%08lx\n", hr);
return false;
}
} else {
// otherwise, add a component a component with the generic logical path
logicalPath = setType;
hr = pMetadata->AddComponent(VSS_CT_FILEGROUP, // type
logicalPath, // wszLogicalPath
setGuid, // wszComponentName
NULL, // wszCaption
NULL, // pbIcon
0, // cbIcon
false, // bRestoreMetadata
true, // bNotifyOnBackupComplete
true, // bSelectable
true // bSelectableForRestore
);
if (FAILED(hr)) {
DPRINT1(1, "IVssCreateWriterMetadata::AddComponent failed with hresult 0x%08lx\n", hr);
return false;
}
// add the root replication directory to the filegroup. This isn't necessary for SYSVOL since
// that will be included in the call to NtFrsApiGetBackupRestoreSetPaths.
winStatus = ::NtFrsApiGetBackupRestoreSetDirectory(context, replicaSet, &dirSize, NULL);
FRS_ASSERT(winStatus == ERROR_INSUFFICIENT_BUFFER);
directory = (WCHAR*)::FrsAlloc(dirSize);
// I assume that the directory cannot change in this short windows. If so, we must loop.
winStatus = ::NtFrsApiGetBackupRestoreSetDirectory(context, replicaSet, &dirSize, directory);
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "NtFrsApiGetBackupRestoreSetDirectory failed with status 0x%08lx\n", winStatus);
return false;
}
hr = pMetadata->AddFilesToFileGroup(logicalPath, // wszLogicalPath
setGuid, // wszGroupName
directory, // wszPath
L"*", // wszFilespec
true, // bRecursive
NULL // wszAlternateLocation
);
if (FAILED(hr)) {
DPRINT1(1, "IVssCreateWriterMetadata::AddFilesToFileGroup failed with hresult 0x%08lx\n", hr);
return false;
}
}
winStatus = ::NtFrsApiGetBackupRestoreSetPaths(context,
replicaSet,
&pathSize,
NULL,
&filterSize,
NULL
);
FRS_ASSERT(winStatus == ERROR_INSUFFICIENT_BUFFER);
paths = (WCHAR*)::FrsAlloc(pathSize);
filters = (WCHAR*)::FrsAlloc(filterSize);
// once again, I assume that the sizes won't change in this window
winStatus = ::NtFrsApiGetBackupRestoreSetPaths(context,
replicaSet,
&pathSize,
paths,
&filterSize,
filters
);
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "NtFrsApiGetBackupRestoreSetPaths failed with status 0x%08lx\n", winStatus);
return false;
}
// add all of the paths to the group
WCHAR* currentPath = paths;
while (*currentPath) {
hr = pMetadata->AddFilesToFileGroup(logicalPath, // wszLogicalPath
setGuid, // wszGroupName
currentPath, // wszPath
L"*", // wszFilespec
true, // bRecursive
NULL // wszAlternateLocation
);
if (FAILED(hr)) {
DPRINT1(1, "IVssCreateWriterMetadata::AddFilesToFileGroup failed with hresult 0x%08lx\n", hr);
return false;
}
currentPath += wcslen(currentPath) + 1;
}
*retFilters = filters.Detach();
return true;
} __except(GetExceptionCode() == ERROR_OUTOFMEMORY) {
DPRINT(1, "Out of memory\n");
return false;
}
}
bool STDMETHODCALLTYPE CFrsWriter::OnPrepareSnapshot()
/*++
Routine Description:
This routine is called in response to an Identify event being sent to this writer. The writer
will freeze FRS in this event.
Arguments:
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::OnPrepareSnapshot:"
DPRINT(4, "Received OnPrepareSnapshot event\n");
DWORD winStatus = ::FrsFreezeForBackup();
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "FrsFreezeForBackup failed with status 0x%08lx\n", winStatus);
CVssWriter::SetWriterFailure(VSS_E_WRITERERROR_RETRYABLE);
return false;
}
return true;
}
bool STDMETHODCALLTYPE CFrsWriter::OnFreeze()
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::OnFreeze:"
DPRINT(4, "Received OnFreeze event\n");
return true;
}
bool STDMETHODCALLTYPE CFrsWriter::OnThaw()
/*++
Routine Description:
This routine is called in response to a Thaw event being sent to this writer. The writer
will thaw FRS in this event.
Arguments:
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::OnThaw:"
DPRINT(4, "Received OnThaw event\n");
DWORD winStatus = ::FrsThawAfterBackup();
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "FrsThawAfterBackup failed with status 0x%08lx\n", winStatus);
CVssWriter::SetWriterFailure(VSS_E_WRITERERROR_RETRYABLE);
return false;
}
return true;
}
bool STDMETHODCALLTYPE CFrsWriter::OnAbort()
/*++
Routine Description:
This routine is called in response to an Abort event being sent to this writer. The writer
will thaw FRS in this event.
Arguments:
Return Value:
boolean
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::OnAbort:"
DPRINT(4, "Received OnAbort event\n");
DWORD winStatus = ::FrsThawAfterBackup();
if (!WIN_SUCCESS(winStatus)) {
DPRINT1(1, "FrsThawAfterBackup failed with status 0x%08lx\n", winStatus);
return false;
}
return true;
}
HRESULT CFrsWriter::CreateWriter()
/*++
Routine Description:
This routine is called to create and initialize the FRS writer. It must be called from
a thread that has COM initialized with multi-threaded apartments.
Arguments:
Return Value:
HRESULT
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::CreateWriter:"
// initialization is idempotent
if (m_pWriterInstance != NULL)
return S_OK;
// try and create the writer
m_pWriterInstance = new CFrsWriter();
if (m_pWriterInstance == NULL)
return E_OUTOFMEMORY;
// try and initialize the writer
HRESULT hr = S_OK;
hr = m_pWriterInstance->Initialize();
if (FAILED(hr)) {
delete m_pWriterInstance;
m_pWriterInstance = NULL;
}
return hr;
}
void CFrsWriter::DestroyWriter()
/*++
Routine Description:
This routine is called to destroy the FRS writer.
Arguments:
Return Value:
HRESULT
--*/
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::DestroyWriter:"
delete m_pWriterInstance;
m_pWriterInstance = NULL;
}
HRESULT STDMETHODCALLTYPE CFrsWriter::Initialize()
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::Initialize:"
HRESULT hr = S_OK;
hr = CVssWriter::Initialize(WriterId, // WriterID
WriterName, // wszWriterName
VSS_UT_BOOTABLESYSTEMSTATE, // usage type
VSS_ST_OTHER, // source type
VSS_APP_SYSTEM // nLevel
);
if (FAILED(hr)) {
DPRINT1(1, "CVssWriter::Initialize failed with hresult 0x%08lx\n", hr);
return hr;
}
hr = CVssWriter::Subscribe();
if (FAILED(hr))
DPRINT1(1, "CVssWriter::Subscribe failed with hresult 0x%08lx\n", hr);
return hr;
}
void CFrsWriter::Uninitialize()
{
#undef DEBSUB
#define DEBSUB "CFrsWriter::Uninitialize:"
HRESULT hr = CVssWriter::Unsubscribe();
if (FAILED(hr))
DPRINT1(1, "CVssWriter::Unsubscribe failed with hresult 0x%08lx\n", hr);
}