package main
import (
+ "fmt"
"os"
"github.com/anacrolix/torrent/metainfo"
err = metainfo.ValidatePieceLayers(mi.PieceLayers, &info.FileTree, info.PieceLength)
assertOk(err)
},
+ "pprint": func() {
+ mi, err := metainfo.LoadFromFile(args[2])
+ assertOk(err)
+ info, err := mi.UnmarshalInfo()
+ assertOk(err)
+ files := info.UpvertedFiles()
+ pieceIndex := 0
+ for _, f := range files {
+ numPieces := int((f.Length + info.PieceLength - 1) / info.PieceLength)
+ endIndex := pieceIndex + numPieces
+ fmt.Printf(
+ "%x: %q: pieces (%v-%v)\n",
+ f.PiecesRoot.Unwrap(),
+ f.BestPath(),
+ pieceIndex,
+ endIndex-1,
+ )
+ pieceIndex = endIndex
+ }
+ },
}[args[1]]()
},
}[args[0]]()
import (
"crypto/sha256"
"hash"
+ "unsafe"
)
func NewHash() *Hash {
- return &Hash{
+ h := &Hash{
nextBlock: sha256.New(),
}
+ return h
}
type Hash struct {
}
func (h *Hash) nextBlockSum() (sum [32]byte) {
- h.nextBlock.Sum(sum[:0])
+ if unsafe.SliceData(h.nextBlock.Sum(sum[:0])) != unsafe.SliceData(sum[:]) {
+ panic("go sux")
+ }
return
}
func (h *Hash) Reset() {
h.blocks = h.blocks[:0]
h.nextBlock.Reset()
+ h.written = 0
}
func (h *Hash) Size() int {
return keys
}
-func (ft *FileTree) UpvertedFiles(path []string, out func(fi FileInfo)) {
+func (ft *FileTree) upvertedFiles(pieceLength int64, out func(fi FileInfo)) {
+ var offset int64
+ ft.upvertedFilesInner(pieceLength, nil, &offset, out)
+}
+
+func (ft *FileTree) upvertedFilesInner(
+ pieceLength int64,
+ path []string,
+ offset *int64,
+ out func(fi FileInfo),
+) {
if ft.IsDir() {
for _, key := range ft.orderedKeys() {
if key == FileTreePropertiesKey {
continue
}
sub := g.MapMustGet(ft.Dir, key)
- sub.UpvertedFiles(append(path, key), out)
+ sub.upvertedFilesInner(pieceLength, append(path, key), offset, out)
}
} else {
out(FileInfo{
Length: ft.File.Length,
Path: append([]string(nil), path...),
// BEP 52 requires paths be UTF-8 if possible.
- PathUtf8: append([]string(nil), path...),
- PiecesRoot: ft.PiecesRootAsByteArray(),
+ PathUtf8: append([]string(nil), path...),
+ PiecesRoot: ft.PiecesRootAsByteArray(),
+ TorrentOffset: *offset,
})
+ *offset += (ft.File.Length + pieceLength - 1) / pieceLength * pieceLength
}
}
// BEP 52. This isn't encoded in a v1 FileInfo, but is exposed here for APIs that expect to deal
// v1 files.
- PiecesRoot g.Option[[32]byte] `bencode:"-"`
+ PiecesRoot g.Option[[32]byte] `bencode:"-"`
+ TorrentOffset int64 `bencode:"-"`
}
func (fi *FileInfo) DisplayPath(info *Info) string {
// single and multi-file torrent infos.
func (info *Info) UpvertedFiles() (files []FileInfo) {
if info.HasV2() {
- info.FileTree.UpvertedFiles(nil, func(fi FileInfo) {
+ info.FileTree.upvertedFiles(info.PieceLength, func(fi FileInfo) {
files = append(files, fi)
})
return
pieceLength := p.Info.PieceLength
lastFileEnd := int64(0)
done := false
- p.Info.FileTree.UpvertedFiles(nil, func(fi FileInfo) {
+ p.Info.FileTree.upvertedFiles(pieceLength, func(fi FileInfo) {
if done {
return
}
type Length = Int
-func min(i Int, rest ...Int) Int {
- ret := i
- for _, i := range rest {
- if i < ret {
- ret = i
- }
- }
- return ret
-}
-
type Extent struct {
Start, Length Int
}
}
type (
- Callback = func(int, Extent) bool
+ Callback = func(segmentIndex int, segmentBounds Extent) bool
LengthIter = func() (Length, bool)
)
+// Returns true if callback returns false early, or all segments in the haystack for the needle are
+// found.
func Scan(haystack LengthIter, needle Extent, callback Callback) bool {
i := 0
for needle.Length != 0 {
if err != nil {
err = fmt.Errorf("unmarshalling info: %w", err)
}
- v1Ih := mi.HashInfoBytes()
+ var v1Ih metainfo.Hash
+ if info.HasV1() {
+ v1Ih = mi.HashInfoBytes()
+ }
var v2Infohash g.Option[infohash_v2.T]
if info.HasV2() {
v2Infohash.Set(infohash_v2.HashBytes(mi.InfoBytes))
- if !info.HasV1() {
- v1Ih = *v2Infohash.Value.ToShort()
- }
}
return &TorrentSpec{
func (t *Torrent) pieceHasher(index pieceIndex) {
p := t.piece(index)
+ // Do we really need to spell out that it's a copy error? If it's a failure to hash the hash
+ // will just be wrong.
correct, failedPeers, copyErr := t.hashPiece(index)
switch copyErr {
case nil, io.EOF:
default:
- log.Fmsg("piece %v (%s) hash failure copy error: %v", p, p.hash.HexString(), copyErr).Log(t.logger)
+ t.logger.Levelf(
+ log.Warning,
+ "error hashing piece %v: %v", index, copyErr)
}
t.storageLock.RUnlock()
t.cl.lock()