From 0ecfeec242bf9ebabe4ae30a982187757e966b49 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Wed, 20 Mar 2024 14:02:41 +1100 Subject: [PATCH] Include piece layers in dynamically generated metainfo --- metainfo/metainfo.go | 2 +- torrent.go | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/metainfo/metainfo.go b/metainfo/metainfo.go index b20a9efd..6a5ea1cd 100644 --- a/metainfo/metainfo.go +++ b/metainfo/metainfo.go @@ -24,7 +24,7 @@ type MetaInfo struct { CreatedBy string `bencode:"created by,omitempty"` Encoding string `bencode:"encoding,omitempty"` UrlList UrlList `bencode:"url-list,omitempty"` // BEP 19 WebSeeds - // BEP 52 (BitTorrent v2): Keys are file merkle roots (pieces root?), and the values are the + // BEP 52 (BitTorrent v2): Keys are file merkle roots ("pieces root"s), and the values are the // concatenated hashes of the merkle tree layer that corresponds to the piece length. PieceLayers map[string]string `bencode:"piece layers,omitempty"` } diff --git a/torrent.go b/torrent.go index e2375a44..b952e3ce 100644 --- a/torrent.go +++ b/torrent.go @@ -922,7 +922,7 @@ func (t *Torrent) newMetaInfo() metainfo.MetaInfo { return metainfo.MetaInfo{ CreationDate: time.Now().Unix(), Comment: "dynamic metainfo from client", - CreatedBy: "go.torrent", + CreatedBy: "https://github.com/anacrolix/torrent", AnnounceList: t.metainfo.UpvertedAnnounceList().Clone(), InfoBytes: func() []byte { if t.haveInfo() { @@ -938,6 +938,7 @@ func (t *Torrent) newMetaInfo() metainfo.MetaInfo { } return ret }(), + PieceLayers: t.pieceLayers(), } } @@ -3169,3 +3170,34 @@ func (t *Torrent) getFileByPiecesRoot(hash [32]byte) *File { } return nil } + +func (t *Torrent) pieceLayers() (pieceLayers map[string]string) { + if t.files == nil { + return + } + files := *t.files + g.MakeMapWithCap(&pieceLayers, len(files)) +file: + for _, f := range files { + if !f.piecesRoot.Ok { + continue + } + key := f.piecesRoot.Value + var value strings.Builder + for i := f.BeginPieceIndex(); i < f.EndPieceIndex(); i++ { + hashOpt := t.piece(i).hashV2 + if !hashOpt.Ok { + // All hashes must be present. This implementation should handle missing files, so move on to the next file. + continue file + } + value.Write(hashOpt.Value[:]) + } + if value.Len() == 0 { + // Non-empty files are not recorded in piece layers. + continue + } + // If multiple files have the same root that shouldn't matter. + pieceLayers[string(key[:])] = value.String() + } + return +} -- 2.44.0