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.
416 lines
12 KiB
416 lines
12 KiB
/*
|
|
**++
|
|
**
|
|
** Copyright (c) 2002 Microsoft Corporation
|
|
**
|
|
**
|
|
** Module Name:
|
|
**
|
|
** writerconfig.h
|
|
**
|
|
**
|
|
** Abstract:
|
|
**
|
|
** declare classes that encapsulate the Test writer's configuration
|
|
**
|
|
** Author:
|
|
**
|
|
** Reuven Lax [reuvenl] 04-June-2002
|
|
**
|
|
**
|
|
**
|
|
** Revision History:
|
|
**
|
|
**--
|
|
*/
|
|
|
|
#ifndef _WRITERCONFIG_H_
|
|
#define _WRITERCONFIG_H_
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
|
|
#include <string>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include "vs_xml.hxx"
|
|
#include "utility.h"
|
|
|
|
using std::wstring;
|
|
using Utility::missingAttribute;
|
|
using Utility::missingElement;
|
|
using Utility::AutoCS;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Declarations
|
|
|
|
// this namespace contains all XML data
|
|
namespace XMLData {
|
|
// names of attributes and elements
|
|
extern wchar_t AlternateLocationMapping[];
|
|
extern wchar_t Component[];
|
|
extern wchar_t ComponentFile[];
|
|
extern wchar_t ExcludeFile[];
|
|
extern wchar_t NewTarget[];
|
|
extern wchar_t FailEvent[];
|
|
extern wchar_t Dependency[];
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Class Declarations
|
|
|
|
// this is the generic collection class for sequences in the XML document
|
|
template <class T, wchar_t ElementName[]>
|
|
class XMLCollection {
|
|
public:
|
|
// required typedefs for a collection class
|
|
typedef const T value_type ;
|
|
typedef const T& reference ;
|
|
typedef const T& const_reference ;
|
|
typedef T* pointer ;
|
|
typedef const T* const_pointer ;
|
|
typedef long size_type ;
|
|
|
|
class Iterator;
|
|
typedef Iterator iterator;
|
|
typedef Iterator const_iterator ;
|
|
|
|
// The iterator for objects in the collection. The iterator is read only -- objects in the collection can't be modified
|
|
class Iterator : public std::iterator<std::input_iterator_tag, T> {
|
|
CXMLDocument m_doc;
|
|
mutable long* m_identifier;
|
|
mutable T* m_currentElement;
|
|
bool m_pastEnd;
|
|
unsigned long m_index;
|
|
public:
|
|
Iterator() : m_identifier(NULL), m_currentElement(NULL), m_pastEnd(true), m_index(0) {}
|
|
Iterator(const Iterator& other) : m_identifier(NULL) { *this = other; }
|
|
Iterator(const XMLCollection& collection) : m_doc(collection.m_doc), m_currentElement(NULL), m_pastEnd(false), m_index(0)
|
|
{
|
|
// the assumption is that m_doc is currently at a node with type ElementName
|
|
// bad things will ensue if this is not true
|
|
m_doc.SetToplevel();
|
|
|
|
// m_identifer is used to ensure the following statements
|
|
// iterator i1 = ...;
|
|
// iterator i2 = i1;
|
|
// assert(i1 == i2);
|
|
// assert(++i1 == ++i2);
|
|
m_identifier = new long(1);
|
|
if (m_identifier == NULL)
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
virtual ~Iterator() {
|
|
if (m_identifier && --*m_identifier == 0)
|
|
delete m_identifier;
|
|
|
|
delete m_currentElement;
|
|
}
|
|
|
|
Iterator& operator=(const Iterator& other) {
|
|
if (&other == this)
|
|
return *this;
|
|
|
|
m_currentElement = NULL;
|
|
m_doc = other.m_doc;
|
|
m_pastEnd = other.m_pastEnd;
|
|
m_index = other.m_index;
|
|
|
|
// make the reference count right
|
|
if (other.m_identifier)
|
|
++*other.m_identifier;
|
|
if(m_identifier && --*m_identifier == 0)
|
|
delete m_identifier;
|
|
|
|
m_identifier = other.m_identifier;
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const Iterator& other) const {
|
|
return (m_pastEnd && other.m_pastEnd) ||
|
|
((m_identifier == other.m_identifier) && (m_index == other.m_index) && !m_pastEnd && !other.m_pastEnd);
|
|
}
|
|
|
|
bool operator!=(const Iterator& other) const { return !(*this == other); }
|
|
|
|
const_reference operator*() const {
|
|
assert(m_identifier);
|
|
assert(!m_pastEnd);
|
|
|
|
if (!m_currentElement)
|
|
m_currentElement = new T(m_doc);
|
|
if (m_currentElement == NULL)
|
|
throw std::bad_alloc();
|
|
|
|
return *m_currentElement;
|
|
}
|
|
|
|
const_pointer operator->() const { return &**this; }
|
|
|
|
Iterator& operator++() {
|
|
if (m_pastEnd) {
|
|
assert(false);
|
|
return *this;
|
|
}
|
|
|
|
assert(m_identifier);
|
|
|
|
delete m_currentElement;
|
|
m_currentElement = NULL;
|
|
|
|
if (!m_doc.FindElement(ElementName, false))
|
|
m_pastEnd = true;
|
|
|
|
++m_index;
|
|
|
|
return *this;
|
|
}
|
|
|
|
Iterator operator++(int) {
|
|
Iterator temp = *this;
|
|
++*this;
|
|
return temp;
|
|
}
|
|
};
|
|
|
|
XMLCollection() : m_size(0) {} // initialize an empty collection
|
|
XMLCollection(const XMLCollection& other) { *this = other; }
|
|
XMLCollection(CXMLDocument& document) : m_doc(document), m_size(-1) { m_doc.SetToplevel(); }
|
|
virtual ~XMLCollection() {}
|
|
|
|
XMLCollection& operator= (const XMLCollection& other) {
|
|
m_doc = other.m_doc;
|
|
m_size = other.m_size;
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const XMLCollection& other) const {
|
|
return (size() == other.size()) && std::equal(begin(), end(), other.begin());
|
|
}
|
|
bool operator!=(const XMLCollection& other) const { return !(*this == other); }
|
|
|
|
size_type size() const {
|
|
// if we've already calculated the size, return it
|
|
if (m_size != -1)
|
|
return m_size;
|
|
|
|
// otherwise, calculate the size and return it
|
|
assert(!m_doc.IsEmpty()); // if so, then m_size should==0, and we wouldn't be here
|
|
size_type size = 0;
|
|
iterator current(*this); // can't use begin()/end() as that would recurse
|
|
while (current != m_pastEndIterator) {
|
|
++size;
|
|
++current;
|
|
}
|
|
assert(size > 0);
|
|
|
|
return (m_size = size);
|
|
}
|
|
|
|
size_type max_size() const { return LONG_MAX; }
|
|
bool empty() const { return size() == 0; }
|
|
iterator begin() const { return empty() ? m_pastEndIterator : Iterator(*this); }
|
|
iterator end() const { return m_pastEndIterator; }
|
|
private:
|
|
friend class Iterator;
|
|
|
|
CXMLDocument m_doc;
|
|
mutable long m_size;
|
|
Iterator m_pastEndIterator;
|
|
};
|
|
|
|
// little class to ensure that the document is always reset at the end of each function
|
|
struct Resetter {
|
|
CXMLDocument& m_config;
|
|
Resetter(CXMLDocument& config) : m_config(config) {}
|
|
~Resetter() { m_config.ResetToDocument(); }
|
|
};
|
|
|
|
// generic file specification.
|
|
struct File {
|
|
File(CXMLDocument node);
|
|
File(const wstring& path, const wstring& filespec, bool recursive) :
|
|
m_path(path), m_filespec(filespec), m_recursive(recursive) {
|
|
std::transform(m_path.begin(), m_path.end(), m_path.begin(), towupper);
|
|
std::transform(m_filespec.begin(), m_filespec.end(), m_filespec.begin(), towupper);
|
|
}
|
|
bool operator==(const File& other) const {
|
|
return (m_path == other.m_path) &&
|
|
(m_filespec == other.m_filespec) &&
|
|
(m_recursive == other.m_recursive);
|
|
}
|
|
bool operator!=(const File& other) const { return !(*this == other); }
|
|
|
|
wstring toString() const;
|
|
|
|
wstring m_path;
|
|
wstring m_filespec;
|
|
bool m_recursive;
|
|
};
|
|
|
|
// file specification together with an alternate-path target.
|
|
struct TargetedFile : public File {
|
|
TargetedFile(CXMLDocument node);
|
|
TargetedFile(const wstring &path, const wstring& filespec,
|
|
bool recursive, const wstring& alternate) : File(path, filespec, recursive),
|
|
m_alternatePath(alternate) {
|
|
std::transform(m_alternatePath.begin(), m_alternatePath.end(), m_alternatePath.begin(), towupper);
|
|
}
|
|
bool operator==(const TargetedFile& other) const {
|
|
return (m_alternatePath == other.m_alternatePath) &&
|
|
(File::operator==(other));
|
|
}
|
|
bool operator!=(const TargetedFile& other) const { return !(*this == other); }
|
|
|
|
wstring toString() const;
|
|
|
|
wstring m_alternatePath;
|
|
};
|
|
|
|
// Writer restore method
|
|
struct RestoreMethod {
|
|
RestoreMethod(CXMLDocument node);
|
|
bool operator==(const RestoreMethod& other) const {
|
|
return (m_method == other.m_method) &&
|
|
(m_writerRestore == other.m_writerRestore) &&
|
|
(m_service ==other.m_service) &&
|
|
(m_rebootRequired == other.m_rebootRequired) &&
|
|
(m_alternateLocations == other.m_alternateLocations);
|
|
}
|
|
bool operator!=(const RestoreMethod& other) const { return !(*this == other); }
|
|
|
|
wstring toString() const;
|
|
|
|
VSS_RESTOREMETHOD_ENUM m_method;
|
|
VSS_WRITERRESTORE_ENUM m_writerRestore;
|
|
wstring m_service;
|
|
bool m_rebootRequired;
|
|
|
|
typedef XMLCollection<TargetedFile, XMLData::AlternateLocationMapping> AlternateList ;
|
|
AlternateList m_alternateLocations;
|
|
};
|
|
|
|
|
|
// component dependency
|
|
struct Dependency {
|
|
Dependency(CXMLDocument node);
|
|
bool operator==(const Dependency& other) const {
|
|
return (m_writerId == other.m_writerId) &&
|
|
(m_logicalPath == other.m_logicalPath) &&
|
|
(m_componentName == other.m_componentName);
|
|
}
|
|
|
|
bool operator!=(const Dependency& other) const { return !(*this == other); }
|
|
|
|
wstring toString() const;
|
|
|
|
VSS_ID m_writerId;
|
|
wstring m_logicalPath;
|
|
wstring m_componentName;
|
|
};
|
|
|
|
// Writer component
|
|
struct ComponentBase {
|
|
ComponentBase(const wstring& path = L"", const wstring& name = L"") : m_logicalPath(path), m_name(name)
|
|
{}
|
|
wstring toString() const;
|
|
|
|
wstring m_logicalPath;
|
|
wstring m_name;
|
|
};
|
|
|
|
struct Component : public ComponentBase {
|
|
Component(CXMLDocument node);
|
|
|
|
VSS_COMPONENT_TYPE m_componentType;
|
|
VSS_RESTORE_TARGET m_restoreTarget;
|
|
bool m_selectable;
|
|
bool m_selectableForRestore;
|
|
|
|
typedef XMLCollection<TargetedFile, XMLData::ComponentFile> ComponentFileList;
|
|
typedef std::vector<TargetedFile> TargetList;
|
|
typedef XMLCollection<Dependency, XMLData::Dependency> DependencyList;
|
|
|
|
ComponentFileList m_files;
|
|
DependencyList m_dependencies;
|
|
TargetList m_newTargets;
|
|
};
|
|
|
|
// comparison operators for Component and ComponentBase
|
|
bool operator==(const ComponentBase& left, const ComponentBase& right);
|
|
bool operator!=(const ComponentBase& left, const ComponentBase& right);
|
|
bool operator==(const Component& left, const Component& right);
|
|
bool operator!=(const Component& left, const Component& right);
|
|
|
|
// Writer event.
|
|
struct WriterEvent {
|
|
WriterEvent(CXMLDocument node);
|
|
WriterEvent(Utility::Events event, bool retryable = true, long failures = 1) :
|
|
m_writerEvent(event), m_retryable(retryable),
|
|
m_numFailures(failures) {}
|
|
bool operator==(const WriterEvent& other) const { return m_writerEvent == other.m_writerEvent; }
|
|
bool operator!=(const WriterEvent& other) const { return !(*this == other); }
|
|
|
|
Utility::Events m_writerEvent;
|
|
bool m_retryable;
|
|
long m_numFailures;
|
|
};
|
|
|
|
|
|
// Singleton class that encapsulates writer configuration
|
|
class WriterConfiguration {
|
|
private:
|
|
// disallow explicit creation of this class
|
|
WriterConfiguration() {}
|
|
WriterConfiguration(WriterConfiguration&);
|
|
operator= (WriterConfiguration&);
|
|
|
|
mutable CComAutoCriticalSection m_section;
|
|
mutable CXMLDocument m_doc;
|
|
|
|
template <class T, wchar_t ElementName[]>
|
|
const XMLCollection<T, ElementName> getCollection() const {
|
|
assert(m_doc.GetLevel() == 0);
|
|
AutoCS critical(m_section);
|
|
Resetter reset(m_doc);
|
|
|
|
if (m_doc.FindElement(ElementName, true))
|
|
return XMLCollection<T, ElementName>(m_doc);
|
|
else
|
|
return XMLCollection<T,ElementName>();
|
|
}
|
|
public:
|
|
typedef XMLCollection<File, XMLData::ExcludeFile> ExcludeFileList;
|
|
typedef XMLCollection<Component, XMLData::Component>ComponentList;
|
|
typedef XMLCollection<WriterEvent, XMLData::FailEvent> FailEventList;
|
|
static WriterConfiguration* instance();
|
|
|
|
void loadFromXML(const wstring& xml);
|
|
VSS_USAGE_TYPE usage() const;
|
|
Utility::Verbosity verbosity() const;
|
|
bool checkExcludes() const;
|
|
bool checkIncludes() const;
|
|
RestoreMethod restoreMethod() const;
|
|
const ExcludeFileList excludeFiles() const
|
|
{ return getCollection<File, XMLData::ExcludeFile>(); }
|
|
const ComponentList components() const
|
|
{ return getCollection<Component, XMLData::Component>(); }
|
|
const FailEventList failEvents() const
|
|
{ return getCollection<WriterEvent, XMLData::FailEvent>(); }
|
|
};
|
|
|
|
// return the singleton instance of the class
|
|
// This is always called for the first time at the beginning of main, so no critical section
|
|
// need be involved
|
|
inline WriterConfiguration* WriterConfiguration::instance()
|
|
{
|
|
static WriterConfiguration configuration;
|
|
|
|
return &configuration;
|
|
}
|
|
|
|
#endif
|
|
|