106 lines
2.1 KiB
Go
106 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/hex"
|
|
"flag"
|
|
"fmt"
|
|
"github.com/minio/md5-simd"
|
|
"github.com/minio/sha256-simd"
|
|
"io"
|
|
"math"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type HashFileResult struct {
|
|
error error
|
|
path string
|
|
sha256 string
|
|
md5 string
|
|
}
|
|
|
|
func HashFile(results chan<- HashFileResult, jobs chan string, path string, md5server *md5simd.Server, taskCount *int64) {
|
|
defer atomic.AddInt64(taskCount, -1)
|
|
fh, err := os.Open(path)
|
|
if err != nil {
|
|
results <- HashFileResult{
|
|
error: err,
|
|
path: path,
|
|
}
|
|
<-jobs
|
|
return
|
|
}
|
|
defer fh.Close()
|
|
|
|
sha256sum := sha256.New()
|
|
md5sum := (*md5server).NewHash()
|
|
defer md5sum.Close()
|
|
|
|
io.Copy(io.MultiWriter(sha256sum, md5sum), fh)
|
|
|
|
results <- HashFileResult{
|
|
error: nil,
|
|
path: path,
|
|
sha256: hex.EncodeToString(sha256sum.Sum(nil)),
|
|
md5: hex.EncodeToString(md5sum.Sum(nil)),
|
|
}
|
|
|
|
<-jobs
|
|
}
|
|
|
|
func PrintHashFileResult(result *HashFileResult) {
|
|
if result.error != nil {
|
|
fmt.Fprintln(os.Stderr, result.path, "error: ", result.error)
|
|
} else {
|
|
fmt.Println(result.sha256, result.md5, result.path)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
taskLimit := flag.Int("tasklimit", int(math.Ceil(float64(runtime.NumCPU())*1.5)), "Maximum number of concurrent hashing tasks. Change to avoid fdlimit issues. Defaults to number of CPU cores * 1.5")
|
|
|
|
flag.Parse()
|
|
|
|
var taskCount int64
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
defer os.Stdin.Close()
|
|
|
|
md5server := md5simd.NewServer()
|
|
defer md5server.Close()
|
|
|
|
resultChannel := make(chan HashFileResult)
|
|
|
|
jobs := make(chan string, *taskLimit)
|
|
|
|
atomic.AddInt64(&taskCount, 1)
|
|
go func() {
|
|
defer atomic.AddInt64(&taskCount, -1)
|
|
for scanner.Scan() {
|
|
text := scanner.Text()
|
|
|
|
path := strings.TrimRight(text, "\n\r")
|
|
|
|
jobs <- path
|
|
atomic.AddInt64(&taskCount, 1)
|
|
go HashFile(resultChannel, jobs, path, &md5server, &taskCount)
|
|
}
|
|
|
|
}()
|
|
|
|
//Already print before finishing, use atomic ints instead of a WaitGroup
|
|
for atomic.LoadInt64(&taskCount) > 0 {
|
|
result := <-resultChannel
|
|
PrintHashFileResult(&result)
|
|
}
|
|
|
|
close(resultChannel)
|
|
|
|
for result := range resultChannel {
|
|
PrintHashFileResult(&result)
|
|
}
|
|
}
|