2011-12-16 00:04:31 +05:30
|
|
|
// Copyright (C) 2011 Red Hat, Inc. All rights reserved.
|
2011-12-06 19:23:05 +05:30
|
|
|
//
|
2011-12-06 19:13:56 +05:30
|
|
|
// This file is part of the thin-provisioning-tools source.
|
|
|
|
//
|
|
|
|
// thin-provisioning-tools is free software: you can redistribute it
|
|
|
|
// and/or modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation, either version 3 of
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// thin-provisioning-tools is distributed in the hope that it will be
|
|
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License along
|
|
|
|
// with thin-provisioning-tools. If not, see
|
|
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
|
2011-10-10 19:36:07 +05:30
|
|
|
#include "xml_format.h"
|
|
|
|
|
2011-10-25 19:17:49 +05:30
|
|
|
#include <boost/lexical_cast.hpp>
|
2012-05-17 17:33:10 +05:30
|
|
|
#include <boost/optional.hpp>
|
2011-10-25 19:17:49 +05:30
|
|
|
#include <expat.h>
|
2011-10-10 19:36:07 +05:30
|
|
|
#include <iostream>
|
2011-10-25 19:17:49 +05:30
|
|
|
#include <map>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string.h>
|
2011-10-10 19:36:07 +05:30
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace thin_provisioning;
|
|
|
|
|
2011-10-10 20:29:37 +05:30
|
|
|
namespace tp = thin_provisioning;
|
|
|
|
|
2011-10-10 19:36:07 +05:30
|
|
|
//----------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace {
|
2011-10-25 19:17:49 +05:30
|
|
|
//------------------------------------------------
|
|
|
|
// XML generator
|
|
|
|
//------------------------------------------------
|
2011-10-10 19:36:07 +05:30
|
|
|
class xml_emitter : public emitter {
|
|
|
|
public:
|
|
|
|
xml_emitter(ostream &out)
|
|
|
|
: out_(out),
|
|
|
|
indent_(0) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void begin_superblock(string const &uuid,
|
|
|
|
uint64_t time,
|
|
|
|
uint64_t trans_id,
|
2012-03-02 18:31:07 +05:30
|
|
|
uint32_t data_block_size,
|
2012-05-17 17:33:10 +05:30
|
|
|
uint64_t nr_data_blocks,
|
2013-06-25 18:18:02 +05:30
|
|
|
boost::optional<uint64_t> metadata_snap) {
|
2011-10-10 20:44:36 +05:30
|
|
|
indent();
|
|
|
|
out_ << "<superblock uuid=\"" << uuid << "\""
|
|
|
|
<< " time=\"" << time << "\""
|
|
|
|
<< " transaction=\"" << trans_id << "\""
|
2012-03-02 18:31:07 +05:30
|
|
|
<< " data_block_size=\"" << data_block_size << "\""
|
2012-05-17 17:33:10 +05:30
|
|
|
<< " nr_data_blocks=\"" << nr_data_blocks;
|
|
|
|
|
|
|
|
if (metadata_snap)
|
|
|
|
out_ << " metadata_snap=\"" << *metadata_snap;
|
|
|
|
|
|
|
|
out_ << "\">"
|
2011-10-10 19:36:07 +05:30
|
|
|
<< endl;
|
2011-10-10 20:44:36 +05:30
|
|
|
inc();
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void end_superblock() {
|
2011-10-10 20:44:36 +05:30
|
|
|
dec();
|
|
|
|
indent();
|
|
|
|
out_ << "</superblock>" << endl;
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void begin_device(uint32_t dev_id,
|
|
|
|
uint64_t mapped_blocks,
|
|
|
|
uint64_t trans_id,
|
|
|
|
uint64_t creation_time,
|
|
|
|
uint64_t snap_time) {
|
|
|
|
indent();
|
2011-11-09 17:08:46 +05:30
|
|
|
out_ << "<device dev_id=\"" << dev_id << "\""
|
2011-10-10 19:36:07 +05:30
|
|
|
<< " mapped_blocks=\"" << mapped_blocks << "\""
|
|
|
|
<< " transaction=\"" << trans_id << "\""
|
|
|
|
<< " creation_time=\"" << creation_time << "\""
|
|
|
|
<< " snap_time=\"" << snap_time << "\">" << endl;
|
|
|
|
inc();
|
|
|
|
}
|
|
|
|
|
|
|
|
void end_device() {
|
|
|
|
dec();
|
2011-10-10 20:44:36 +05:30
|
|
|
indent();
|
2011-10-10 19:36:07 +05:30
|
|
|
out_ << "</device>" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void begin_named_mapping(string const &name) {
|
2011-10-10 20:44:36 +05:30
|
|
|
indent();
|
|
|
|
out_ << "<named_mapping>" << endl;
|
|
|
|
inc();
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void end_named_mapping() {
|
2011-10-10 20:44:36 +05:30
|
|
|
dec();
|
|
|
|
indent();
|
|
|
|
out_ << "</named_mapping>" << endl;
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void identifier(string const &name) {
|
2011-10-10 20:44:36 +05:30
|
|
|
indent();
|
|
|
|
out_ << "<identifier name=\"" << name << "\"/>" << endl;
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
2011-10-28 18:23:15 +05:30
|
|
|
void range_map(uint64_t origin_begin, uint64_t data_begin, uint32_t time, uint64_t len) {
|
2011-10-10 19:36:07 +05:30
|
|
|
indent();
|
|
|
|
|
|
|
|
out_ << "<range_mapping origin_begin=\"" << origin_begin << "\""
|
|
|
|
<< " data_begin=\"" << data_begin << "\""
|
2011-10-28 18:23:15 +05:30
|
|
|
<< " length=\"" << len << "\""
|
|
|
|
<< " time=\"" << time << "\""
|
|
|
|
<< "/>" << endl;
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
2011-10-28 18:23:15 +05:30
|
|
|
void single_map(uint64_t origin_block, uint64_t data_block, uint32_t time) {
|
2011-10-10 19:36:07 +05:30
|
|
|
indent();
|
|
|
|
|
|
|
|
out_ << "<single_mapping origin_block=\"" << origin_block << "\""
|
2011-10-28 18:23:15 +05:30
|
|
|
<< " data_block=\"" << data_block << "\""
|
|
|
|
<< " time=\"" << time << "\""
|
|
|
|
<< "/>" << endl;
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void indent() {
|
|
|
|
for (unsigned i = 0; i < indent_ * 2; i++)
|
|
|
|
out_ << ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
void inc() {
|
|
|
|
indent_++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dec() {
|
|
|
|
indent_--;
|
|
|
|
}
|
|
|
|
|
|
|
|
ostream &out_;
|
|
|
|
unsigned indent_;
|
|
|
|
};
|
2011-10-25 19:17:49 +05:30
|
|
|
|
|
|
|
//------------------------------------------------
|
|
|
|
// XML parser
|
|
|
|
//------------------------------------------------
|
|
|
|
typedef std::map<string, string> attributes;
|
|
|
|
|
|
|
|
void build_attributes(attributes &a, char const **attr) {
|
|
|
|
while (*attr) {
|
|
|
|
char const *key = *attr;
|
|
|
|
|
|
|
|
attr++;
|
|
|
|
if (!*attr) {
|
|
|
|
ostringstream out;
|
|
|
|
out << "No value given for xml attribute: " << key;
|
|
|
|
throw runtime_error(out.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
char const *value = *attr;
|
|
|
|
a.insert(make_pair(string(key), string(value)));
|
|
|
|
attr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T get_attr(attributes const &attr, string const &key) {
|
|
|
|
attributes::const_iterator it = attr.find(key);
|
|
|
|
if (it == attr.end()) {
|
|
|
|
ostringstream out;
|
|
|
|
out << "could not find attribute: " << key;
|
|
|
|
throw runtime_error(out.str());
|
|
|
|
}
|
|
|
|
|
2013-06-25 18:18:02 +05:30
|
|
|
return boost::lexical_cast<T>(it->second);
|
2011-10-25 19:17:49 +05:30
|
|
|
}
|
|
|
|
|
2012-05-17 17:33:10 +05:30
|
|
|
template <typename T>
|
2013-06-25 18:18:02 +05:30
|
|
|
boost::optional<T> get_opt_attr(attributes const &attr, string const &key) {
|
|
|
|
typedef boost::optional<T> rtype;
|
2012-05-17 17:33:10 +05:30
|
|
|
attributes::const_iterator it = attr.find(key);
|
|
|
|
if (it == attr.end())
|
|
|
|
return rtype();
|
|
|
|
|
2013-06-25 18:18:02 +05:30
|
|
|
return rtype(boost::lexical_cast<T>(it->second));
|
2012-05-17 17:33:10 +05:30
|
|
|
}
|
|
|
|
|
2011-10-25 19:17:49 +05:30
|
|
|
void parse_superblock(emitter *e, attributes const &attr) {
|
|
|
|
e->begin_superblock(get_attr<string>(attr, "uuid"),
|
|
|
|
get_attr<uint64_t>(attr, "time"),
|
|
|
|
get_attr<uint64_t>(attr, "transaction"),
|
2012-03-02 18:31:07 +05:30
|
|
|
get_attr<uint32_t>(attr, "data_block_size"),
|
2012-05-17 17:33:10 +05:30
|
|
|
get_attr<uint64_t>(attr, "nr_data_blocks"),
|
|
|
|
get_opt_attr<uint64_t>(attr, "metadata_snap"));
|
2011-10-25 19:17:49 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void parse_device(emitter *e, attributes const &attr) {
|
|
|
|
e->begin_device(get_attr<uint32_t>(attr, "dev_id"),
|
|
|
|
get_attr<uint64_t>(attr, "mapped_blocks"),
|
|
|
|
get_attr<uint64_t>(attr, "transaction"),
|
|
|
|
get_attr<uint64_t>(attr, "creation_time"),
|
|
|
|
get_attr<uint64_t>(attr, "snap_time"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_range_mapping(emitter *e, attributes const &attr) {
|
|
|
|
e->range_map(get_attr<uint64_t>(attr, "origin_begin"),
|
|
|
|
get_attr<uint64_t>(attr, "data_begin"),
|
2011-10-28 18:23:15 +05:30
|
|
|
get_attr<uint32_t>(attr, "time"),
|
2011-10-25 19:17:49 +05:30
|
|
|
get_attr<uint64_t>(attr, "length"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_single_mapping(emitter *e, attributes const &attr) {
|
|
|
|
e->single_map(get_attr<uint64_t>(attr, "origin_block"),
|
2011-10-28 18:23:15 +05:30
|
|
|
get_attr<uint64_t>(attr, "data_block"),
|
|
|
|
get_attr<uint32_t>(attr, "time"));
|
2011-10-25 19:17:49 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void start_tag(void *data, char const *el, char const **attr) {
|
|
|
|
emitter *e = static_cast<emitter *>(data);
|
|
|
|
attributes a;
|
|
|
|
|
|
|
|
build_attributes(a, attr);
|
|
|
|
|
|
|
|
if (!strcmp(el, "superblock"))
|
|
|
|
parse_superblock(e, a);
|
|
|
|
|
|
|
|
else if (!strcmp(el, "device"))
|
|
|
|
parse_device(e, a);
|
|
|
|
|
|
|
|
else if (!strcmp(el, "range_mapping"))
|
|
|
|
parse_range_mapping(e, a);
|
|
|
|
|
|
|
|
else if (!strcmp(el, "single_mapping"))
|
|
|
|
parse_single_mapping(e, a);
|
|
|
|
|
|
|
|
else
|
|
|
|
throw runtime_error("unknown tag type");
|
|
|
|
}
|
|
|
|
|
|
|
|
void end_tag(void *data, const char *el) {
|
|
|
|
emitter *e = static_cast<emitter *>(data);
|
|
|
|
|
|
|
|
if (!strcmp(el, "superblock"))
|
|
|
|
e->end_superblock();
|
|
|
|
|
|
|
|
else if (!strcmp(el, "device"))
|
|
|
|
e->end_device();
|
|
|
|
|
|
|
|
else if (!strcmp(el, "range_mapping")) {
|
|
|
|
// do nothing
|
|
|
|
|
|
|
|
} else if (!strcmp(el, "single_mapping")) {
|
|
|
|
// do nothing
|
|
|
|
|
|
|
|
} else
|
|
|
|
throw runtime_error("unknown tag close");
|
|
|
|
}
|
2011-10-10 19:36:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
|
|
|
2011-10-10 20:29:37 +05:30
|
|
|
tp::emitter::ptr
|
|
|
|
tp::create_xml_emitter(ostream &out)
|
2011-10-10 19:36:07 +05:30
|
|
|
{
|
|
|
|
return emitter::ptr(new xml_emitter(out));
|
|
|
|
}
|
|
|
|
|
2011-10-25 19:17:49 +05:30
|
|
|
void
|
|
|
|
tp::parse_xml(std::istream &in, emitter::ptr e)
|
|
|
|
{
|
|
|
|
XML_Parser parser = XML_ParserCreate(NULL);
|
|
|
|
if (!parser)
|
|
|
|
throw runtime_error("couldn't create xml parser");
|
|
|
|
|
|
|
|
XML_SetUserData(parser, e.get());
|
|
|
|
XML_SetElementHandler(parser, start_tag, end_tag);
|
|
|
|
|
|
|
|
while (!in.eof()) {
|
|
|
|
char buffer[4096];
|
|
|
|
in.read(buffer, sizeof(buffer));
|
|
|
|
size_t len = in.gcount();
|
|
|
|
int done = in.eof();
|
|
|
|
|
|
|
|
if (!XML_Parse(parser, buffer, len, done)) {
|
|
|
|
ostringstream out;
|
|
|
|
out << "Parse error at line "
|
|
|
|
<< XML_GetCurrentLineNumber(parser)
|
|
|
|
<< ":\n"
|
|
|
|
<< XML_ErrorString(XML_GetErrorCode(parser))
|
|
|
|
<< endl;
|
|
|
|
throw runtime_error(out.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-10 19:36:07 +05:30
|
|
|
//----------------------------------------------------------------
|