package main import ( "crypto/sha256" "encoding/hex" "encoding/json" "flag" "fmt" "io" "io/ioutil" "log" "os" "path/filepath" "runtime" "sync" ) type Fdhashes struct { Path string Hashes map[string]string } var hashes map[string]Fdhashes var wg sync.WaitGroup var mu sync.RWMutex func main() { runtime.GOMAXPROCS(5) hashes = make(map[string]Fdhashes) flag.Parse() myFile := flag.Arg(0) file, err := os.Stat(myFile) if os.IsNotExist(err) { log.Fatalln("File does not exists:", myFile) } if file.IsDir() { log.Println("start with folder:", myFile) processFolder(myFile) } else { log.Printf("file %s has hash %s\n", myFile, getHash(myFile)) } fmt.Println("waiting") wg.Wait() log.Println("done") } func getHash(fileStr string) string { f, err := os.Open(fileStr) if err != nil { log.Fatal(err) } defer f.Close() h := sha256.New() if _, err := io.Copy(h, f); err != nil { log.Fatal(err) } return hex.EncodeToString(h.Sum(nil)) } func outputHash(fileStr string) { var hashFile Fdhashes doHash := true defer wg.Done() fmt.Print(".") dir, fileName := filepath.Split(fileStr) if fileName == ".fdhashes3" { return } mu.Lock() hashFile, ok := hashes[dir] if !ok { _, err := os.Stat(dir + ".fdhashes3") if os.IsNotExist(err) { hashFile = Fdhashes{Path: dir, Hashes: make(map[string]string)} } else { hashFile = loadHashfile(dir + ".fdhashes3") } hashes[dir] = hashFile saveHashfile(hashFile) } _, ok = hashFile.Hashes[fileName] doHash = !ok hashFile = hashes[dir] mu.Unlock() if doHash { hash := getHash(fileStr) mu.Lock() hashFile.Hashes[fileName] = hash saveHashfile(hashFile) mu.Unlock() log.Printf("file %s has hash %s\n", fileStr, hash) } } func processFolder(folder string) { err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { wg.Add(1) go outputHash(path) } return nil }) if err != nil { panic(err) } } func saveHashfile(hashFile Fdhashes) { b, err := json.Marshal(hashFile) if err != nil { fmt.Println(err) return } err = ioutil.WriteFile(hashFile.Path+".fdhashes3", b, 0644) if err != nil { panic(err) } } func loadHashfile(filename string) Fdhashes { file, err := ioutil.ReadFile(filename) if err != nil { panic(err) } data := Fdhashes{} err = json.Unmarshal([]byte(file), &data) if err != nil { panic(err) } return data }