]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Fix file storage segments for v2 torrents
authorMatt Joiner <anacrolix@gmail.com>
Fri, 1 Mar 2024 12:54:56 +0000 (23:54 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Sat, 2 Mar 2024 02:02:56 +0000 (13:02 +1100)
common/upverted_files.go
segments/index.go
storage/file-piece.go
storage/file.go
torrent.go
webseed/client.go

index 1933e16a13bdaff14c620a65f5838a542de3fdfc..8984eb251cfa01ec39b644baa2ccd6b616a8de12 100644 (file)
@@ -16,3 +16,12 @@ func LengthIterFromUpvertedFiles(fis []metainfo.FileInfo) segments.LengthIter {
                return l, true
        }
 }
+
+// Returns file segments, BitTorrent v2 aware.
+func TorrentOffsetFileSegments(info *metainfo.Info) (ret []segments.Extent) {
+       files := info.UpvertedFiles()
+       for _, fi := range files {
+               ret = append(ret, segments.Extent{fi.TorrentOffset, fi.Length})
+       }
+       return
+}
index 6717dcba463db0ae0ed059a56283b26fc5dd1cdc..888e90a813afcaccef5c4a2c370a486532ba2bae 100644 (file)
@@ -17,6 +17,10 @@ type Index struct {
        segments []Extent
 }
 
+func NewIndexFromSegments(segments []Extent) Index {
+       return Index{segments}
+}
+
 func (me Index) iterSegments() func() (Length, bool) {
        return func() (Length, bool) {
                if len(me.segments) == 0 {
@@ -29,6 +33,8 @@ func (me Index) iterSegments() func() (Length, bool) {
        }
 }
 
+// Returns true if the callback returns false early, or extents are found in the index for all parts
+// of the given extent.
 func (me Index) Locate(e Extent, output Callback) bool {
        first := sort.Search(len(me.segments), func(i int) bool {
                _e := me.segments[i]
index 47772017e3e1680f28a8e4de7bb74aa40202aa5f..99ff5fc8675129083f4fd1b4d8dbe6fc0bfc7168 100644 (file)
@@ -1,6 +1,7 @@
 package storage
 
 import (
+       "github.com/anacrolix/torrent/segments"
        "io"
        "log"
        "os"
@@ -32,12 +33,19 @@ func (fs *filePieceImpl) Completion() Completion {
        verified := true
        if c.Complete {
                // If it's allegedly complete, check that its constituent files have the necessary length.
-               for _, fi := range extentCompleteRequiredLengths(fs.p.Info, fs.p.Offset(), fs.p.Length()) {
-                       s, err := os.Stat(fs.files[fi.fileIndex].path)
-                       if err != nil || s.Size() < fi.length {
+               if !fs.segmentLocater.Locate(segments.Extent{
+                       Start:  fs.p.Offset(),
+                       Length: fs.p.Length(),
+               }, func(i int, extent segments.Extent) bool {
+                       file := fs.files[i]
+                       s, err := os.Stat(file.path)
+                       if err != nil || s.Size() < extent.Start+extent.Length {
                                verified = false
-                               break
+                               return false
                        }
+                       return true
+               }) {
+                       panic("files do not cover piece extent")
                }
        }
 
index b873964787886d4e62169deecc2141bfc3ef5473..231825fdfeed38f9dfeb1229542c8fde31942bde 100644 (file)
@@ -83,7 +83,7 @@ func (fs fileClientImpl) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash
        }
        t := &fileTorrentImpl{
                files,
-               segments.NewIndex(common.LengthIterFromUpvertedFiles(upvertedFiles)),
+               segments.NewIndexFromSegments(common.TorrentOffsetFileSegments(info)),
                infoHash,
                fs.opts.PieceCompletion,
        }
index 64e8066012ca015c50f32dc52e46c06035fc572b..a361c4edd64037bfda43b053e44bbc3614698404 100644 (file)
@@ -1133,7 +1133,11 @@ func (t *Torrent) hashPiece(piece pieceIndex) (
        if logPieceContents {
                writers = append(writers, &examineBuf)
        }
-       _, err = storagePiece.WriteTo(io.MultiWriter(writers...))
+       var written int64
+       written, err = storagePiece.WriteTo(io.MultiWriter(writers...))
+       if err == nil && written != int64(p.length()) {
+               err = io.ErrShortWrite
+       }
        if logPieceContents {
                t.logger.WithDefaultLevel(log.Debug).Printf("hashed %q with copy err %v", examineBuf.Bytes(), err)
        }
index d5ae3ac1db51528b56f2b50c52f2329c5f7b130e..4614a3e407a9bc1adb5c55e2a1cd902eccbd7e64 100644 (file)
@@ -64,7 +64,7 @@ func (me *Client) SetInfo(info *metainfo.Info) {
                // http://ia600500.us.archive.org/1/items URLs in archive.org torrents.
                return
        }
-       me.fileIndex = segments.NewIndex(common.LengthIterFromUpvertedFiles(info.UpvertedFiles()))
+       me.fileIndex = segments.NewIndexFromSegments(common.TorrentOffsetFileSegments(info))
        me.info = info
        me.Pieces.AddRange(0, uint64(info.NumPieces()))
 }