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.
443 lines
13 KiB
443 lines
13 KiB
/*
|
|
**++
|
|
**
|
|
** Copyright (c) 2002 Microsoft Corporation
|
|
**
|
|
**
|
|
** Module Name:
|
|
**
|
|
** writerconfig.cpp
|
|
**
|
|
**
|
|
** Abstract:
|
|
**
|
|
** defines classes that encapsulate the Test writer's configuration
|
|
**
|
|
** Author:
|
|
**
|
|
** Reuven Lax [reuvenl] 04-June-2002
|
|
**
|
|
**
|
|
**
|
|
** Revision History:
|
|
**
|
|
**--
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
|
|
#include "stdafx.h"
|
|
#include "writerconfig.h"
|
|
#include "vs_xml.hxx"
|
|
#include "msxml2.h"
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Declarations
|
|
|
|
using Utility::checkReturn;
|
|
using Utility::AutoCS;
|
|
using std::wstring;
|
|
using std::wstringstream;
|
|
|
|
namespace XMLData {
|
|
// names of attributes and elements
|
|
wchar_t Name[] =L"name";
|
|
wchar_t Xmlns[] = L"xmlns";
|
|
wchar_t SchemaPointer[] = L"x-schema:#VssTestWriterConfig";
|
|
wchar_t RootStart[] = L"<root>";
|
|
wchar_t RootEnd[] = L"</root>\n";
|
|
wchar_t Root[] = L"root";
|
|
wchar_t TestWriter[] = L"TestWriter";
|
|
wchar_t Verbosity[] = L"verbosity";
|
|
wchar_t CheckExcludes[] = L"checkExcludes";
|
|
wchar_t CheckIncludes[] = L"checkIncludes";
|
|
wchar_t Path[] = L"path";
|
|
wchar_t Filespec[] = L"filespec";
|
|
wchar_t Recursive[] = L"recursive";
|
|
wchar_t AlternatePath[] = L"alternatePath";
|
|
wchar_t Usage[] = L"usage";
|
|
wchar_t RestoreMethod[] = L"RestoreMethod";
|
|
wchar_t Method[] = L"method";
|
|
wchar_t WriterRestore[] = L"writerRestore";
|
|
wchar_t Service[] = L"service";
|
|
wchar_t RebootRequired[] = L"rebootRequired";
|
|
wchar_t AlternateLocationMapping[] = L"AlternateLocationMapping";
|
|
wchar_t Component[] = L"Component";
|
|
wchar_t ComponentType[] = L"componentType";
|
|
wchar_t LogicalPath[] = L"logicalPath";
|
|
wchar_t Selectable[] = L"selectable";
|
|
wchar_t SelectableForRestore[] = L"selectableForRestore";
|
|
wchar_t ComponentName[] = L"componentName";
|
|
wchar_t ComponentFile[] = L"ComponentFile";
|
|
wchar_t Dependency[] = L"Dependency";
|
|
wchar_t WriterId[] = L"writerId";
|
|
wchar_t ExcludeFile[] = L"ExcludeFile";
|
|
wchar_t RestoreTarget[] = L"restoreTarget";
|
|
wchar_t NewTarget[] = L"NewTarget";
|
|
wchar_t FailEvent[] = L"FailEvent";
|
|
wchar_t WriterEvent[] = L"writerEvent";
|
|
wchar_t Retryable[] = L"retryable";
|
|
wchar_t NumFailures[] = L"numFailures";
|
|
|
|
// string containing the Test writer schema
|
|
#include "schema.h"
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the File struct
|
|
|
|
File::File(CXMLDocument node)
|
|
{
|
|
// read the attributes from the document and store in the structure
|
|
CComBSTR path;
|
|
if (!node.FindAttribute(XMLData::Path, &path))
|
|
missingAttribute(XMLData::Path);
|
|
|
|
CComBSTR filespec;
|
|
if (!node.FindAttribute(XMLData::Filespec, &filespec))
|
|
missingAttribute(XMLData::Filespec);
|
|
|
|
CComBSTR recursive;
|
|
if (!node.FindAttribute(XMLData::Recursive, &recursive))
|
|
missingAttribute(XMLData::Recursive);
|
|
|
|
m_path = (BSTR)path;
|
|
std::transform(m_path.begin(), m_path.end(), m_path.begin(), towupper);
|
|
|
|
m_filespec = (BSTR)filespec;
|
|
std::transform(m_filespec.begin(), m_filespec.end(), m_filespec.begin(), towupper);
|
|
|
|
// path and filespec should never be empty.
|
|
if (m_path.empty())
|
|
throw Utility::TestWriterException(L"File specification has empty path");
|
|
if (m_filespec.empty())
|
|
throw Utility::TestWriterException(L"File specification has empty filespec");
|
|
|
|
if (m_path[m_path.size() -1] != L'\\')
|
|
m_path += L'\\';
|
|
|
|
m_recursive = Utility::toBoolean(recursive);
|
|
}
|
|
|
|
wstring File::toString() const
|
|
{
|
|
wstringstream msg;
|
|
msg << L"Path: " << m_path << std::endl <<
|
|
L"Filespec: " << m_filespec << std::endl <<
|
|
L"Recursive: " << Utility::toString(m_recursive);
|
|
|
|
return msg.str();
|
|
}
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the TargetedFile struct
|
|
|
|
TargetedFile::TargetedFile(CXMLDocument node) : File(node)
|
|
{
|
|
// read the alternatePath attribute and store it
|
|
CComBSTR alternatePath;
|
|
if (!node.FindAttribute(XMLData::AlternatePath, &alternatePath))
|
|
return;
|
|
assert(alternatePath);
|
|
|
|
m_alternatePath = (BSTR)alternatePath;
|
|
std::transform(m_alternatePath.begin(), m_alternatePath.end(), m_alternatePath.begin(), towupper);
|
|
|
|
if (m_alternatePath.empty())
|
|
throw Utility::TestWriterException(L"File specification has empty alternate path");
|
|
|
|
if (m_alternatePath[m_alternatePath.size()-1] != L'\\')
|
|
m_alternatePath += L'\\';
|
|
}
|
|
|
|
wstring TargetedFile::toString() const
|
|
{
|
|
wstringstream msg;
|
|
msg << File::toString() << std::endl <<
|
|
L"AlternatePath: " << m_alternatePath;
|
|
|
|
return msg.str();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the RestoreMethod struct
|
|
|
|
RestoreMethod::RestoreMethod(CXMLDocument node)
|
|
{
|
|
node.SetToplevel();
|
|
|
|
CComBSTR method, writerRestore, service, rebootRequired;
|
|
// read attributes and elements from document
|
|
if (!node.FindAttribute(XMLData::Method, &method))
|
|
missingAttribute(XMLData::Method);
|
|
|
|
if (!node.FindAttribute(XMLData::WriterRestore, &writerRestore))
|
|
missingAttribute(XMLData::WriterRestore);
|
|
|
|
node.FindAttribute(XMLData::Service, &service);
|
|
|
|
if(!node.FindAttribute(XMLData::RebootRequired, &rebootRequired))
|
|
missingAttribute(XMLData::RebootRequired);
|
|
|
|
if (node.FindElement(XMLData::AlternateLocationMapping, true))
|
|
m_alternateLocations = AlternateList(node);
|
|
|
|
m_method = Utility::toMethod(method);
|
|
m_writerRestore = Utility::toWriterRestore(writerRestore);
|
|
m_service = (service.Length() > 0) ? service : L"";
|
|
m_rebootRequired = Utility::toBoolean(rebootRequired);
|
|
}
|
|
|
|
wstring RestoreMethod::toString() const
|
|
{
|
|
wstringstream msg;
|
|
msg << L"method: " << Utility::toString(m_method) << std::endl <<
|
|
L"service: " << m_service << std::endl <<
|
|
L"writerRestore: " << Utility::toString(m_writerRestore) << std::endl <<
|
|
L"reboot: " << Utility::toString(m_rebootRequired);
|
|
|
|
return msg.str();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the Dependency struct
|
|
Dependency::Dependency(CXMLDocument node)
|
|
{
|
|
node.SetToplevel();
|
|
|
|
CComBSTR logicalPath, componentName, writerId;
|
|
|
|
if(!node.FindAttribute(XMLData::WriterId, &writerId))
|
|
missingAttribute(XMLData::WriterId);
|
|
|
|
node.FindAttribute(XMLData::LogicalPath, &logicalPath);
|
|
|
|
if(!node.FindAttribute(XMLData::ComponentName, &componentName))
|
|
missingAttribute(XMLData::ComponentName);
|
|
|
|
|
|
HRESULT hr = ::UuidFromString(writerId, &m_writerId);
|
|
checkReturn(hr, L"CLSIDFromString");
|
|
|
|
m_logicalPath = (logicalPath.Length() > 0) ? logicalPath : L"";
|
|
m_componentName = componentName;
|
|
}
|
|
|
|
wstring Dependency::toString() const
|
|
{
|
|
wstringstream msg;
|
|
msg << L"WriterId: " << (wchar_t*)CComBSTR(m_writerId) << std::endl <<
|
|
L"Logical Path: " << m_logicalPath << std::endl <<
|
|
L"Component Name: " << m_componentName;
|
|
|
|
return msg.str();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the Component struct
|
|
|
|
Component::Component(CXMLDocument node)
|
|
{
|
|
node.SetToplevel();
|
|
|
|
CComBSTR componentType, restoreTarget, logicalPath, name, selectable,
|
|
selectableForRestore;
|
|
|
|
// read attributes from document and store them
|
|
if (!node.FindAttribute(XMLData::ComponentType, &componentType))
|
|
missingAttribute(XMLData::ComponentType);
|
|
|
|
node.FindAttribute(XMLData::RestoreTarget, &restoreTarget);
|
|
|
|
node.FindAttribute(XMLData::LogicalPath, &logicalPath);
|
|
|
|
if (!node.FindAttribute(XMLData::ComponentName, &name))
|
|
missingAttribute(XMLData::ComponentName);
|
|
|
|
if (!node.FindAttribute(XMLData::Selectable, &selectable))
|
|
missingAttribute(XMLData::Selectable);
|
|
|
|
if (!node.FindAttribute(XMLData::SelectableForRestore, &selectableForRestore))
|
|
missingAttribute(XMLData::SelectableForRestore);
|
|
|
|
m_componentType = Utility::toComponentType(componentType);
|
|
m_restoreTarget = (restoreTarget.Length() > 0) ? Utility::toRestoreTarget(restoreTarget) : VSS_RT_UNDEFINED;
|
|
m_logicalPath = (logicalPath.Length() > 0) ? logicalPath : L"";
|
|
m_selectable = Utility::toBoolean(selectable);
|
|
m_selectableForRestore = Utility::toBoolean(selectableForRestore);
|
|
|
|
m_name = name;
|
|
if (m_name.empty())
|
|
throw Utility::TestWriterException(L"Component has empty name");
|
|
|
|
// read elements from document and store them
|
|
if (node.FindElement(XMLData::ComponentFile, true))
|
|
m_files = ComponentFileList(node);
|
|
|
|
node.ResetToDocument();
|
|
|
|
if (node.FindElement(XMLData::Dependency, true))
|
|
m_dependencies = DependencyList(node);
|
|
}
|
|
|
|
wstring ComponentBase::toString() const
|
|
{
|
|
wstringstream msg;
|
|
msg << L"Logical Path: " << m_logicalPath << std::endl <<
|
|
L"Name: " << m_name << std::endl;
|
|
|
|
return msg.str();
|
|
}
|
|
|
|
// comparison operations for writer components
|
|
bool operator==(const ComponentBase& left, const ComponentBase& right)
|
|
{
|
|
return (left.m_name == right.m_name) &&
|
|
(left.m_logicalPath == right.m_logicalPath);
|
|
}
|
|
bool operator!=(const ComponentBase& left, const ComponentBase& right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
bool operator==(const Component& left, const Component& right)
|
|
{
|
|
return ((ComponentBase&)left == (ComponentBase&)right) &&
|
|
(left.m_componentType == right.m_componentType) &&
|
|
(left.m_restoreTarget == right.m_restoreTarget) &&
|
|
(left.m_selectable == right.m_selectable) &&
|
|
(left.m_selectableForRestore == right.m_selectableForRestore) &&
|
|
(left.m_files == right.m_files) &&
|
|
(left.m_newTargets == right.m_newTargets);
|
|
|
|
}
|
|
bool operator!=(const Component& left, const Component& right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the WriterEvent struct
|
|
|
|
WriterEvent::WriterEvent(CXMLDocument node)
|
|
{
|
|
CComBSTR event;
|
|
if (!node.FindAttribute(XMLData::WriterEvent, &event))
|
|
missingAttribute(XMLData::WriterEvent);
|
|
|
|
CComBSTR retryable;
|
|
if (!node.FindAttribute(XMLData::Retryable, &retryable))
|
|
missingAttribute(XMLData::Retryable);
|
|
|
|
CComBSTR numFailures;
|
|
if (!node.FindAttribute(XMLData::NumFailures, &numFailures))
|
|
missingAttribute(XMLData::NumFailures);
|
|
|
|
m_writerEvent = Utility::toWriterEvent(event);
|
|
m_retryable = Utility::toBoolean(retryable);
|
|
m_numFailures = Utility::toLong(numFailures);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation for the WriterConfiguration class
|
|
|
|
// load configuration from the XML file
|
|
void WriterConfiguration::loadFromXML(const wstring& xml)
|
|
{
|
|
AutoCS critical(m_section);
|
|
|
|
// load the document from the XML string
|
|
wstring xmlString = XMLData::RootStart;
|
|
xmlString += XMLData::Schema;
|
|
xmlString += xml;
|
|
xmlString += XMLData::RootEnd;
|
|
|
|
// load twice so we can do schema validation the second time
|
|
for (int x = 0; x < 2; x++) {
|
|
if (!m_doc.LoadFromXML(const_cast<wchar_t*> (xmlString.c_str())))
|
|
Utility::parseError(m_doc);
|
|
|
|
// --- skip to the part of the document we care about
|
|
if (!m_doc.FindElement(XMLData::Root, true))
|
|
missingElement(XMLData::Root);
|
|
if (!m_doc.FindElement(XMLData::TestWriter, true))
|
|
missingElement(XMLData::TestWriter);
|
|
|
|
// --- set the schema namespace
|
|
if (x == 0) {
|
|
CXMLNode testNode(m_doc.GetCurrentNode(), m_doc.GetInterface());
|
|
testNode.SetAttribute(XMLData::Xmlns, XMLData::SchemaPointer);
|
|
xmlString = m_doc.SaveAsXML();
|
|
}
|
|
}
|
|
|
|
m_doc.SetToplevel();
|
|
}
|
|
|
|
VSS_USAGE_TYPE WriterConfiguration::usage() const
|
|
{
|
|
assert(m_doc.GetLevel() == 0);
|
|
AutoCS critical(m_section);
|
|
Resetter reset(m_doc);
|
|
|
|
CComBSTR value;
|
|
if (!m_doc.FindAttribute(XMLData::Usage, &value))
|
|
missingAttribute(XMLData::Usage);
|
|
|
|
return Utility::toUsage(value);
|
|
}
|
|
|
|
Utility::Verbosity WriterConfiguration::verbosity() const
|
|
{
|
|
assert(m_doc.GetLevel() == 0);
|
|
AutoCS critical(m_section);
|
|
Resetter reset(m_doc);
|
|
|
|
CComBSTR value;
|
|
if (!m_doc.FindAttribute(XMLData::Verbosity, &value))
|
|
missingAttribute(XMLData::Verbosity);
|
|
|
|
return Utility::toVerbosity(value);
|
|
}
|
|
|
|
bool WriterConfiguration::checkExcludes() const
|
|
{
|
|
assert(m_doc.GetLevel() == 0);
|
|
AutoCS critical(m_section);
|
|
Resetter reset(m_doc);
|
|
|
|
CComBSTR value;
|
|
if (!m_doc.FindAttribute(XMLData::CheckExcludes, &value))
|
|
missingAttribute(XMLData::CheckExcludes);
|
|
|
|
return Utility::toBoolean(value);
|
|
}
|
|
|
|
bool WriterConfiguration::checkIncludes() const
|
|
{
|
|
assert(m_doc.GetLevel() == 0);
|
|
AutoCS critical(m_section);
|
|
Resetter reset(m_doc);
|
|
|
|
CComBSTR value;
|
|
if (!m_doc.FindAttribute(XMLData::CheckIncludes, &value))
|
|
missingAttribute(XMLData::CheckIncludes);
|
|
|
|
return Utility::toBoolean(value);
|
|
}
|
|
|
|
// get the writer's restore method
|
|
RestoreMethod WriterConfiguration::restoreMethod() const
|
|
{
|
|
assert(m_doc.GetLevel() == 0);
|
|
AutoCS critical(m_section);
|
|
Resetter reset(m_doc);
|
|
|
|
if (!m_doc.FindElement(XMLData::RestoreMethod, true))
|
|
missingElement(XMLData::RestoreMethod);
|
|
|
|
return RestoreMethod(m_doc);
|
|
}
|
|
|