issue-949_test.go | 27 +++++++++++++++++++++++++++ metainfo/info.go | 11 ++++++++--- metainfo/piece.go | 2 +- torrent.go | 4 ++-- diff --git a/issue-949_test.go b/issue-949_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f04bd5574d3f7ebd8dc69744573aa1058a1b357c --- /dev/null +++ b/issue-949_test.go @@ -0,0 +1,27 @@ +package torrent + +import ( + "github.com/anacrolix/torrent/metainfo" + qt "github.com/frankban/quicktest" + "testing" +) + +func TestIssue949LastPieceZeroPadding(t *testing.T) { + // This torrent has a padding file after the last file listed in the v2 info file tree. + mi, err := metainfo.LoadFromFile("testdata/issue-949.torrent") + if err != nil { + panic(err) + } + info, err := mi.UnmarshalInfo() + if err != nil { + panic(err) + } + lastPiece := info.Piece(info.NumPieces() - 1) + c := qt.New(t) + c.Assert(info.FilesArePieceAligned(), qt.IsTrue) + // Check the v1 piece length includes the trailing padding file. + c.Check(lastPiece.V1Length(), qt.Equals, info.PieceLength) + // The v2 piece should only include the file data, which fits inside the piece length for this + // file. + c.Check(lastPiece.Length(), qt.Equals, int64(3677645)) +} diff --git a/metainfo/info.go b/metainfo/info.go index 3f14b08b5b97ee697a0056daa9caaa6333595b30..5252e209f78db67fe77c1a19b892275ea3ea3e39 100644 --- a/metainfo/info.go +++ b/metainfo/info.go @@ -150,9 +150,8 @@ // I wonder if we should check for the existence of Info.Length here instead. return len(info.Files) != 0 } -// The files field, converted up from the old single-file in the parent info -// dict if necessary. This is a helper to avoid having to conditionally handle -// single and multi-file torrent infos. +// The files field, converted up from the old single-file in the parent info dict if necessary. This +// is a helper to avoid having to conditionally handle single and multi-file torrent infos. func (info *Info) UpvertedFiles() (files []FileInfo) { if info.HasV2() { info.FileTree.upvertedFiles(info.PieceLength, func(fi FileInfo) { @@ -160,6 +159,12 @@ files = append(files, fi) }) return } + return info.UpvertedV1Files() +} + +// UpvertedFiles but specific to the files listed in the v1 info fields. This will include padding +// files for example that wouldn't appear in v2 file trees. +func (info *Info) UpvertedV1Files() (files []FileInfo) { if len(info.Files) == 0 { return []FileInfo{{ Length: info.Length, diff --git a/metainfo/piece.go b/metainfo/piece.go index c4101a6dc63b7d1566c68bb894a73497b9bc07fd..946e874bb248d75504d5fba1b1e5c22e924e0274 100644 --- a/metainfo/piece.go +++ b/metainfo/piece.go @@ -45,7 +45,7 @@ switch { case 0 <= i && i < lastPiece: return p.Info.PieceLength case lastPiece >= 0 && i == lastPiece: - files := p.Info.UpvertedFiles() + files := p.Info.UpvertedV1Files() lastFile := files[len(files)-1] length := lastFile.TorrentOffset + lastFile.Length - int64(i)*p.Info.PieceLength if length <= 0 || length > p.Info.PieceLength { diff --git a/testdata/issue-949.torrent b/testdata/issue-949.torrent new file mode 100644 index 0000000000000000000000000000000000000000..7ebf67d6b3fefbae0244da29a53300c07ddf0ac8 Binary files /dev/null and b/testdata/issue-949.torrent differ diff --git a/torrent.go b/torrent.go index 3a5d358c6c05f9360ee5a95854b59a1e036946df..26c1714d2df73f05457a1670e2cf4341b2588f4e 100644 --- a/torrent.go +++ b/torrent.go @@ -1157,8 +1157,8 @@ return } h := pieceHash.New() differingPeers, err = t.hashPieceWithSpecificHash(piece, h) - // For a hybrid torrent, we work with the v2 files, but if we use a v1 hash, we can assume that - // the pieces are padded with zeroes. + // For a hybrid torrent, we work with the v2 files, but if we use a v1 hash, we can assume + // that the pieces are padded with zeroes. if t.info.FilesArePieceAligned() { paddingLen := p.Info().V1Length() - p.Info().Length() written, err := io.CopyN(h, zeroReader, paddingLen)