diff --git a/cmd/torrent-verify/main.go b/cmd/torrent-verify/main.go index ba64d801..4e5774d9 100644 --- a/cmd/torrent-verify/main.go +++ b/cmd/torrent-verify/main.go @@ -3,13 +3,13 @@ package main import ( "bytes" "crypto/sha1" - "flag" "fmt" "io" "log" "os" "path/filepath" + "github.com/anacrolix/tagflag" "github.com/bradfitz/iter" "github.com/edsrzf/mmap-go" @@ -17,35 +17,56 @@ import ( "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) } @@ -53,27 +74,8 @@ func main() { 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) } }