/* Copyright (c) 2018, Steven Siloti Copyright (c) 2003-2004, 2008-2010, 2013, 2015-2020, Arvid Norberg Copyright (c) 2018, Alden Torres All rights reserved. You may use, distribute and modify this code under the terms of the BSD license, see LICENSE file. */ #include // for snprintf #include // for PRId64 et.al. #include #include #include "libtorrent/entry.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/load_torrent.hpp" #include "libtorrent/bdecode.hpp" #include "libtorrent/magnet_uri.hpp" #include "libtorrent/span.hpp" namespace { [[noreturn]] void print_usage() { std::cerr << R"(usage: dump_torrent torrent-file [options] OPTIONS: --items-limit set the upper limit of the number of bencode items in the torrent file. --depth-limit set the recursion limit in the bdecoder --show-padfiles show pad files in file list --max-pieces set the upper limit on the number of pieces to load in the torrent. --max-size reject files larger than this size limit )"; std::exit(1); } } int main(int argc, char const* argv[]) try { lt::span args(argv, argc); // strip executable name args = args.subspan(1); lt::load_torrent_limits cfg; bool show_pad = false; if (args.empty()) print_usage(); char const* filename = args[0]; args = args.subspan(1); using namespace lt::literals; while (!args.empty()) { if (args[0] == "--items-limit"_sv && args.size() > 1) { cfg.max_decode_tokens = atoi(args[1]); args = args.subspan(2); } else if (args[0] == "--depth-limit"_sv && args.size() > 1) { cfg.max_decode_depth = atoi(args[1]); args = args.subspan(2); } else if (args[0] == "--max-pieces"_sv && args.size() > 1) { cfg.max_pieces = atoi(args[1]); args = args.subspan(2); } else if (args[0] == "--max-size"_sv && args.size() > 1) { cfg.max_buffer_size = atoi(args[1]) * 1024 * 1024; args = args.subspan(2); } else if (args[0] == "--show-padfiles"_sv) { show_pad = true; args = args.subspan(1); } else { std::cerr << "unknown option: " << args[0] << "\n"; print_usage(); } } lt::add_torrent_params const atp = lt::load_torrent_file(filename, cfg); // print info about torrent if (!atp.dht_nodes.empty()) { std::printf("nodes:\n"); for (auto const& i : atp.dht_nodes) std::printf("%s: %d\n", i.first.c_str(), i.second); } if (!atp.trackers.empty()) { puts("trackers:\n"); auto tier_it = atp.tracker_tiers.begin(); int tier = 0; for (auto const& i : atp.trackers) { if (tier_it != atp.tracker_tiers.end()) { tier = *tier_it; ++tier_it; } std::printf("%2d: %s\n", tier, i.c_str()); } } std::stringstream ih; ih << atp.info_hashes.v1; if (atp.info_hashes.has_v2()) ih << ", " << atp.info_hashes.v2; std::printf("number of pieces: %d\n" "piece length: %d\n" "info hash: %s\n" "comment: %s\n" "created by: %s\n" "magnet link: %s\n" "name: %s\n" "number of files: %d\n" "files:\n" , atp.ti->num_pieces() , atp.ti->piece_length() , ih.str().c_str() , atp.comment.c_str() , atp.created_by.c_str() , make_magnet_uri(atp).c_str() , atp.name.c_str() , atp.ti->num_files()); lt::file_storage const& st = atp.ti->layout(); for (auto const i : st.file_range()) { auto const first = st.map_file(i, 0, 0).piece; auto const last = st.map_file(i, std::max(std::int64_t(st.file_size(i)) - 1, std::int64_t(0)), 0).piece; auto const flags = st.file_flags(i); if ((flags & lt::file_storage::flag_pad_file) && !show_pad) continue; std::stringstream file_root; if (!st.root(i).is_all_zeros()) file_root << st.root(i); std::printf(" %8" PRIx64 " %11" PRId64 " %c%c%c%c [ %5d, %5d ] %7u %s %s %s%s\n" , std::uint64_t(st.file_offset(i)) , st.file_size(i) , ((flags & lt::file_storage::flag_pad_file)?'p':'-') , ((flags & lt::file_storage::flag_executable)?'x':'-') , ((flags & lt::file_storage::flag_hidden)?'h':'-') , ((flags & lt::file_storage::flag_symlink)?'l':'-') , static_cast(first) , static_cast(last) , std::uint32_t(st.mtime(i)) , file_root.str().c_str() , st.file_path(i).c_str() , (flags & lt::file_storage::flag_symlink) ? "-> " : "" , (flags & lt::file_storage::flag_symlink) ? st.symlink(i).c_str() : ""); } std::printf("web seeds:\n"); for (auto const& ws : atp.url_seeds) std::printf("%s\n", ws.c_str()); return 0; } catch (std::exception const& e) { std::cerr << "ERROR: " << e.what() << "\n"; }