]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Fix calculation of request for torrent data offset
authorMatt Joiner <anacrolix@gmail.com>
Tue, 8 Apr 2014 06:45:33 +0000 (16:45 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Tue, 8 Apr 2014 06:45:33 +0000 (16:45 +1000)
torrent.go
torrent_test.go [new file with mode: 0644]

index 19c64d2fbb0a99dc0d205f00942d65e308a9141f..5445eb97f1d221c488b7a1748a80c3175479d4d8 100644 (file)
@@ -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 (file)
index 0000000..e31a16a
--- /dev/null
@@ -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)
+               }
+       }
+}