import (
"bytes"
"crypto/sha1"
- "flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
+ "github.com/anacrolix/tagflag"
"github.com/bradfitz/iter"
"github.com/edsrzf/mmap-go"
"github.com/anacrolix/torrent/mmap_span"
)
-var (
- torrentPath = flag.String("torrent", "/path/to/the.torrent", "path of the torrent file")
- dataPath = flag.String("path", "/torrent/data", "path of the torrent data")
-)
-
-func fileToMmap(filename string, length int64) mmap.MMap {
- osFile, err := os.Open(filename)
- if os.IsNotExist(err) {
- return nil
- }
+func mmapFile(name string) (mm mmap.MMap, err error) {
+ f, err := os.Open(name)
if err != nil {
- log.Fatal(err)
+ return
}
- goMMap, err := mmap.MapRegion(osFile, int(length), mmap.RDONLY, mmap.COPY, 0)
+ defer f.Close()
+ fi, err := f.Stat()
if err != nil {
- log.Fatal(err)
+ return
}
- if int64(len(goMMap)) != length {
- log.Printf("file mmap has wrong size: %#v", filename)
+ if fi.Size() == 0 {
+ return
}
- osFile.Close()
+ return mmap.MapRegion(f, -1, mmap.RDONLY, mmap.COPY, 0)
+}
- return goMMap
+func verifyTorrent(info *metainfo.Info, root string) error {
+ span := new(mmap_span.MMapSpan)
+ for _, file := range info.UpvertedFiles() {
+ filename := filepath.Join(append([]string{root, info.Name}, file.Path...)...)
+ mm, err := mmapFile(filename)
+ if err != nil {
+ return err
+ }
+ if int64(len(mm)) != file.Length {
+ return fmt.Errorf("file %q has wrong length", filename)
+ }
+ span.Append(mm)
+ }
+ for i := range iter.N(info.NumPieces()) {
+ p := info.Piece(i)
+ hash := sha1.New()
+ _, err := io.Copy(hash, io.NewSectionReader(span, p.Offset(), p.Length()))
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%d: %x: %v\n", i, p.Hash(), bytes.Equal(hash.Sum(nil), p.Hash().Bytes()))
+ }
+ return nil
}
func main() {
log.SetFlags(log.Flags() | log.Lshortfile)
- flag.Parse()
- metaInfo, err := metainfo.LoadFromFile(*torrentPath)
+ var flags = struct {
+ DataDir string
+ tagflag.StartPos
+ TorrentFile string
+ }{}
+ tagflag.Parse(&flags)
+ metaInfo, err := metainfo.LoadFromFile(flags.TorrentFile)
if err != nil {
log.Fatal(err)
}
if err != nil {
log.Fatalf("error unmarshalling info: %s", err)
}
- mMapSpan := &mmap_span.MMapSpan{}
- if len(info.Files) > 0 {
- for _, file := range info.Files {
- filename := filepath.Join(append([]string{*dataPath, info.Name}, file.Path...)...)
- goMMap := fileToMmap(filename, file.Length)
- mMapSpan.Append(goMMap)
- }
- log.Println(len(info.Files))
- } else {
- goMMap := fileToMmap(*dataPath, info.Length)
- mMapSpan.Append(goMMap)
- }
- log.Println(mMapSpan.Size())
- log.Println(len(info.Pieces))
- for i := range iter.N(info.NumPieces()) {
- p := info.Piece(i)
- hash := sha1.New()
- _, err := io.Copy(hash, io.NewSectionReader(mMapSpan, p.Offset(), p.Length()))
- if err != nil {
- log.Fatal(err)
- }
- fmt.Printf("%d: %x: %v\n", i, p.Hash(), bytes.Equal(hash.Sum(nil), p.Hash().Bytes()))
+ err = verifyTorrent(&info, flags.DataDir)
+ if err != nil {
+ log.Fatalf("torrent failed verification: %s", err)
}
}