-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhasher.go
104 lines (88 loc) · 2.62 KB
/
hasher.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
package slicesync
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
const (
SLICEHASH_SIZE = 20
)
// NamedHash is a hash.Hash with a name
type NamedHash interface {
hash.Hash
Name() string
}
// simpleHash implements the namedHash for a single hash.Hash
type simpleHash struct {
hash.Hash
name string
}
// RollingHash can roll or scroll the hash window
type RollingHash interface {
hash.Hash
Roll(window uint32, oldbyte, newbyte byte) []byte
}
// RollingHash32 is a rollingHash that produces 32bit hashes
type RollingHash32 interface {
hash.Hash32
Roll(window uint32, oldbyte, newbyte byte) []byte
Roll32(window uint32, oldbyte, newbyte byte) uint32
}
// Name is the name of this namedHash
func (sh *simpleHash) Name() string {
return sh.name
}
// Complex hash implements hash.Hash composed of a 32bit rolling hash and strong Hash
type complexHash struct {
rolling RollingHash32
strong hash.Hash
name string
}
// Write for complexHash's io.Writer implementation
func (ch *complexHash) Write(p []byte) (n int, err error) {
n, err = ch.rolling.Write(p)
if err != nil {
return
}
return ch.strong.Write(p)
}
// Sum for complexHash's hash.Hash implementation:
// Appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
func (ch *complexHash) Sum(b []byte) []byte {
sum := ch.rolling.Sum(b)
return append(sum, ch.strong.Sum(b)...)
}
// Reset for complexHash's hash.Hash implementation:
// Resets the hash to one with zero bytes written.
func (ch *complexHash) Reset() {
ch.rolling.Reset()
ch.strong.Reset()
}
// Size for complexHash's hash.Hash implementation:
// Returns the number of bytes Sum will return.
func (ch *complexHash) Size() int {
return ch.rolling.Size() + ch.strong.Size()
}
// BlockSize for complexHash's hash.Hash implementation:
// Returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all writes
// are a multiple of the block size.
// (complexHash returns the string hash blocksize as it is the more cpu intensive one)
func (ch *complexHash) BlockSize() int {
return ch.strong.BlockSize()
}
// Name is the name of this namedHash
func (ch *complexHash) Name() string {
return ch.name
}
// newHasher returns a Hash implementation for the whole file (usually SHA1)
func NewHasher() NamedHash {
return &simpleHash{sha1.New(), "sha1"}
}
// newSliceHasher returns a Hash implementation for each slice
// (SHA1 on naive implementation or rolling+hash in rsync's symulation)
func NewSliceHasher() NamedHash {
return &complexHash{NewRollingAdler32(), md5.New(), "adler32+md5"}
}