GoHash.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package main
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "log"
  10. "os"
  11. "path/filepath"
  12. "runtime"
  13. "sync"
  14. "time"
  15. flag "github.com/spf13/pflag"
  16. )
  17. // Fdhashes struct for holding all informations about one folder.
  18. type Fdhashes struct {
  19. Path string
  20. Hashes map[string]string
  21. Times map[string]time.Time
  22. }
  23. var hashes map[string]Fdhashes
  24. var wg sync.WaitGroup
  25. var mu sync.RWMutex
  26. var driveLetter string
  27. var rewrite bool
  28. func init() {
  29. flag.BoolVarP(&rewrite, "rewrite", "r", false, "rewrite all fhhashes files.")
  30. }
  31. func main() {
  32. log.Println("starting GoHash")
  33. runtime.GOMAXPROCS(5)
  34. hashes = make(map[string]Fdhashes)
  35. flag.Parse()
  36. myFile := flag.Arg(0)
  37. file, err := os.Stat(myFile)
  38. if os.IsNotExist(err) {
  39. log.Fatalln("File does not exists:", myFile)
  40. }
  41. if file.IsDir() {
  42. log.Println("start with folder:", myFile)
  43. driveLetter = ""
  44. if runtime.GOOS == "windows" {
  45. driveLetter = filepath.VolumeName(myFile) + "/"
  46. }
  47. processFolder(myFile)
  48. } else {
  49. log.Printf("file %s has hash %s\n", myFile, getSha256Hash(myFile))
  50. }
  51. fmt.Println("waiting")
  52. wg.Wait()
  53. log.Println("done")
  54. }
  55. func getSha256Hash(fileStr string) string {
  56. f, err := os.Open(fileStr)
  57. if err != nil {
  58. log.Fatal(err)
  59. }
  60. defer f.Close()
  61. h := sha256.New()
  62. if _, err := io.Copy(h, f); err != nil {
  63. log.Fatal(err)
  64. }
  65. return hex.EncodeToString(h.Sum(nil))
  66. }
  67. func outputHash(fileStr string) {
  68. var hashFile Fdhashes
  69. doHash := true
  70. defer wg.Done()
  71. dir, fileName := filepath.Split(fileStr)
  72. if fileName == ".fdhashes3" {
  73. return
  74. }
  75. // checking if hash is present
  76. mu.Lock()
  77. hashFile, ok := hashes[dir]
  78. if !ok {
  79. _, err := os.Stat(dir + ".fdhashes3")
  80. if os.IsNotExist(err) {
  81. hashFile = Fdhashes{Path: dir, Hashes: make(map[string]string), Times: make(map[string]time.Time)}
  82. } else {
  83. hashFile = loadHashfile(dir + ".fdhashes3")
  84. }
  85. hashes[dir] = hashFile
  86. saveHashfile(hashFile)
  87. }
  88. _, ok = hashFile.Hashes[fileName]
  89. mu.Unlock()
  90. doHash = !ok
  91. // checking if dattime is identically
  92. file, _ := os.Stat(fileStr)
  93. time := file.ModTime()
  94. savedTime, ok := hashFile.Times[fileName]
  95. if !time.Equal(savedTime) || !ok {
  96. doHash = true
  97. }
  98. if doHash {
  99. hash := getSha256Hash(fileStr)
  100. mu.Lock()
  101. hashFile.Hashes[fileName] = hash
  102. hashFile.Times[fileName] = time
  103. hashes[dir] = hashFile
  104. saveHashfile(hashFile)
  105. mu.Unlock()
  106. log.Printf("file \"%s\" has hash \"%s\"\n", fileStr, hash)
  107. }
  108. }
  109. var count int
  110. var addWork int
  111. func processFolder(folder string) {
  112. count = 0
  113. addWork = 0
  114. err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
  115. count++
  116. if (count % 100) == 0 {
  117. fmt.Print(".")
  118. }
  119. if (count % 10000) == 0 {
  120. fmt.Println()
  121. }
  122. filename := info.Name()
  123. if filename[0:1] != "." {
  124. if info.IsDir() {
  125. fmt.Println(path)
  126. }
  127. if !info.IsDir() {
  128. addWork++
  129. wg.Add(1)
  130. go outputHash(path)
  131. if addWork > 100 {
  132. fmt.Println("x")
  133. wg.Wait()
  134. addWork = 0
  135. }
  136. }
  137. }
  138. return nil
  139. })
  140. if err != nil {
  141. panic(err)
  142. }
  143. }
  144. func saveHashfile(hashFile Fdhashes) {
  145. b, err := json.Marshal(hashFile)
  146. if err != nil {
  147. fmt.Println(err)
  148. return
  149. }
  150. err = ioutil.WriteFile(hashFile.Path+".fdhashes3", b, 0644)
  151. if err != nil {
  152. panic(err)
  153. }
  154. }
  155. func loadHashfile(fileStr string) Fdhashes {
  156. dir, _ := filepath.Split(fileStr)
  157. data := Fdhashes{Path: dir, Hashes: make(map[string]string), Times: make(map[string]time.Time)}
  158. if !rewrite {
  159. file, err := ioutil.ReadFile(fileStr)
  160. if err != nil {
  161. panic(err)
  162. }
  163. err = json.Unmarshal([]byte(file), &data)
  164. if err != nil {
  165. log.Printf("can't read file %s", fileStr)
  166. }
  167. }
  168. if data.Path == "" {
  169. data.Path = dir
  170. }
  171. return data
  172. }