From a0a715c6f64204c5d5e2bd308a4736a80cba29d1 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Tue, 8 Apr 2014 16:45:33 +1000 Subject: [PATCH] Fix calculation of request for torrent data offset --- torrent.go | 28 ++++++++++++++++------------ torrent_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 torrent_test.go diff --git a/torrent.go b/torrent.go index 19c64d2f..5445eb97 100644 --- a/torrent.go +++ b/torrent.go @@ -74,25 +74,29 @@ func (t *Torrent) piecesByPendingBytesDesc() (indices []peer_protocol.Integer) { return slice.Indices } -func (t *Torrent) offsetRequest(off int64) (req Request, ok bool) { - req.Index = peer_protocol.Integer(off / t.MetaInfo.PieceLength) - if req.Index < 0 || int(req.Index) >= len(t.Pieces) { - return - } - off %= t.MetaInfo.PieceLength - pieceLeft := t.PieceLength(req.Index) - peer_protocol.Integer(off) - if pieceLeft <= 0 { +// Return the request that would include the given offset into the torrent data. +func torrentOffsetRequest(torrentLength, pieceSize, chunkSize, offset int64) ( + r Request, ok bool) { + if offset < 0 || offset >= torrentLength { return } - req.Begin = chunkSize * (peer_protocol.Integer(off) / chunkSize) - req.Length = chunkSize - if req.Length > pieceLeft { - req.Length = pieceLeft + r.Index = peer_protocol.Integer(offset / pieceSize) + r.Begin = peer_protocol.Integer(offset % pieceSize / chunkSize * chunkSize) + left := torrentLength - int64(r.Index)*pieceSize - int64(r.Begin) + if chunkSize < left { + r.Length = peer_protocol.Integer(chunkSize) + } else { + r.Length = peer_protocol.Integer(left) } ok = true return } +// Return the request that would include the given offset into the torrent data. +func (t *Torrent) offsetRequest(off int64) (req Request, ok bool) { + return torrentOffsetRequest(t.Length(), t.MetaInfo.PieceLength, chunkSize, off) +} + func (t *Torrent) WriteChunk(piece int, begin int64, data []byte) (err error) { _, err = t.Data.WriteAt(data, int64(piece)*t.MetaInfo.PieceLength+begin) return diff --git a/torrent_test.go b/torrent_test.go new file mode 100644 index 00000000..e31a16a2 --- /dev/null +++ b/torrent_test.go @@ -0,0 +1,42 @@ +package torrent + +import ( + "bitbucket.org/anacrolix/go.torrent/peer_protocol" + "testing" +) + +func r(i, b, l peer_protocol.Integer) Request { + return Request{i, ChunkSpec{b, l}} +} + +// Check the given Request is correct for various torrent offsets. +func TestTorrentRequest(t *testing.T) { + const s = 472183431 // Length of torrent. + for _, _case := range []struct { + off int64 // An offset into the torrent. + req Request // The expected Request. The zero value means !ok. + }{ + // Invalid offset. + {-1, Request{}}, + {0, r(0, 0, 16384)}, + // One before the end of a piece. + {1<<18 - 1, r(0, 1<<18-16384, 16384)}, + // Offset beyond torrent length. + {472 * 1 << 20, Request{}}, + // One before the end of the torrent. Complicates the chunk length. + {s - 1, r((s-1)/(1<<18), (s-1)%(1<<18)/(16384)*(16384), 12935)}, + {1, r(0, 0, 16384)}, + // One before end of chunk. + {16383, r(0, 0, 16384)}, + // Second chunk. + {16384, r(0, 16384, 16384)}, + } { + req, ok := torrentOffsetRequest(472183431, 1<<18, 16384, _case.off) + if (_case.req == Request{}) == ok { + t.Fatalf("expected %v, got %v", _case.req, req) + } + if req != _case.req { + t.Fatalf("expected %v, got %v", _case.req, req) + } + } +} -- 2.44.0