diff --git a/include/libtorrent/aux_/disk_cache.hpp b/include/libtorrent/aux_/disk_cache.hpp index d0ca9b3af45..2e78984f537 100644 --- a/include/libtorrent/aux_/disk_cache.hpp +++ b/include/libtorrent/aux_/disk_cache.hpp @@ -108,8 +108,9 @@ struct cached_block_entry struct cached_piece_entry { - cached_piece_entry(piece_location const& loc, int const num_blocks) + cached_piece_entry(piece_location const& loc, int const num_blocks, int const piece_size_v2) : piece(loc) + , piece_size2(piece_size_v2) , blocks_in_piece(num_blocks) , blocks(std::make_unique(std::size_t(num_blocks))) , ph(hasher()) @@ -144,6 +145,10 @@ struct cached_piece_entry bool v1_hashes = false; bool v2_hashes = false; + // if this is a v2 torrent, this is the exact size of this piece. The + // end-piece of each file may be truncated for v2 torrents + int piece_size2; + int blocks_in_piece = 0; // the number of blocks that have been hashed so far. Specifically for the @@ -404,11 +409,11 @@ struct disk_cache auto i = view.find(loc); if (i == view.end()) { -//#error this computation is not right for v2 torrents. it will make v2 hashes computed incorrectly -//#error we don't know what the block size actually is here. If the piece size is less than 16 kiB, this computation is incorrect pread_storage* storage = write_job->storage.get(); + file_storage const& fs = storage->files(); int const blocks_in_piece = (storage->files().piece_size(loc.piece) + default_block_size - 1) / default_block_size; - cached_piece_entry pe(loc, blocks_in_piece); + int const piece_size2 = fs.piece_size2(loc.piece); + cached_piece_entry pe(loc, blocks_in_piece, piece_size2); pe.v1_hashes = storage->v1(); pe.v2_hashes = storage->v2(); i = m_pieces.insert(std::move(pe)).first; @@ -526,7 +531,7 @@ struct disk_cache ++block_idx; ++end; } - auto blocks = blocks_storage.first(block_idx); + auto const blocks = blocks_storage.first(block_idx); hasher& ctx = const_cast(piece_iter->ph); @@ -537,6 +542,7 @@ struct disk_cache l.unlock(); + int bytes_left = piece_iter->piece_size2 - (cursor * default_block_size); for (auto& buf: blocks) { cached_block_entry& cbe = piece_iter->blocks[cursor]; @@ -544,8 +550,12 @@ struct disk_cache if (need_v1) ctx.update(buf); - if (need_v2) - cbe.block_hash = hasher256(buf).final(); + if (need_v2 && bytes_left > 0) + { + int const this_block_size = std::min(bytes_left, default_block_size); + cbe.block_hash = hasher256(buf.first(this_block_size)).final(); + bytes_left -= default_block_size; + } ++cursor; }