From: Matt Joiner Date: Tue, 11 Jun 2024 06:21:04 +0000 (+1000) Subject: Correctly hash hybrid torrents with trailing v1 padding file X-Git-Tag: v1.56.1 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=3bbe1c34f0dcd92fb5ba8fa673fd85ffa942952b;p=btrtrc.git Correctly hash hybrid torrents with trailing v1 padding file Fixes #949. --- diff --git a/issue-949_test.go b/issue-949_test.go new file mode 100644 index 00000000..f04bd557 --- /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 3f14b08b..5252e209 100644 --- a/metainfo/info.go +++ b/metainfo/info.go @@ -150,9 +150,8 @@ func (info *Info) IsDir() bool { 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 @@ func (info *Info) UpvertedFiles() (files []FileInfo) { }) 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 c4101a6d..946e874b 100644 --- a/metainfo/piece.go +++ b/metainfo/piece.go @@ -45,7 +45,7 @@ func (p Piece) V1Length() int64 { 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 00000000..7ebf67d6 Binary files /dev/null and b/testdata/issue-949.torrent differ diff --git a/torrent.go b/torrent.go index 3a5d358c..26c1714d 100644 --- a/torrent.go +++ b/torrent.go @@ -1157,8 +1157,8 @@ func (t *Torrent) hashPiece(piece pieceIndex) ( } 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)