factor out verify_resume_data to storage_utils
This commit is contained in:
parent
8cc88a8921
commit
202386dd9d
|
@ -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<iovec_t const> bufs, int bytes, span<iovec_t> target);
|
||||
TORRENT_EXTRA_EXPORT span<iovec_t> advance_bufs(span<iovec_t> 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<std::string, file_index_t> const& links
|
||||
, file_storage const& fs
|
||||
, aux::vector<std::uint8_t, file_index_t> const& file_priority
|
||||
, stat_cache& stat
|
||||
, std::string const& save_path
|
||||
, storage_error& ec);
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
108
src/storage.cpp
108
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<void*>(this)
|
||||
, ec.ec.message().c_str());
|
||||
|
@ -630,104 +630,8 @@ namespace libtorrent
|
|||
, aux::vector<std::string, file_index_t> 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<file_slice> 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;
|
||||
}
|
||||
|
|
|
@ -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 <set>
|
||||
#include <string>
|
||||
|
||||
namespace libtorrent
|
||||
namespace libtorrent { namespace aux
|
||||
{
|
||||
int copy_bufs(span<iovec_t const> bufs, int bytes, span<iovec_t> target)
|
||||
{
|
||||
|
@ -445,5 +447,113 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool verify_resume_data(add_torrent_params const& rd
|
||||
, aux::vector<std::string, file_index_t> const& links
|
||||
, file_storage const& fs
|
||||
, aux::vector<std::uint8_t, file_index_t> 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<file_slice> 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;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
|
|
@ -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<std::vector<char>, 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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue