-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhash.go
More file actions
117 lines (105 loc) · 2.16 KB
/
hash.go
File metadata and controls
117 lines (105 loc) · 2.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package main
import (
"fmt"
"golang.org/x/sync/errgroup"
"io"
"log"
"os"
)
func hashF(f io.ReadCloser, checksums []*Checksum) ([]*Checksum, Size) {
if checksums == nil {
checksums = make([]*Checksum, len(chosen))
for i, h := range chosen {
checksums[i] = &Checksum{hash: h}
}
}
if len(checksums) == 1 {
h := checksums[0]
initHash(h)
n, err := io.Copy(h, f)
if err != nil {
log.Print(err)
return nil, 0
}
h.sum = h.Sum(nil)
return checksums, Size(n)
}
writers := make([]io.Writer, len(checksums))
pipeWriters := make([]*io.PipeWriter, len(checksums))
g := new(errgroup.Group)
for i, h := range checksums {
initHash(h)
pr, pw := io.Pipe()
writers[i] = pw
pipeWriters[i] = pw
g.Go(func() error {
defer pr.Close()
if _, err := io.Copy(h, pr); err != nil {
return err
}
h.sum = h.Sum(nil)
return nil
})
}
var size Size
g.Go(func() error {
defer func() {
for _, pw := range pipeWriters {
pw.Close()
}
}()
// build the multiwriter for all the pipes
mw := io.MultiWriter(writers...)
// copy the data into the multiwriter
n, err := io.Copy(mw, f)
size = Size(n)
return err
})
if err := g.Wait(); err != nil {
log.Print(err)
return nil, 0
}
return checksums, size
}
func hashFile(file string, checksums []*Checksum) (*Checksums, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return nil, err
}
if info.IsDir() {
return nil, fmt.Errorf("%s is a directory", file)
}
checksums, size := hashF(f, checksums)
return &Checksums{
file: file,
size: size,
checksums: checksums,
}, nil
}
func hashStdin() *Checksums {
checksums, size := hashF(os.Stdin, nil)
return &Checksums{
file: "",
size: size,
checksums: checksums,
}
}
func hashString(str string) *Checksums {
checksums := make([]*Checksum, len(chosen))
for i, h := range chosen {
checksums[i] = &Checksum{hash: h}
initHash(checksums[i])
checksums[i].Write([]byte(str))
checksums[i].sum = checksums[i].Sum(nil)
}
return &Checksums{
file: `"` + str + `"`,
size: Size(len(str)),
checksums: checksums,
}
}