From e6e0b227dabee4a8f46565af1b93e9a00713bcc5 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 16 May 2015 13:23:33 +0100 Subject: [PATCH] Multiple file metainfo mode support in cmd tools torrent-create and torrent-verify did not work correctly when a single file is present in metainfo torrent file. torrent-create now fails if the path passed as an argument does not exist. I've als modified dht.go which now handles the case when an empty string is passed in DHT bootstrap nodes slice. Finally in span.go I've sneaked in cheekily a change which defines a type more like idiomatic Go (I have an OCD :-)) --- cmd/torrent-create/main.go | 3 ++ cmd/torrent-verify/main.go | 71 +++++++++++++++++++++++--------------- dht/dht.go | 10 +++--- mmap_span/span.go | 4 +-- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/cmd/torrent-create/main.go b/cmd/torrent-create/main.go index 65978b76..3f80a928 100644 --- a/cmd/torrent-create/main.go +++ b/cmd/torrent-create/main.go @@ -26,6 +26,9 @@ func init() { func main() { b := torrent.Builder{} for _, filename := range flag.Args() { + if _, err := os.Stat(filename); os.IsNotExist(err) { + log.Fatal(err) + } if err := filepath.Walk(filename, func(path string, info os.FileInfo, err error) error { log.Print(path) if info.IsDir() { diff --git a/cmd/torrent-verify/main.go b/cmd/torrent-verify/main.go index 9aae543f..061932e4 100644 --- a/cmd/torrent-verify/main.go +++ b/cmd/torrent-verify/main.go @@ -16,16 +16,40 @@ import ( ) var ( - filePath = flag.String("torrent", "/path/to/the.torrent", "path of the torrent file") - dirPath = flag.String("path", "/torrent/data", "path of the torrent data") + torrentPath = flag.String("torrent", "/path/to/the.torrent", "path of the torrent file") + dataPath = flag.String("path", "/torrent/data", "path of the torrent data") + summary = flag.Bool("summary", false, "display summary at the end") ) -func init() { - flag.Parse() +func verifySummary(sMap map[bool][]int) { + fmt.Println("----------------") + fmt.Println(" TORRENT-VERIFY ") + fmt.Println("----------------") + fmt.Printf("Number of correct pieces: %d\n", len(sMap[true])) + fmt.Printf("Number of wrong pieces: %d\n", len(sMap[false])) +} + +func fileToMmap(filename string, length int64, devZero *os.File, mMapSpan *mmap_span.MMapSpan) { + osFile, err := os.Open(filename) + if err != nil { + log.Fatal(err) + } + mmapFd := osFile.Fd() + goMMap, err := gommap.MapRegion(mmapFd, 0, length, gommap.PROT_READ, gommap.MAP_PRIVATE) + if err != nil { + log.Fatal(err) + } + if int64(len(goMMap)) != length { + log.Printf("file mmap has wrong size: %#v", filename) + } + osFile.Close() + mMapSpan.Append(goMMap) } func main() { - metaInfo, err := metainfo.LoadFromFile(*filePath) + flag.Parse() + summaryMap := make(map[bool][]int) + metaInfo, err := metainfo.LoadFromFile(*torrentPath) if err != nil { log.Fatal(err) } @@ -34,31 +58,19 @@ func main() { log.Print(err) } defer devZero.Close() - var mMapSpan *mmap_span.MMapSpan - for _, file := range metaInfo.Info.Files { - filename := filepath.Join(append([]string{*dirPath, metaInfo.Info.Name}, file.Path...)...) - osFile, err := os.Open(filename) - mmapFd := osFile.Fd() - if err != nil { - if pe, ok := err.(*os.PathError); ok && pe.Err.Error() == "no such file or directory" { - mmapFd = devZero.Fd() - } else { - log.Fatal(err) - } + mMapSpan := &mmap_span.MMapSpan{} + if len(metaInfo.Info.Files) > 0 { + for _, file := range metaInfo.Info.Files { + filename := filepath.Join(append([]string{*dataPath, metaInfo.Info.Name}, file.Path...)...) + fileToMmap(filename, file.Length, devZero, mMapSpan) } - goMMap, err := gommap.MapRegion(mmapFd, 0, file.Length, gommap.PROT_READ, gommap.MAP_PRIVATE) - if err != nil { - log.Fatal(err) - } - if int64(len(goMMap)) != file.Length { - log.Printf("file mmap has wrong size: %#v", filename) - } - osFile.Close() - mMapSpan.Append(goMMap) + log.Println(len(metaInfo.Info.Files)) + } else { + fileToMmap(*dataPath, metaInfo.Info.Length, devZero, mMapSpan) } - log.Println(len(metaInfo.Info.Files)) log.Println(mMapSpan.Size()) log.Println(len(metaInfo.Info.Pieces)) + var pieceValid bool for piece := 0; piece < (len(metaInfo.Info.Pieces)+sha1.Size-1)/sha1.Size; piece++ { expectedHash := metaInfo.Info.Pieces[sha1.Size*piece : sha1.Size*(piece+1)] if len(expectedHash) == 0 { @@ -69,6 +81,11 @@ func main() { if err != nil { log.Fatal(err) } - fmt.Println(piece, bytes.Equal(hash.Sum(nil), expectedHash)) + pieceValid = bytes.Equal(hash.Sum(nil), expectedHash) + summaryMap[pieceValid] = append(summaryMap[pieceValid], piece) + fmt.Println(piece, pieceValid) + } + if *summary { + verifySummary(summaryMap) } } diff --git a/dht/dht.go b/dht/dht.go index deb45e79..116da78f 100644 --- a/dht/dht.go +++ b/dht/dht.go @@ -980,11 +980,13 @@ func bootstrapAddrs(nodeAddrs []string) (addrs []*net.UDPAddr, err error) { } } for _, addrStr := range bootstrapNodes { - udpAddr, err := net.ResolveUDPAddr("udp4", addrStr) - if err != nil { - continue + if addrStr != "" { + udpAddr, err := net.ResolveUDPAddr("udp4", addrStr) + if err != nil { + continue + } + addrs = append(addrs, udpAddr) } - addrs = append(addrs, udpAddr) } if len(addrs) == 0 { err = errors.New("nothing resolved") diff --git a/mmap_span/span.go b/mmap_span/span.go index 5db95885..622c179a 100644 --- a/mmap_span/span.go +++ b/mmap_span/span.go @@ -4,9 +4,7 @@ type sizer interface { Size() int64 } -type ( - span []sizer -) +type span []sizer func (me span) ApplyTo(off int64, f func(int64, sizer) (stop bool)) { for _, interval := range me {