main.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package main
  2. import (
  3. "bytes"
  4. "crypto/sha1"
  5. "fmt"
  6. "io"
  7. "log"
  8. "os"
  9. "path"
  10. "github.com/cheggaaa/pb"
  11. "github.com/jackpal/bencode-go"
  12. )
  13. // currently only single file
  14. type torrentFileSpec struct {
  15. Announce string
  16. Info struct {
  17. Name string
  18. Length int
  19. PieceLen int `piece length`
  20. Pieces string
  21. }
  22. }
  23. var tdata torrentFileSpec
  24. func main() {
  25. if len(os.Args) != 3 {
  26. fmt.Fprintf(os.Stderr, "Usage: %s <torrent file> <dir containing files>\n", os.Args[0])
  27. os.Exit(1)
  28. }
  29. // open specified torrent file
  30. tfile, err := os.Open(os.Args[1])
  31. checkErr(err)
  32. defer tfile.Close()
  33. // decode the torrent file
  34. err = bencode.Unmarshal(tfile, &tdata)
  35. checkErr(err)
  36. // print some meta data from the file
  37. fmt.Println("PieceLen: ", tdata.Info.PieceLen)
  38. fmt.Println("Len of Pieces string:", len(tdata.Info.Pieces))
  39. // open the file, the torrent knows about
  40. fname := path.Join(os.Args[2], tdata.Info.Name)
  41. ffile, err := os.Open(fname)
  42. checkErr(err)
  43. defer ffile.Close()
  44. fmt.Println("Checking file:", fname)
  45. finfo, err := os.Stat(fname)
  46. checkErr(err)
  47. bar := pb.New(int(finfo.Size())).SetUnits(pb.U_BYTES)
  48. bar.Start()
  49. // iterate over the Peices string which contains the hash values
  50. for i := 0; i < tdata.Info.PieceLen; i += 20 {
  51. hasher := sha1.New()
  52. n, err := io.CopyN(io.MultiWriter(hasher, bar), ffile, int64(tdata.Info.PieceLen))
  53. // break the for loop if we copied all the bytes from the file
  54. if err == io.EOF {
  55. // TODO:
  56. // should also check the rest that was copied
  57. // last copy could be wrong
  58. break
  59. } else {
  60. checkErr(err)
  61. }
  62. // check if the copied amount was correct
  63. if int(n) != tdata.Info.PieceLen {
  64. fmt.Fprintf(os.Stderr, "Error: .Read() wrote the wrong amount\nn != tdata.Info.PieceLen=> %d != %d\n", n, tdata.Info.PieceLen)
  65. os.Exit(2)
  66. }
  67. // check if the calculated hash is equal to one specified by the torrent file
  68. infoSum := []byte(tdata.Info.Pieces[i : i+20])
  69. thisSum := hasher.Sum(nil)
  70. if bytes.Compare(infoSum, thisSum) != 0 {
  71. log.Fatalf("Error: sum is wrong in pice %d\nInfo: % x\nCalc: % x\n", i/20, infoSum, thisSum)
  72. }
  73. }
  74. bar.FinishPrint("Check complete, no errors!")
  75. os.Exit(0)
  76. }
  77. func checkErr(err error) {
  78. if err != nil {
  79. fmt.Fprintf(os.Stderr, "Errror: %s\n", err)
  80. os.Exit(2)
  81. }
  82. }