// 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 // . #include "base/output_file_requirements.h" #include "base/xml_utils.h" #include "metadata_dumper.h" #include "metadata.h" #include "persistent-data/file_utils.h" #include "persistent-data/space-maps/disk_structures.h" #include "restore_emitter.h" #include "xml_format.h" #include "thin-provisioning/commands.h" #include "version.h" #include #include #include using namespace persistent_data; using namespace std; using namespace thin_provisioning; using namespace xml_utils; //---------------------------------------------------------------- namespace { struct user_data { block_manager::ptr input_bm_; block_manager::ptr output_bm_; metadata::ptr md_; XML_Parser parser_; emitter::ptr emitter_; }; void open_resources(user_data &ud, attributes const &attr) { boost::optional val; // open the input metadata // Allow to read superblock at arbitrary location for low-level restore block_address sb_location = (val = get_opt_attr(attr, "blocknr")) ? *val : superblock_detail::SUPERBLOCK_LOCATION; ud.md_ = metadata::ptr(new metadata(ud.input_bm_, sb_location)); // override superblock::device_details_root_ if ((val = get_opt_attr(attr, "device_details_root"))) { ud.md_->sb_.device_details_root_ = *val; ud.md_->details_ = device_tree::ptr(new device_tree(*ud.md_->tm_, *val, device_tree_detail::device_details_traits::ref_counter())); } // open the output metadata metadata::ptr new_md(new metadata(ud.output_bm_, metadata::CREATE, 128, 0)); ud.emitter_ = create_restore_emitter(new_md); } void parse_superblock(metadata::ptr md, emitter::ptr e, attributes const &attr) { sm_disk_detail::sm_root_disk const *d = reinterpret_cast(md->sb_.data_space_map_root_); sm_disk_detail::sm_root v; sm_disk_detail::sm_root_traits::unpack(*d, v); e->begin_superblock("", md->sb_.time_, md->sb_.trans_id_, md->sb_.flags_, md->sb_.version_, md->sb_.data_block_size_, v.nr_blocks_, boost::optional()); } void parse_device(metadata::ptr md, emitter::ptr e, attributes const &attr) { uint32_t dev_id = get_attr(attr, "dev_id"); device_tree_detail::device_details details; device_tree::ptr details_tree; boost::optional details_root = get_opt_attr(attr, "blocknr"); if (details_root) details_tree = device_tree::ptr(new device_tree(*md->tm_, *details_root, device_tree_detail::device_details_traits::ref_counter())); else details_tree = md->details_; uint64_t key[1] = {dev_id}; device_tree::maybe_value v; try { v = details_tree->lookup(key); } catch (std::exception &e) { cerr << "missing device " << dev_id << ": " << e.what() << endl; } if (v) details = *v; e->begin_device(dev_id, 0, details.transaction_id_, details.creation_time_, details.snapshotted_time_); } void parse_node(metadata::ptr md, emitter::ptr e, attributes const &attr) { metadata_dump_subtree(md, e, true, get_attr(attr, "blocknr")); } void start_tag(void *data, char const *el, char const **attr) { user_data *ud = static_cast(data); attributes a; build_attributes(a, attr); if (!strcmp(el, "superblock")) { open_resources(*ud, a); parse_superblock(ud->md_, ud->emitter_, a); } else if (!strcmp(el, "device")) parse_device(ud->md_, ud->emitter_, a); else if (!strcmp(el, "node")) parse_node(ud->md_, ud->emitter_, a); else throw runtime_error("unknown tag type"); } void end_tag(void *data, const char *el) { user_data *ud = static_cast(data); if (!strcmp(el, "superblock")) { ud->emitter_->end_superblock(); XML_StopParser(ud->parser_, XML_FALSE); // skip the rest elements } else if (!strcmp(el, "device")) ud->emitter_->end_device(); else if (!strcmp(el, "node")) ; else throw runtime_error("unknown tag type"); } } //--------------------------------------------------------------------------- namespace { struct flags { flags() { } }; int low_level_restore_(string const &src_metadata, string const &input, string const &output, flags const &f) { user_data ud; ud.input_bm_ = open_bm(src_metadata, block_manager::READ_ONLY); ud.output_bm_ = open_bm(output, block_manager::READ_WRITE); xml_parser p; ud.parser_ = p.get_parser(); XML_SetUserData(p.get_parser(), &ud); XML_SetElementHandler(p.get_parser(), start_tag, end_tag); bool quiet = true; p.parse(input, quiet); return 0; } int low_level_restore(string const &src_metadata, string const &input, string const &output, flags const &f) { try { low_level_restore_(src_metadata, input, output, f); } catch (std::exception &e) { cerr << e.what() << endl; return 1; } return 0; } } //--------------------------------------------------------------------------- thin_ll_restore_cmd::thin_ll_restore_cmd() : command("thin_ll_restore") { } void thin_ll_restore_cmd::usage(ostream &out) const { out << "Usage: " << get_name() << " [options]" << endl << "Options:" << endl << " {-h|--help}" << endl << " {-E|--source-metadata} " << endl << " {-i|--input} " << endl << " {-o|--output} " << endl << " {-V|--version}" << endl; } int thin_ll_restore_cmd::run(int argc, char **argv) { string input; string output; string input_metadata; flags f; int c; const char shortopts[] = "hi:o:E:V"; const struct option longopts[] = { { "help", no_argument, NULL, 'h'}, { "input", required_argument, NULL, 'i'}, { "output", required_argument, NULL, 'o'}, { "source-metadata", required_argument, NULL, 'E'}, { "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; case 'i': input = optarg; break; case 'o': output = optarg; break; case 'E': input_metadata = optarg; break; case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; default: usage(cerr); return 1; } } if (argc != optind) { usage(cerr); return 1; } if (!input.length()) { cerr << "No input file provided." << endl; usage(cerr); return 1; } if (!input_metadata.length()) { cerr << "No input metadata provided." << endl; usage(cerr); return 1; } if (!output.length()) { cerr << "No output file provided." << endl; usage(cerr); return 1; } else check_output_file_requirements(output); return low_level_restore(input_metadata, input, output, f); } //---------------------------------------------------------------------------