/
library-compare.go
149 lines (121 loc) · 4.1 KB
/
library-compare.go
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package hashsum
import(
"bufio"
"bytes"
"github.com/ProhtMeyhet/libgosimpleton/iotool"
"github.com/ProhtMeyhet/libgosimpleton/parallel"
"github.com/ProhtMeyhet/gonixutils/library/abstract"
)
func Compare(input *Input) (exitCode uint8) {
work := parallel.NewStringsFeeder(input.PathList...)
output := abstract.NewOutput(input.Stdout, input.Stderr)
// TODO
// if input.OrderedOutput {
// exitCode = compareOrdered(work, output)
// } else {
exitCode = compare(input, output, work)
// }
output.Done(); output.Wait()
return
}
func compare(input *Input, output abstract.OutputInterface, work *parallel.WorkString) (exitCode uint8) {
work.Start(func() {
exitCode = compare1(input, output, work.Talk)
})
work.Wait()
return
}
func compare1(input *Input, output abstract.OutputInterface, list chan string) (exitCode uint8) {
if !input.Type.Valid() { return abstract.ERROR_INVALID_ARGUMENT }
notFound, unequalHashes, wrongHashFunction, hashlen, expectedHashLen := 0, 0, uint(0), 0, input.Type.Len()
reader, helper := &bufio.Reader{}, prepareFileHelper(input, output, &exitCode)
work := parallel.NewWork(0); talk := make(chan HashPath, work.SuggestBufferSize(0))
// parse input file and send result via talk
work.Feed(func() {
for path := range list {
handler, e := iotool.Open(helper, path); if e != nil { continue }
reader.Reset(handler); scanner := bufio.NewScanner(reader)
scanner.Split(bufio.ScanWords); hashPath := HashPath{}
for i := 1; scanner.Scan(); i++ {
if i % 2 != 0 {
hashPath.Hash = scanner.Bytes()
} else {
hashPath.Path = scanner.Bytes()
if uint(len(hashPath.Hash)) != expectedHashLen {
// no lock required (yet)
wrongHashFunction++
output.WriteError("%s, wrong hash function!\n", hashPath.Path)
// give up
if wrongHashFunction == input.Idiot {
output.WriteError("file %s is probably not valid. giving up!\n", path)
exitCode = ERROR_INVALID_FILE_FORMAT
break
}
} else {
talk <-hashPath
}
}
}
}; close(talk)
})
// read from talk, hash file and compare
work.Start(func() {
hash1List := make(chan string, work.SuggestBufferSize(0))
in := bytes.NewBuffer(make([]byte, 0)); buffered := abstract.NewOutput(in, input.Stderr)
iwork := parallel.NewWork(work.Workers()); hashPaths := make(map[string]HashPath)
iwork.Feed(func() {
for hashPath := range talk {
hash1List <-string(hashPath.Path)
hashPaths[string(hashPath.Path)] = hashPath
hashlen = len(hashPath.Hash)
}; close(hash1List)
})
iwork.Start(func() {
Hash(input, buffered, helper, input.Type.Factory(input), hash1List)
})
// since the output is unordered, wait until everything is finished before comparing
// comparing is very quick, even with many files, as it's still only a few bytes
iwork.Wait(); buffered.Done(); buffered.Wait()
hash, path := make([]byte, 0), ""
scanner := bufio.NewScanner(in); scanner.Split(bufio.ScanWords)
for i := 1; scanner.Scan(); i++ {
if i % 2 != 0 {
hash = scanner.Bytes()
} else {
path = scanner.Text()
// the if only guards nil panics
if value, ok := hashPaths[path]; ok {
if !bytes.Equal(hash, value.Hash) {
output.WriteError("%s: FAILED!\n", path)
work.Lock(); unequalHashes++; work.Unlock()
} else if !input.Quiet {
output.WriteFormatted("%s: OK\n", path)
}
delete(hashPaths, path)
}
}
}
if len(hashPaths) > 0 {
exitCode = abstract.FAILED
work.Lock(); notFound += len(hashPaths); work.Unlock()
for path, _ := range hashPaths {
output.WriteError("%s: FAILED! file not found.\n", path)
}
}
})
work.Wait()
if wrongHashFunction > 0 {
output.WriteError(`hashsum: WARNING: on %v listed file(s) the hash size was unexpected! ` +
`probably wrong hash function!` + "\n", wrongHashFunction)
}
if notFound > 0 {
output.WriteError("hashsum: WARNING: %v listed file(s) could not be read or not found!\n", notFound)
}
if unequalHashes > 0 {
output.WriteError("hashsum: WARNING: %v computed checksum(s) did NOT match!\n", unequalHashes)
}
return
}
type HashPath struct {
Hash, Path []byte
}