GoHash.go 4.4 KB

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