From bb04cb88430d2609c5f0c67f71029d08c98960ec Mon Sep 17 00:00:00 2001
From: Matt Joiner <anacrolix@gmail.com>
Date: Tue, 22 Mar 2016 13:11:36 +1100
Subject: [PATCH] Tidy up bytesLeft calculations

This should fix a bug where completion is shown as negative in WriteStatus
---
 misc.go    |  8 ++++++++
 piece.go   | 50 ++++++++++++++++++++++++++++++++++++++++++--------
 torrent.go | 24 +-----------------------
 3 files changed, 51 insertions(+), 31 deletions(-)

diff --git a/misc.go b/misc.go
index ab6dcf78..8f13a179 100644
--- a/misc.go
+++ b/misc.go
@@ -121,3 +121,11 @@ func validateInfo(info *metainfo.Info) error {
 	}
 	return nil
 }
+
+func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
+	ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
+	if ret.Begin+ret.Length > pieceLength {
+		ret.Length = pieceLength - ret.Begin
+	}
+	return ret
+}
diff --git a/piece.go b/piece.go
index bcc09546..104602f3 100644
--- a/piece.go
+++ b/piece.go
@@ -69,14 +69,6 @@ func (p *piece) pendChunkIndex(i int) {
 	p.DirtyChunks.Remove(i)
 }
 
-func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
-	ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
-	if ret.Begin+ret.Length > pieceLength {
-		ret.Length = pieceLength - ret.Begin
-	}
-	return ret
-}
-
 func (p *piece) numChunks() int {
 	return p.t.pieceNumChunks(p.index)
 }
@@ -112,3 +104,45 @@ func (p *piece) waitNoPendingWrites() {
 	}
 	p.pendingWritesMutex.Unlock()
 }
+
+func (p *piece) chunkIndexDirty(chunk int) bool {
+	return p.DirtyChunks.Contains(chunk)
+}
+
+func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
+	return chunkIndexSpec(chunk, p.length(), p.chunkSize())
+}
+
+func (p *piece) numDirtyBytes() (ret pp.Integer) {
+	defer func() {
+		if ret > p.length() {
+			panic("too many dirty bytes")
+		}
+	}()
+	numRegularDirtyChunks := p.numDirtyChunks()
+	if p.chunkIndexDirty(p.numChunks() - 1) {
+		numRegularDirtyChunks--
+		ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
+	}
+	ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
+	return
+}
+
+func (p *piece) length() pp.Integer {
+	return p.t.pieceLength(p.index)
+}
+
+func (p *piece) chunkSize() pp.Integer {
+	return p.t.chunkSize
+}
+
+func (p *piece) lastChunkIndex() int {
+	return p.numChunks() - 1
+}
+
+func (p *piece) bytesLeft() (ret pp.Integer) {
+	if p.t.pieceComplete(p.index) {
+		return 0
+	}
+	return p.length() - p.numDirtyBytes()
+}
diff --git a/torrent.go b/torrent.go
index 6453c508..598c1718 100644
--- a/torrent.go
+++ b/torrent.go
@@ -29,25 +29,6 @@ func (t *torrent) chunkIndexSpec(chunkIndex, piece int) chunkSpec {
 	return chunkIndexSpec(chunkIndex, t.pieceLength(piece), t.chunkSize)
 }
 
-func (t *torrent) pieceNumPendingBytes(index int) (count pp.Integer) {
-	if t.pieceComplete(index) {
-		return
-	}
-	piece := &t.Pieces[index]
-	count = t.pieceLength(index)
-	if !piece.EverHashed {
-		return
-	}
-	regularDirty := piece.numDirtyChunks()
-	lastChunkIndex := t.pieceNumChunks(index) - 1
-	if piece.pendingChunkIndex(lastChunkIndex) {
-		regularDirty--
-		count -= t.chunkIndexSpec(lastChunkIndex, index).Length
-	}
-	count -= pp.Integer(regularDirty) * t.chunkSize
-	return
-}
-
 type peersKey struct {
 	IPBytes string
 	Port    int
@@ -511,11 +492,8 @@ func (t *torrent) MetaInfo() *metainfo.MetaInfo {
 }
 
 func (t *torrent) bytesLeft() (left int64) {
-	if !t.haveInfo() {
-		return -1
-	}
 	for i := 0; i < t.numPieces(); i++ {
-		left += int64(t.pieceNumPendingBytes(i))
+		left += int64(t.Pieces[i].bytesLeft())
 	}
 	return
 }
-- 
2.51.0