Add some ftests, and fixup whitespace from Nikhil's work
This commit is contained in:
parent
cb055c90e5
commit
5f2c3bed69
@ -101,7 +101,7 @@ SOURCE=\
|
||||
thin-provisioning/metadata_checker.cc \
|
||||
thin-provisioning/metadata_counter.cc \
|
||||
thin-provisioning/metadata_dumper.cc \
|
||||
thin-provisioning/override_emitter.cc \
|
||||
thin-provisioning/override_emitter.cc \
|
||||
thin-provisioning/pool_stream.cc \
|
||||
thin-provisioning/restore_emitter.cc \
|
||||
thin-provisioning/rmap_visitor.cc \
|
||||
|
@ -46,6 +46,9 @@ Options:
|
||||
{-h|--help}
|
||||
{-i|--input} <input xml file>
|
||||
{-o|--output} <output device or file>
|
||||
{--transaction-id} <natural>
|
||||
{--data-block-size} <natural>
|
||||
{--nr-data-blocks} <natural>
|
||||
{-q|--quiet}
|
||||
{-V|--version}")
|
||||
|
||||
|
@ -216,6 +216,33 @@
|
||||
(run-ok-rcv (stdout _) (thin-restore "-i" xml "-o" md "--quiet")
|
||||
(assert-eof stdout)))))
|
||||
|
||||
(define-scenario (thin-restore override transaction-id)
|
||||
"thin_restore obeys the --transaction-id override"
|
||||
(with-empty-metadata (md)
|
||||
(with-thin-xml (xml)
|
||||
(run-ok-rcv (stdout stderr) (thin-restore "--transaction-id 2345" "-i" xml "-o" md)
|
||||
(assert-eof stderr))
|
||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
||||
(assert-matches ".*transaction=\"2345\"" stdout)))))
|
||||
|
||||
(define-scenario (thin-restore override data-block-size)
|
||||
"thin_restore obeys the --data-block-size override"
|
||||
(with-empty-metadata (md)
|
||||
(with-thin-xml (xml)
|
||||
(run-ok-rcv (stdout stderr) (thin-restore "--data-block-size 8192" "-i" xml "-o" md)
|
||||
(assert-eof stderr))
|
||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
||||
(assert-matches ".*data_block_size=\"8192\"" stdout)))))
|
||||
|
||||
(define-scenario (thin-restore override nr-data-blocks)
|
||||
"thin_restore obeys the --nr-data-blocks override"
|
||||
(with-empty-metadata (md)
|
||||
(with-thin-xml (xml)
|
||||
(run-ok-rcv (stdout stderr) (thin-restore "--nr-data-blocks 234500" "-i" xml "-o" md)
|
||||
(assert-eof stderr))
|
||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
||||
(assert-matches ".*nr_data_blocks=\"234500\"" stdout)))))
|
||||
|
||||
;;;-----------------------------------------------------------
|
||||
;;; thin_dump scenarios
|
||||
;;;-----------------------------------------------------------
|
||||
|
@ -39,8 +39,8 @@ OPTIONS
|
||||
This option may be specified multiple times to select more than one thin
|
||||
device.
|
||||
|
||||
--transaction-id {natural} Override the transaction id given in the input xml.
|
||||
--data-block-size {natural} Override the data block size given in the input xml.
|
||||
--transaction-id {natural} Override the transaction id given in the input xml.
|
||||
--data-block-size {natural} Override the data block size given in the input xml.
|
||||
--nr-data-blocks {natural} Override the nr data blocks given in the input xml.
|
||||
|
||||
--skip-mappings Do not dump the mappings.
|
||||
|
@ -21,8 +21,8 @@ OPTIONS
|
||||
If a file is used for output, then it must be preallocated, and large
|
||||
enough to hold the metadata.
|
||||
|
||||
--transaction-id {natural} Override the transaction id given in the input xml.
|
||||
--data-block-size {natural} Override the data block size given in the input xml.
|
||||
--transaction-id {natural} Override the transaction id given in the input xml.
|
||||
--data-block-size {natural} Override the data block size given in the input xml.
|
||||
--nr-data-blocks {natural} Override the nr data blocks given in the input xml.
|
||||
|
||||
EXAMPLE
|
||||
|
@ -23,8 +23,8 @@ OPTIONS
|
||||
If a file is used for output, then it must be preallocated, and large
|
||||
enough to hold the metadata.
|
||||
|
||||
--transaction-id {natural} Override the transaction id given in the input xml.
|
||||
--data-block-size {natural} Override the data block size given in the input xml.
|
||||
--transaction-id {natural} Override the transaction id given in the input xml.
|
||||
--data-block-size {natural} Override the data block size given in the input xml.
|
||||
--nr-data-blocks {natural} Override the nr data blocks given in the input xml.
|
||||
|
||||
EXAMPLE
|
||||
|
@ -33,7 +33,6 @@
|
||||
using namespace base;
|
||||
using namespace thin_provisioning;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
@ -276,20 +276,19 @@ namespace {
|
||||
|
||||
class gatherer {
|
||||
public:
|
||||
gatherer(block_manager<> &bm)
|
||||
: bm_(bm),
|
||||
referenced_(bm.get_nr_blocks(), false),
|
||||
examined_(bm.get_nr_blocks(), false) {
|
||||
}
|
||||
gatherer(block_manager<> &bm)
|
||||
: bm_(bm),
|
||||
referenced_(bm.get_nr_blocks(), false),
|
||||
examined_(bm.get_nr_blocks(), false) {
|
||||
}
|
||||
|
||||
struct roots {
|
||||
block_address mapping_root;
|
||||
block_address detail_root;
|
||||
uint32_t time;
|
||||
};
|
||||
|
||||
optional<roots>
|
||||
struct roots {
|
||||
block_address mapping_root;
|
||||
block_address detail_root;
|
||||
uint32_t time;
|
||||
};
|
||||
|
||||
optional<roots>
|
||||
find_best_roots(transaction_manager &tm) {
|
||||
vector<node_info> mapping_roots;
|
||||
vector<node_info> device_roots;
|
||||
@ -304,16 +303,16 @@ namespace {
|
||||
|
||||
auto info = get_info(b);
|
||||
|
||||
if (info.valid) {
|
||||
if (info.type == TOP_LEVEL) {
|
||||
mapping_roots.push_back(info);
|
||||
}
|
||||
if (info.valid) {
|
||||
if (info.type == TOP_LEVEL) {
|
||||
mapping_roots.push_back(info);
|
||||
}
|
||||
|
||||
else if (info.type == DEVICE_DETAILS) {
|
||||
device_roots.push_back(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (info.type == DEVICE_DETAILS) {
|
||||
device_roots.push_back(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SHOW_WORKING
|
||||
cerr << "mapping candidates (" << mapping_roots.size() << "):\n";
|
||||
@ -332,27 +331,27 @@ namespace {
|
||||
cerr << "(" << p.first << ", " << p.second << ")\n";
|
||||
#endif
|
||||
|
||||
if (pairs.size())
|
||||
return mk_roots(pairs[0]);
|
||||
else
|
||||
return optional<roots>();
|
||||
}
|
||||
if (pairs.size())
|
||||
return mk_roots(pairs[0]);
|
||||
else
|
||||
return optional<roots>();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t get_time(block_address b) const {
|
||||
auto i = lookup_info(b);
|
||||
return i ? i->age : 0;
|
||||
}
|
||||
uint32_t get_time(block_address b) const {
|
||||
auto i = lookup_info(b);
|
||||
return i ? i->age : 0;
|
||||
}
|
||||
|
||||
roots mk_roots(pair<block_address, block_address> const &p) {
|
||||
roots r;
|
||||
roots mk_roots(pair<block_address, block_address> const &p) {
|
||||
roots r;
|
||||
|
||||
r.mapping_root = p.second;
|
||||
r.detail_root = p.first;
|
||||
r.time = max<block_address>(get_time(p.first), get_time(p.second));
|
||||
r.mapping_root = p.second;
|
||||
r.detail_root = p.first;
|
||||
r.time = max<block_address>(get_time(p.first), get_time(p.second));
|
||||
|
||||
return r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool set_eq(set<uint32_t> const &lhs, set<uint32_t> const &rhs) {
|
||||
for (auto v : lhs)
|
||||
@ -624,14 +623,13 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
optional<node_info> lookup_info(block_address b) const {
|
||||
auto it = infos_.find(b);
|
||||
if (it == infos_.end())
|
||||
return optional<node_info>();
|
||||
|
||||
return optional<node_info>(it->second);
|
||||
}
|
||||
optional<node_info> lookup_info(block_address b) const {
|
||||
auto it = infos_.find(b);
|
||||
if (it == infos_.end())
|
||||
return optional<node_info>();
|
||||
|
||||
return optional<node_info>(it->second);
|
||||
}
|
||||
|
||||
block_manager<> &bm_;
|
||||
vector<bool> referenced_;
|
||||
@ -779,102 +777,102 @@ namespace {
|
||||
return 0ull;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
emit_trees_(block_manager<>::ptr bm, superblock_detail::superblock const &sb,
|
||||
void
|
||||
emit_trees_(block_manager<>::ptr bm, superblock_detail::superblock const &sb,
|
||||
emitter::ptr e, override_options const &ropts)
|
||||
{
|
||||
metadata md(bm, sb);
|
||||
dump_options opts;
|
||||
details_extractor de(opts);
|
||||
device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy(true));
|
||||
walk_device_tree(*md.details_, de, *dd_policy);
|
||||
{
|
||||
metadata md(bm, sb);
|
||||
dump_options opts;
|
||||
details_extractor de(opts);
|
||||
device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy(true));
|
||||
walk_device_tree(*md.details_, de, *dd_policy);
|
||||
|
||||
e->begin_superblock("", sb.time_,
|
||||
sb.trans_id_,
|
||||
sb.flags_,
|
||||
sb.version_,
|
||||
sb.data_block_size_,
|
||||
get_nr_blocks(md),
|
||||
boost::optional<block_address>());
|
||||
e->begin_superblock("", sb.time_,
|
||||
sb.trans_id_,
|
||||
sb.flags_,
|
||||
sb.version_,
|
||||
sb.data_block_size_,
|
||||
get_nr_blocks(md),
|
||||
boost::optional<block_address>());
|
||||
|
||||
{
|
||||
mapping_tree_detail::damage_visitor::ptr md_policy(mapping_damage_policy(true));
|
||||
mapping_tree_emit_visitor mte(opts, *md.tm_, e, de.get_details(), mapping_damage_policy(true));
|
||||
walk_mapping_tree(*md.mappings_top_level_, mte, *md_policy);
|
||||
}
|
||||
{
|
||||
mapping_tree_detail::damage_visitor::ptr md_policy(mapping_damage_policy(true));
|
||||
mapping_tree_emit_visitor mte(opts, *md.tm_, e, de.get_details(), mapping_damage_policy(true));
|
||||
walk_mapping_tree(*md.mappings_top_level_, mte, *md_policy);
|
||||
}
|
||||
|
||||
e->end_superblock();
|
||||
}
|
||||
e->end_superblock();
|
||||
}
|
||||
|
||||
void
|
||||
find_better_roots_(block_manager<>::ptr bm, superblock_detail::superblock &sb)
|
||||
{
|
||||
// We assume the superblock is wrong, and find the best roots
|
||||
// for ourselves. We've had a few cases where people have
|
||||
// activated a pool on multiple hosts at once, which results in
|
||||
// the superblock being over written.
|
||||
gatherer g(*bm);
|
||||
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
||||
auto p = g.find_best_roots(*tm);
|
||||
void
|
||||
find_better_roots_(block_manager<>::ptr bm, superblock_detail::superblock &sb)
|
||||
{
|
||||
// We assume the superblock is wrong, and find the best roots
|
||||
// for ourselves. We've had a few cases where people have
|
||||
// activated a pool on multiple hosts at once, which results in
|
||||
// the superblock being over written.
|
||||
gatherer g(*bm);
|
||||
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
||||
auto p = g.find_best_roots(*tm);
|
||||
|
||||
if (p) {
|
||||
sb.metadata_snap_ = 0;
|
||||
sb.time_ = p->time;
|
||||
sb.device_details_root_ = p->detail_root;
|
||||
sb.data_mapping_root_ = p->mapping_root;
|
||||
sb.metadata_nr_blocks_ = bm->get_nr_blocks();
|
||||
}
|
||||
}
|
||||
|
||||
superblock_detail::superblock
|
||||
recreate_superblock(override_options const &opts)
|
||||
{
|
||||
superblock_detail::superblock sb;
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
// FIXME: we need to get this by walking both the mapping and device trees.
|
||||
sb.time_ = 100000;
|
||||
if (p) {
|
||||
sb.metadata_snap_ = 0;
|
||||
sb.time_ = p->time;
|
||||
sb.device_details_root_ = p->detail_root;
|
||||
sb.data_mapping_root_ = p->mapping_root;
|
||||
sb.metadata_nr_blocks_ = bm->get_nr_blocks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sb.trans_id_ = opts.get_transaction_id();
|
||||
sb.version_ = superblock_detail::METADATA_VERSION;
|
||||
sb.data_block_size_ = opts.get_data_block_size();
|
||||
|
||||
// Check that this has been overridden.
|
||||
opts.get_nr_data_blocks();
|
||||
superblock_detail::superblock
|
||||
recreate_superblock(override_options const &opts)
|
||||
{
|
||||
superblock_detail::superblock sb;
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
return sb;
|
||||
}
|
||||
// FIXME: we need to get this by walking both the mapping and device trees.
|
||||
sb.time_ = 100000;
|
||||
|
||||
optional<superblock_detail::superblock>
|
||||
maybe_read_superblock(block_manager<>::ptr bm)
|
||||
{
|
||||
try {
|
||||
auto sb = read_superblock(bm);
|
||||
return optional<superblock_detail::superblock>(sb);
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
return optional<superblock_detail::superblock>();
|
||||
}
|
||||
sb.trans_id_ = opts.get_transaction_id();
|
||||
sb.version_ = superblock_detail::METADATA_VERSION;
|
||||
sb.data_block_size_ = opts.get_data_block_size();
|
||||
|
||||
void
|
||||
metadata_repair_(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
|
||||
{
|
||||
auto msb = maybe_read_superblock(bm);
|
||||
if (!msb)
|
||||
msb = recreate_superblock(opts);
|
||||
// Check that this has been overridden.
|
||||
opts.get_nr_data_blocks();
|
||||
|
||||
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
||||
return sb;
|
||||
}
|
||||
|
||||
if (!get_dev_ids(*tm, msb->device_details_root_) ||
|
||||
!get_map_ids(*tm, msb->data_mapping_root_))
|
||||
find_better_roots_(bm, *msb);
|
||||
optional<superblock_detail::superblock>
|
||||
maybe_read_superblock(block_manager<>::ptr bm)
|
||||
{
|
||||
try {
|
||||
auto sb = read_superblock(bm);
|
||||
return optional<superblock_detail::superblock>(sb);
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
emit_trees_(bm, *msb, e, opts);
|
||||
}
|
||||
return optional<superblock_detail::superblock>();
|
||||
}
|
||||
|
||||
void
|
||||
metadata_repair_(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
|
||||
{
|
||||
auto msb = maybe_read_superblock(bm);
|
||||
if (!msb)
|
||||
msb = recreate_superblock(opts);
|
||||
|
||||
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
||||
|
||||
if (!get_dev_ids(*tm, msb->device_details_root_) ||
|
||||
!get_map_ids(*tm, msb->data_mapping_root_))
|
||||
find_better_roots_(bm, *msb);
|
||||
|
||||
emit_trees_(bm, *msb, e, opts);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -906,15 +904,15 @@ thin_provisioning::metadata_dump(metadata::ptr md, emitter::ptr e, dump_options
|
||||
void
|
||||
thin_provisioning::metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
|
||||
{
|
||||
try {
|
||||
metadata_repair_(bm, e, opts);
|
||||
try {
|
||||
metadata_repair_(bm, e, opts);
|
||||
|
||||
} catch (override_error const &e) {
|
||||
ostringstream out;
|
||||
out << "The following field needs to be provided on the command line due to corruption in the superblock: "
|
||||
<< e.what();
|
||||
throw runtime_error(out.str());
|
||||
}
|
||||
} catch (override_error const &e) {
|
||||
ostringstream out;
|
||||
out << "The following field needs to be provided on the command line due to corruption in the superblock: "
|
||||
<< e.what();
|
||||
throw runtime_error(out.str());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
@ -47,8 +47,7 @@ namespace thin_provisioning {
|
||||
}
|
||||
|
||||
bool skip_mappings_;
|
||||
override_options overrides_;
|
||||
|
||||
override_options overrides_;
|
||||
|
||||
using dev_set = std::set<uint64_t>;
|
||||
using maybe_dev_set = boost::optional<dev_set>;
|
||||
@ -61,10 +60,10 @@ namespace thin_provisioning {
|
||||
// corruption encountered will cause an exception to be thrown.
|
||||
void metadata_dump(metadata::ptr md, emitter::ptr e, dump_options const &opts);
|
||||
|
||||
// We have to provide a different interface for repairing, since
|
||||
// the superblock itself may be corrupt, so we wont be able
|
||||
// to create the metadata object.
|
||||
void metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts);
|
||||
// We have to provide a different interface for repairing, since
|
||||
// the superblock itself may be corrupt, so we wont be able
|
||||
// to create the metadata object.
|
||||
void metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts);
|
||||
|
||||
// Only used by ll_restore, so we leave the repair arg
|
||||
void metadata_dump_subtree(metadata::ptr md, emitter::ptr e, bool repair, uint64_t subtree_root);
|
||||
|
@ -23,72 +23,72 @@ using namespace thin_provisioning;
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
class override_emitter : public emitter {
|
||||
public:
|
||||
override_emitter(emitter::ptr inner, override_options const &opts)
|
||||
: inner_(inner),
|
||||
opts_(opts) {
|
||||
}
|
||||
class override_emitter : public emitter {
|
||||
public:
|
||||
override_emitter(emitter::ptr inner, override_options const &opts)
|
||||
: inner_(inner),
|
||||
opts_(opts) {
|
||||
}
|
||||
|
||||
virtual void begin_superblock(std::string const &uuid,
|
||||
uint64_t time,
|
||||
uint64_t trans_id,
|
||||
boost::optional<uint32_t> flags,
|
||||
boost::optional<uint32_t> version,
|
||||
uint32_t data_block_size,
|
||||
uint64_t nr_data_blocks,
|
||||
boost::optional<uint64_t> metadata_snap) {
|
||||
inner_->begin_superblock(uuid, time, opts_.get_transaction_id(trans_id),
|
||||
virtual void begin_superblock(std::string const &uuid,
|
||||
uint64_t time,
|
||||
uint64_t trans_id,
|
||||
boost::optional<uint32_t> flags,
|
||||
boost::optional<uint32_t> version,
|
||||
uint32_t data_block_size,
|
||||
uint64_t nr_data_blocks,
|
||||
boost::optional<uint64_t> metadata_snap) {
|
||||
inner_->begin_superblock(uuid, time, opts_.get_transaction_id(trans_id),
|
||||
flags, version, opts_.get_data_block_size(data_block_size),
|
||||
opts_.get_nr_data_blocks(nr_data_blocks),
|
||||
metadata_snap);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void end_superblock() {
|
||||
inner_->end_superblock();
|
||||
}
|
||||
virtual void end_superblock() {
|
||||
inner_->end_superblock();
|
||||
}
|
||||
|
||||
virtual void begin_device(uint32_t dev,
|
||||
uint64_t mapped_blocks,
|
||||
uint64_t trans_id,
|
||||
uint64_t creation_time,
|
||||
uint64_t snap_time) {
|
||||
inner_->begin_device(dev, mapped_blocks, trans_id, creation_time, snap_time);
|
||||
}
|
||||
virtual void begin_device(uint32_t dev,
|
||||
uint64_t mapped_blocks,
|
||||
uint64_t trans_id,
|
||||
uint64_t creation_time,
|
||||
uint64_t snap_time) {
|
||||
inner_->begin_device(dev, mapped_blocks, trans_id, creation_time, snap_time);
|
||||
}
|
||||
|
||||
virtual void end_device() {
|
||||
inner_->end_device();
|
||||
}
|
||||
virtual void end_device() {
|
||||
inner_->end_device();
|
||||
}
|
||||
|
||||
virtual void begin_named_mapping(std::string const &name) {
|
||||
inner_->begin_named_mapping(name);
|
||||
}
|
||||
virtual void begin_named_mapping(std::string const &name) {
|
||||
inner_->begin_named_mapping(name);
|
||||
}
|
||||
|
||||
virtual void end_named_mapping() {
|
||||
inner_->end_named_mapping();
|
||||
}
|
||||
virtual void end_named_mapping() {
|
||||
inner_->end_named_mapping();
|
||||
}
|
||||
|
||||
virtual void identifier(std::string const &name) {
|
||||
inner_->identifier(name);
|
||||
}
|
||||
virtual void identifier(std::string const &name) {
|
||||
inner_->identifier(name);
|
||||
}
|
||||
|
||||
virtual void range_map(uint64_t origin_begin, uint64_t data_begin, uint32_t time, uint64_t len) {
|
||||
inner_->range_map(origin_begin, data_begin, time, len);
|
||||
}
|
||||
virtual void range_map(uint64_t origin_begin, uint64_t data_begin, uint32_t time, uint64_t len) {
|
||||
inner_->range_map(origin_begin, data_begin, time, len);
|
||||
}
|
||||
|
||||
virtual void single_map(uint64_t origin_block, uint64_t data_block, uint32_t time) {
|
||||
inner_->single_map(origin_block, data_block, time);
|
||||
}
|
||||
virtual void single_map(uint64_t origin_block, uint64_t data_block, uint32_t time) {
|
||||
inner_->single_map(origin_block, data_block, time);
|
||||
}
|
||||
|
||||
private:
|
||||
emitter::ptr inner_;
|
||||
override_options opts_;
|
||||
};
|
||||
private:
|
||||
emitter::ptr inner_;
|
||||
override_options opts_;
|
||||
};
|
||||
}
|
||||
|
||||
emitter::ptr thin_provisioning::create_override_emitter(emitter::ptr inner, override_options const &opts)
|
||||
{
|
||||
return emitter::ptr(new override_emitter(inner, opts));
|
||||
return emitter::ptr(new override_emitter(inner, opts));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
@ -28,56 +28,57 @@
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace thin_provisioning {
|
||||
struct override_error : public std::runtime_error {
|
||||
override_error(std::string const &str)
|
||||
: std::runtime_error(str) {
|
||||
}
|
||||
};
|
||||
struct override_error : public std::runtime_error {
|
||||
override_error(std::string const &str)
|
||||
: std::runtime_error(str) {
|
||||
}
|
||||
};
|
||||
|
||||
struct override_options {
|
||||
uint64_t get_transaction_id() const {
|
||||
if (!transaction_id_)
|
||||
bad_override_("transaction id");
|
||||
struct override_options {
|
||||
uint64_t get_transaction_id() const {
|
||||
if (!transaction_id_)
|
||||
bad_override_("transaction id");
|
||||
|
||||
return *transaction_id_;
|
||||
}
|
||||
return *transaction_id_;
|
||||
}
|
||||
|
||||
uint64_t get_transaction_id(uint64_t dflt) const {
|
||||
return transaction_id_ ? *transaction_id_ : dflt;
|
||||
}
|
||||
uint64_t get_transaction_id(uint64_t dflt) const {
|
||||
return transaction_id_ ? *transaction_id_ : dflt;
|
||||
}
|
||||
|
||||
uint32_t get_data_block_size() const {
|
||||
if (!data_block_size_)
|
||||
bad_override_("data block size");
|
||||
uint32_t get_data_block_size() const {
|
||||
if (!data_block_size_)
|
||||
bad_override_("data block size");
|
||||
|
||||
return *data_block_size_;
|
||||
}
|
||||
uint32_t get_data_block_size(uint32_t dflt) const {
|
||||
return data_block_size_ ? *data_block_size_ : dflt;
|
||||
}
|
||||
return *data_block_size_;
|
||||
}
|
||||
|
||||
uint64_t get_nr_data_blocks() const {
|
||||
if (!nr_data_blocks_)
|
||||
bad_override_("nr data blocks");
|
||||
uint32_t get_data_block_size(uint32_t dflt) const {
|
||||
return data_block_size_ ? *data_block_size_ : dflt;
|
||||
}
|
||||
|
||||
return *nr_data_blocks_;
|
||||
}
|
||||
uint64_t get_nr_data_blocks() const {
|
||||
if (!nr_data_blocks_)
|
||||
bad_override_("nr data blocks");
|
||||
|
||||
uint64_t get_nr_data_blocks(uint64_t dflt) const {
|
||||
return nr_data_blocks_ ? *nr_data_blocks_ : dflt;
|
||||
}
|
||||
return *nr_data_blocks_;
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> transaction_id_;
|
||||
boost::optional<uint32_t> data_block_size_;
|
||||
boost::optional<uint64_t> nr_data_blocks_;
|
||||
uint64_t get_nr_data_blocks(uint64_t dflt) const {
|
||||
return nr_data_blocks_ ? *nr_data_blocks_ : dflt;
|
||||
}
|
||||
|
||||
private:
|
||||
void bad_override_(std::string const &field) const {
|
||||
throw override_error(field);
|
||||
}
|
||||
};
|
||||
boost::optional<uint64_t> transaction_id_;
|
||||
boost::optional<uint32_t> data_block_size_;
|
||||
boost::optional<uint64_t> nr_data_blocks_;
|
||||
|
||||
emitter::ptr create_override_emitter(emitter::ptr inner, override_options const &opts);
|
||||
private:
|
||||
void bad_override_(std::string const &field) const {
|
||||
throw override_error(field);
|
||||
}
|
||||
};
|
||||
|
||||
emitter::ptr create_override_emitter(emitter::ptr inner, override_options const &opts);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
@ -156,7 +156,7 @@ namespace {
|
||||
}
|
||||
|
||||
metadata::ptr md_;
|
||||
override_options opts_;
|
||||
override_options opts_;
|
||||
|
||||
bool in_superblock_;
|
||||
block_address nr_data_blocks_;
|
||||
|
@ -97,8 +97,7 @@ namespace thin_provisioning {
|
||||
|
||||
block_address const SUPERBLOCK_LOCATION = 0;
|
||||
uint32_t const SUPERBLOCK_MAGIC = 27022010;
|
||||
uint32_t const METADATA_VERSION = 2;
|
||||
|
||||
uint32_t const METADATA_VERSION = 2;
|
||||
|
||||
//--------------------------------
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "thin-provisioning/human_readable_format.h"
|
||||
#include "thin-provisioning/metadata.h"
|
||||
#include "thin-provisioning/metadata_dumper.h"
|
||||
#include "thin-provisioning/override_emitter.h"
|
||||
#include "thin-provisioning/shared_library_emitter.h"
|
||||
#include "thin-provisioning/xml_format.h"
|
||||
#include "version.h"
|
||||
@ -84,35 +85,34 @@ namespace {
|
||||
return e;
|
||||
}
|
||||
|
||||
int dump_(string const &path, ostream &out, struct flags &flags) {
|
||||
try {
|
||||
emitter::ptr inner = create_emitter(flags.format, out);
|
||||
emitter::ptr e = create_override_emitter(inner, flags.opts.overrides_);
|
||||
int dump_(string const &path, ostream &out, struct flags &flags) {
|
||||
try {
|
||||
emitter::ptr inner = create_emitter(flags.format, out);
|
||||
emitter::ptr e = create_override_emitter(inner, flags.opts.overrides_);
|
||||
|
||||
if (flags.repair) {
|
||||
auto bm = open_bm(path, block_manager<>::READ_ONLY, true);
|
||||
metadata_repair(bm, e, flags.opts.overrides_);
|
||||
} else {
|
||||
metadata::ptr md = open_metadata(path, flags);
|
||||
metadata_dump(md, e, flags.opts);
|
||||
}
|
||||
if (flags.repair) {
|
||||
auto bm = open_bm(path, block_manager<>::READ_ONLY, true);
|
||||
metadata_repair(bm, e, flags.opts.overrides_);
|
||||
} else {
|
||||
metadata::ptr md = open_metadata(path, flags);
|
||||
metadata_dump(md, e, flags.opts);
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dump(string const &path, char const *output, struct flags &flags) {
|
||||
if (output) {
|
||||
ofstream out(output);
|
||||
return dump_(path, out, flags);
|
||||
} else
|
||||
return dump_(path, cout, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dump(string const &path, char const *output, struct flags &flags) {
|
||||
if (output) {
|
||||
ofstream out(output);
|
||||
return dump_(path, out, flags);
|
||||
} else
|
||||
return dump_(path, cout, flags);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -156,6 +156,9 @@ thin_dump_cmd::run(int argc, char **argv)
|
||||
{ "repair", no_argument, NULL, 'r'},
|
||||
{ "dev-id", required_argument, NULL, 1 },
|
||||
{ "skip-mappings", no_argument, NULL, 2 },
|
||||
{ "transaction-id", required_argument, NULL, 3 },
|
||||
{ "data-block-size", required_argument, NULL, 4 },
|
||||
{ "nr-data-blocks", required_argument, NULL, 5 },
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
@ -207,17 +210,17 @@ thin_dump_cmd::run(int argc, char **argv)
|
||||
flags.opts.skip_mappings_ = true;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
flags.opts.overrides_.transaction_id_ = parse_uint64(optarg, "transaction id");
|
||||
break;
|
||||
case 3:
|
||||
flags.opts.overrides_.transaction_id_ = parse_uint64(optarg, "transaction id");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
flags.opts.overrides_.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
|
||||
break;
|
||||
case 4:
|
||||
flags.opts.overrides_.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
|
||||
break;
|
||||
|
||||
case 5:
|
||||
flags.opts.overrides_.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||
break;
|
||||
case 5:
|
||||
flags.opts.overrides_.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "base/output_file_requirements.h"
|
||||
#include "persistent-data/file_utils.h"
|
||||
#include "thin-provisioning/commands.h"
|
||||
#include "thin-provisioning/override_emitter.h"
|
||||
#include "human_readable_format.h"
|
||||
#include "metadata_dumper.h"
|
||||
#include "metadata.h"
|
||||
@ -17,28 +18,28 @@ using namespace std;
|
||||
using namespace thin_provisioning;
|
||||
|
||||
namespace {
|
||||
int repair(string const &old_path, string const &new_path, override_options const &opts) {
|
||||
bool metadata_touched = false;
|
||||
try {
|
||||
// block size gets updated by the restorer
|
||||
block_manager<>::ptr new_bm = open_bm(new_path, block_manager<>::READ_WRITE);
|
||||
file_utils::check_file_exists(old_path, false);
|
||||
metadata_touched = true;
|
||||
metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
|
||||
emitter::ptr inner = create_restore_emitter(new_md);
|
||||
emitter::ptr e = create_override_emitter(inner, opts);
|
||||
block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY);
|
||||
metadata_repair(old_bm, e, opts);
|
||||
int repair(string const &old_path, string const &new_path, override_options const &opts) {
|
||||
bool metadata_touched = false;
|
||||
try {
|
||||
// block size gets updated by the restorer
|
||||
block_manager<>::ptr new_bm = open_bm(new_path, block_manager<>::READ_WRITE);
|
||||
file_utils::check_file_exists(old_path, false);
|
||||
metadata_touched = true;
|
||||
metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
|
||||
emitter::ptr inner = create_restore_emitter(new_md);
|
||||
emitter::ptr e = create_override_emitter(inner, opts);
|
||||
block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY);
|
||||
metadata_repair(old_bm, e, opts);
|
||||
|
||||
} catch (std::exception &e) {
|
||||
if (metadata_touched)
|
||||
file_utils::zero_superblock(new_path);
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
if (metadata_touched)
|
||||
file_utils::zero_superblock(new_path);
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -51,15 +52,15 @@ thin_repair_cmd::thin_repair_cmd()
|
||||
void
|
||||
thin_repair_cmd::usage(std::ostream &out) const
|
||||
{
|
||||
out << "Usage: " << get_name() << " [options] {device|file}" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-i|--input} <input metadata (binary format)>" << endl
|
||||
<< " {-o|--output} <output metadata (binary format)>" << endl
|
||||
<< " {--transaction-id} <natural>" << endl
|
||||
<< " {--data-block-size} <natural>" << endl
|
||||
<< " {--nr-data-blocks} <natural>" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
out << "Usage: " << get_name() << " [options] {device|file}" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-i|--input} <input metadata (binary format)>" << endl
|
||||
<< " {-o|--output} <output metadata (binary format)>" << endl
|
||||
<< " {--transaction-id} <natural>" << endl
|
||||
<< " {--data-block-size} <natural>" << endl
|
||||
<< " {--nr-data-blocks} <natural>" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
}
|
||||
|
||||
int
|
||||
@ -67,56 +68,55 @@ thin_repair_cmd::run(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
boost::optional<string> input_path, output_path;
|
||||
override_options opts;
|
||||
|
||||
override_options opts;
|
||||
const char shortopts[] = "hi:o:V";
|
||||
|
||||
const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "input", required_argument, NULL, 'i'},
|
||||
{ "output", required_argument, NULL, 'o'},
|
||||
{ "transaction-id", required_argument, NULL, 1},
|
||||
{ "data-block-size", required_argument, NULL, 2},
|
||||
{ "nr-data-blocks", required_argument, NULL, 3},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "input", required_argument, NULL, 'i'},
|
||||
{ "output", required_argument, NULL, 'o'},
|
||||
{ "transaction-id", required_argument, NULL, 1},
|
||||
{ "data-block-size", required_argument, NULL, 2},
|
||||
{ "nr-data-blocks", required_argument, NULL, 3},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(cout);
|
||||
return 0;
|
||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(cout);
|
||||
return 0;
|
||||
|
||||
case 'i':
|
||||
input_path = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
input_path = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
output_path = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output_path = optarg;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
|
||||
break;
|
||||
case 1:
|
||||
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
|
||||
break;
|
||||
case 2:
|
||||
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||
break;
|
||||
case 3:
|
||||
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
default:
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!input_path) {
|
||||
cerr << "no input file provided" << endl;
|
||||
@ -133,8 +133,7 @@ thin_repair_cmd::run(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return repair(*input_path, *output_path, opts);
|
||||
|
||||
return repair(*input_path, *output_path, opts);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
@ -45,28 +45,28 @@ using namespace thin_provisioning;
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
int restore(string const &backup_file, string const &dev, bool quiet, override_options const &opts) {
|
||||
bool metadata_touched = false;
|
||||
try {
|
||||
// The block size gets updated by the restorer.
|
||||
block_manager<>::ptr bm(open_bm(dev, block_manager<>::READ_WRITE));
|
||||
file_utils::check_file_exists(backup_file);
|
||||
metadata_touched = true;
|
||||
metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0));
|
||||
emitter::ptr inner = create_restore_emitter(md);
|
||||
emitter::ptr restorer = create_override_emitter(inner, opts);
|
||||
int restore(string const &backup_file, string const &dev, bool quiet, override_options const &opts) {
|
||||
bool metadata_touched = false;
|
||||
try {
|
||||
// The block size gets updated by the restorer.
|
||||
block_manager<>::ptr bm(open_bm(dev, block_manager<>::READ_WRITE));
|
||||
file_utils::check_file_exists(backup_file);
|
||||
metadata_touched = true;
|
||||
metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0));
|
||||
emitter::ptr inner = create_restore_emitter(md);
|
||||
emitter::ptr restorer = create_override_emitter(inner, opts);
|
||||
|
||||
parse_xml(backup_file, restorer, quiet);
|
||||
parse_xml(backup_file, restorer, quiet);
|
||||
|
||||
} catch (std::exception &e) {
|
||||
if (metadata_touched)
|
||||
file_utils::zero_superblock(dev);
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
if (metadata_touched)
|
||||
file_utils::zero_superblock(dev);
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -79,99 +79,98 @@ thin_restore_cmd::thin_restore_cmd()
|
||||
void
|
||||
thin_restore_cmd::usage(std::ostream &out) const
|
||||
{
|
||||
out << "Usage: " << get_name() << " [options]" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-i|--input} <input xml file>" << endl
|
||||
<< " {-o|--output} <output device or file>" << endl
|
||||
<< " {--transaction-id} <natural>" << endl
|
||||
<< " {--data-block-size} <natural>" << endl
|
||||
<< " {--nr-data-blocks} <natural>" << endl
|
||||
<< " {-q|--quiet}" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
out << "Usage: " << get_name() << " [options]" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-i|--input} <input xml file>" << endl
|
||||
<< " {-o|--output} <output device or file>" << endl
|
||||
<< " {--transaction-id} <natural>" << endl
|
||||
<< " {--data-block-size} <natural>" << endl
|
||||
<< " {--nr-data-blocks} <natural>" << endl
|
||||
<< " {-q|--quiet}" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
}
|
||||
|
||||
int
|
||||
thin_restore_cmd::run(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
const char *shortopts = "hi:o:qV";
|
||||
string input, output;
|
||||
bool quiet = false;
|
||||
override_options opts;
|
||||
int c;
|
||||
const char *shortopts = "hi:o:qV";
|
||||
string input, output;
|
||||
bool quiet = false;
|
||||
override_options opts;
|
||||
|
||||
const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "input", required_argument, NULL, 'i' },
|
||||
{ "output", required_argument, NULL, 'o'},
|
||||
{ "transaction-id", required_argument, NULL, 1},
|
||||
{ "data-block-size", required_argument, NULL, 2},
|
||||
{ "nr-data-blocks", required_argument, NULL, 3},
|
||||
{ "quiet", no_argument, NULL, 'q'},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "input", required_argument, NULL, 'i' },
|
||||
{ "output", required_argument, NULL, 'o'},
|
||||
{ "transaction-id", required_argument, NULL, 1},
|
||||
{ "data-block-size", required_argument, NULL, 2},
|
||||
{ "nr-data-blocks", required_argument, NULL, 3},
|
||||
{ "quiet", no_argument, NULL, 'q'},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(cout);
|
||||
return 0;
|
||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(cout);
|
||||
return 0;
|
||||
|
||||
case 'i':
|
||||
input = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
input = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
output = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output = optarg;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
|
||||
break;
|
||||
case 1:
|
||||
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
|
||||
break;
|
||||
case 2:
|
||||
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||
break;
|
||||
case 3:
|
||||
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
default:
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != optind) {
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
if (argc != optind) {
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (input.empty()) {
|
||||
cerr << "No input file provided." << endl << endl;
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
cerr << "No input file provided." << endl << endl;
|
||||
usage(cerr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (output.empty()) {
|
||||
cerr << "No output file provided." << endl << endl;
|
||||
usage(cerr);
|
||||
return 1;
|
||||
} else
|
||||
check_output_file_requirements(output);
|
||||
if (output.empty()) {
|
||||
cerr << "No output file provided." << endl << endl;
|
||||
usage(cerr);
|
||||
return 1;
|
||||
} else
|
||||
check_output_file_requirements(output);
|
||||
|
||||
return restore(input, output, quiet, opts);
|
||||
return restore(input, output, quiet, opts);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user