dedupe-linker/file/hash.go

79 lines
1.8 KiB
Go
Raw Permalink Normal View History

2014-09-12 20:10:10 +00:00
package file
import (
"crypto"
"fmt"
"io"
"os"
"path/filepath"
"strings"
2014-09-12 20:10:10 +00:00
"time"
)
// HashInfo for tracking the information regarding a file, it's checksum
// and status.
// If Err is set then the caller must take an appropriate action.
type HashInfo struct {
2014-09-12 20:10:10 +00:00
HashType crypto.Hash
Hash string
Path string
2014-10-14 20:54:28 +00:00
Size int64
2014-09-12 20:10:10 +00:00
ModTime time.Time
Err error
}
// HashFileGetter walks the provided `path` with `workers` number of threads.
// The channel of HashInfo are for each regular file encountered.
func HashFileGetter(path string, hash crypto.Hash, ignoreSuffixes []string, workers int, done <-chan struct{}) <-chan HashInfo {
out := make(chan HashInfo, workers)
2014-09-12 20:10:10 +00:00
go func() {
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
for _, suff := range ignoreSuffixes {
if strings.HasSuffix(filepath.Clean(path), filepath.Clean(suff)) {
if os.Getenv("DEBUG") != "" {
fmt.Printf("[DEBUG] skipping dir %q; has suff: %q\n", filepath.Clean(path), filepath.Clean(suff))
}
return filepath.SkipDir
}
}
2014-09-12 20:10:10 +00:00
if !info.Mode().IsRegular() {
return nil
}
fhi := hashFile(path, hash, info)
out <- *fhi
2014-09-12 20:10:10 +00:00
select {
case <-done:
return fmt.Errorf("walk canceled")
default:
return nil
}
})
if err != nil {
out <- HashInfo{Err: err}
2014-09-12 20:10:10 +00:00
}
close(out)
2014-09-12 20:10:10 +00:00
}()
return out
}
func hashFile(path string, hash crypto.Hash, info os.FileInfo) *HashInfo {
fhi := HashInfo{HashType: hash, Path: path, ModTime: info.ModTime(), Size: info.Size()}
2014-09-12 20:10:10 +00:00
h := hash.New()
fh, err := os.Open(path)
if err != nil {
fhi.Err = err
return &fhi
}
if _, err = io.Copy(h, fh); err != nil {
fhi.Err = err
2014-10-14 21:07:13 +00:00
fh.Close()
2014-09-12 20:10:10 +00:00
return &fhi
}
fh.Close()
fhi.Hash = fmt.Sprintf("%x", h.Sum(nil))
return &fhi
}