From 202386dd9dbd8ded65981a50f8dfb101deb33c3a Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 20 Jan 2017 00:01:00 -0500 Subject: [PATCH] factor out verify_resume_data to storage_utils --- include/libtorrent/aux_/storage_utils.hpp | 14 ++- src/storage.cpp | 108 ++------------------ src/storage_utils.cpp | 114 +++++++++++++++++++++- test/test_storage.cpp | 12 +-- 4 files changed, 137 insertions(+), 111 deletions(-) diff --git a/include/libtorrent/aux_/storage_utils.hpp b/include/libtorrent/aux_/storage_utils.hpp index 03f0f2623..622efe5db 100644 --- a/include/libtorrent/aux_/storage_utils.hpp +++ b/include/libtorrent/aux_/storage_utils.hpp @@ -49,6 +49,8 @@ namespace libtorrent class file_storage; struct part_file; struct storage_error; + struct stat_cache; + struct add_torrent_params; #ifdef TORRENT_WINDOWS struct iovec_t @@ -60,6 +62,8 @@ namespace libtorrent using iovec_t = ::iovec; #endif + namespace aux { + TORRENT_EXTRA_EXPORT int copy_bufs(span bufs, int bytes, span target); TORRENT_EXTRA_EXPORT span advance_bufs(span bufs, int bytes); @@ -97,7 +101,15 @@ namespace libtorrent delete_files(file_storage const& fs, std::string const& save_path , std::string const& part_file_name, int const options, storage_error& ec); -} + TORRENT_EXTRA_EXPORT bool + verify_resume_data(add_torrent_params const& rd + , aux::vector const& links + , file_storage const& fs + , aux::vector const& file_priority + , stat_cache& stat + , std::string const& save_path + , storage_error& ec); +}} #endif diff --git a/src/storage.cpp b/src/storage.cpp index 891af85f8..5f8255383 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -118,7 +118,7 @@ namespace libtorrent std::memset(buf.iov_base, 0, buf.iov_len); } - struct write_fileop final : fileop + struct write_fileop final : aux::fileop { write_fileop(default_storage& st, int flags) : m_storage(st) @@ -198,7 +198,7 @@ namespace libtorrent int m_flags; }; - struct read_fileop final : fileop + struct read_fileop final : aux::fileop { read_fileop(default_storage& st, int const flags) : m_storage(st) @@ -620,7 +620,7 @@ namespace libtorrent // delete it if (m_part_file) m_part_file.reset(); - libtorrent::delete_files(files(), m_save_path, m_part_file_name, options, ec); + aux::delete_files(files(), m_save_path, m_part_file_name, options, ec); DFLOG(stderr, "[%p] delete_files result: %s\n", static_cast(this) , ec.ec.message().c_str()); @@ -630,104 +630,8 @@ namespace libtorrent , aux::vector const& links , storage_error& ec) { - file_storage const& fs = files(); -#ifdef TORRENT_DISABLE_MUTABLE_TORRENTS - TORRENT_UNUSED(links); -#else - if (!links.empty()) - { - TORRENT_ASSERT(int(links.size()) == fs.num_files()); - // if this is a mutable torrent, and we need to pick up some files - // from other torrents, do that now. Note that there is an inherent - // race condition here. We checked if the files existed on a different - // thread a while ago. These files may no longer exist or may have been - // moved. If so, we just fail. The user is responsible to not touch - // other torrents until a new mutable torrent has been completely - // added. - for (file_index_t idx(0); idx < fs.end_file(); ++idx) - { - std::string const& s = links[idx]; - if (s.empty()) continue; - - error_code err; - std::string file_path = fs.file_path(idx, m_save_path); - hard_link(s, file_path, err); - - // if the file already exists, that's not an error - // TODO: 2 is this risky? The upper layer will assume we have the - // whole file. Perhaps we should verify that at least the size - // of the file is correct - if (!err || err == boost::system::errc::file_exists) - continue; - - ec.ec = err; - ec.file(idx); - ec.operation = storage_error::hard_link; - return false; - } - } -#endif // TORRENT_DISABLE_MUTABLE_TORRENTS - - bool const seed = rd.have_pieces.all_set(); - - // parse have bitmask. Verify that the files we expect to have - // actually do exist - for (piece_index_t i(0); i < piece_index_t(rd.have_pieces.size()); ++i) - { - if (rd.have_pieces.get_bit(i) == false) continue; - - std::vector f = fs.map_block(i, 0, 1); - TORRENT_ASSERT(!f.empty()); - - file_index_t const file_index = f[0].file_index; - - // files with priority zero may not have been saved to disk at their - // expected location, but is likely to be in a partfile. Just exempt it - // from checking - if (file_index < m_file_priority.end_index() - && m_file_priority[file_index] == 0) - continue; - - error_code error; - std::int64_t const size = m_stat_cache.get_filesize(f[0].file_index - , fs, m_save_path, error); - - if (size < 0) - { - if (error != boost::system::errc::no_such_file_or_directory) - { - ec.ec = error; - ec.file(file_index); - ec.operation = storage_error::stat; - return false; - } - else - { - ec.ec = errors::mismatching_file_size; - ec.file(file_index); - ec.operation = storage_error::stat; - return false; - } - } - - if (seed && size != fs.file_size(file_index)) - { - // the resume data indicates we're a seed, but this file has - // the wrong size. Reject the resume data - ec.ec = errors::mismatching_file_size; - ec.file(file_index); - ec.operation = storage_error::check_resume; - return false; - } - - // OK, this file existed, good. Now, skip all remaining pieces in - // this file. We're just sanity-checking whether the files exist - // or not. - peer_request const pr = fs.map_file(file_index - , fs.file_size(file_index) + 1, 0); - i = std::max(next(i), pr.piece); - } - return true; + return aux::verify_resume_data(rd, links, files() + , m_file_priority, m_stat_cache, m_save_path, ec); } status_t default_storage::move_storage(std::string const& sp, int const flags @@ -736,7 +640,7 @@ namespace libtorrent m_pool.release(storage_index()); status_t ret; - std::tie(ret, m_save_path) = libtorrent::move_storage(files(), m_save_path, sp + std::tie(ret, m_save_path) = aux::move_storage(files(), m_save_path, sp , m_part_file.get(), flags, ec); return ret; } diff --git a/src/storage_utils.cpp b/src/storage_utils.cpp index b1a6582fc..213d367a3 100644 --- a/src/storage_utils.cpp +++ b/src/storage_utils.cpp @@ -36,11 +36,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file.hpp" // for count_bufs #include "libtorrent/part_file.hpp" #include "libtorrent/session.hpp" // for session::delete_files +#include "libtorrent/stat_cache.hpp" +#include "libtorrent/add_torrent_params.hpp" #include #include -namespace libtorrent +namespace libtorrent { namespace aux { int copy_bufs(span bufs, int bytes, span target) { @@ -445,5 +447,113 @@ namespace libtorrent } } } -} + + bool verify_resume_data(add_torrent_params const& rd + , aux::vector const& links + , file_storage const& fs + , aux::vector const& file_priority + , stat_cache& stat + , std::string const& save_path + , storage_error& ec) + { +#ifdef TORRENT_DISABLE_MUTABLE_TORRENTS + TORRENT_UNUSED(links); +#else + if (!links.empty()) + { + TORRENT_ASSERT(int(links.size()) == fs.num_files()); + // if this is a mutable torrent, and we need to pick up some files + // from other torrents, do that now. Note that there is an inherent + // race condition here. We checked if the files existed on a different + // thread a while ago. These files may no longer exist or may have been + // moved. If so, we just fail. The user is responsible to not touch + // other torrents until a new mutable torrent has been completely + // added. + for (file_index_t idx(0); idx < fs.end_file(); ++idx) + { + std::string const& s = links[idx]; + if (s.empty()) continue; + + error_code err; + std::string file_path = fs.file_path(idx, save_path); + hard_link(s, file_path, err); + + // if the file already exists, that's not an error + // TODO: 2 is this risky? The upper layer will assume we have the + // whole file. Perhaps we should verify that at least the size + // of the file is correct + if (!err || err == boost::system::errc::file_exists) + continue; + + ec.ec = err; + ec.file(idx); + ec.operation = storage_error::hard_link; + return false; + } + } +#endif // TORRENT_DISABLE_MUTABLE_TORRENTS + + bool const seed = rd.have_pieces.all_set(); + + // parse have bitmask. Verify that the files we expect to have + // actually do exist + for (piece_index_t i(0); i < piece_index_t(rd.have_pieces.size()); ++i) + { + if (rd.have_pieces.get_bit(i) == false) continue; + + std::vector f = fs.map_block(i, 0, 1); + TORRENT_ASSERT(!f.empty()); + + file_index_t const file_index = f[0].file_index; + + // files with priority zero may not have been saved to disk at their + // expected location, but is likely to be in a partfile. Just exempt it + // from checking + if (file_index < file_priority.end_index() + && file_priority[file_index] == 0) + continue; + + error_code error; + std::int64_t const size = stat.get_filesize(f[0].file_index + , fs, save_path, error); + + if (size < 0) + { + if (error != boost::system::errc::no_such_file_or_directory) + { + ec.ec = error; + ec.file(file_index); + ec.operation = storage_error::stat; + return false; + } + else + { + ec.ec = errors::mismatching_file_size; + ec.file(file_index); + ec.operation = storage_error::stat; + return false; + } + } + + if (seed && size != fs.file_size(file_index)) + { + // the resume data indicates we're a seed, but this file has + // the wrong size. Reject the resume data + ec.ec = errors::mismatching_file_size; + ec.file(file_index); + ec.operation = storage_error::check_resume; + return false; + } + + // OK, this file existed, good. Now, skip all remaining pieces in + // this file. We're just sanity-checking whether the files exist + // or not. + peer_request const pr = fs.map_file(file_index + , fs.file_size(file_index) + 1, 0); + i = std::max(next(i), pr.piece); + } + return true; + } + +}} diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 6eec54b30..e8ec0bcbb 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -990,7 +990,7 @@ TORRENT_TEST(iovec_copy_bufs) TEST_CHECK(bufs_size({iov1, 10}) >= 106); // copy exactly 106 bytes from iov1 to iov2 - int num_bufs = copy_bufs(iov1, 106, iov2); + int num_bufs = aux::copy_bufs(iov1, 106, iov2); // verify that the first 100 bytes is pattern 1 // and that the remaining bytes are pattern 2 @@ -1057,7 +1057,7 @@ TORRENT_TEST(iovec_advance_bufs) // advance iov 13 bytes. Make sure what's left fits pattern 1 shifted // 13 bytes - iov = advance_bufs(iov, 13); + iov = aux::advance_bufs(iov, 13); // make sure what's in int counter = 13; @@ -1089,7 +1089,7 @@ file_storage make_fs() return fs; } -struct test_fileop : libtorrent::fileop +struct test_fileop : aux::fileop { explicit test_fileop(int stripe_size) : m_stripe_size(stripe_size) {} @@ -1127,7 +1127,7 @@ struct test_fileop : libtorrent::fileop aux::vector, file_index_t> m_file_data; }; -struct test_read_fileop : fileop +struct test_read_fileop : aux::fileop { // EOF after size bytes read explicit test_read_fileop(int size) : m_size(size), m_counter(0) {} @@ -1157,7 +1157,7 @@ struct test_read_fileop : fileop int m_counter; }; -struct test_error_fileop : fileop +struct test_error_fileop : aux::fileop { // EOF after size bytes read explicit test_error_fileop(file_index_t error_file) @@ -1207,7 +1207,7 @@ TORRENT_TEST(readwritev_stripe_1) TEST_CHECK(bufs_size({iov, size_t(num_bufs)}) >= fs.total_size()); iovec_t iov2[num_bufs]; - copy_bufs(iov, int(fs.total_size()), iov2); + aux::copy_bufs(iov, int(fs.total_size()), iov2); int num_bufs2 = count_bufs(iov2, int(fs.total_size())); TEST_CHECK(num_bufs2 <= num_bufs);