-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhash_parts.go
136 lines (108 loc) · 3.28 KB
/
hash_parts.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
package main
import (
"hash"
)
// HashPart represents the hash of a single part in a multi-part object.
type HashPart struct {
// total number of bytes written to this HashPart
n int64
// hash algorithm implementation for this HashPart
h hash.Hash
}
// Sum returns the full-body HashSum using the configure checksum algorithm.
func (hp *HashPart) Sum() HashSum {
return HashSum(hp.h.Sum(nil))
}
// HashParts represents the parts in a multi-part object.
type HashParts struct {
// maximum number of bytes per part
partSize int64
// checksum algorithm identifier
checksumAlgorithm *ChecksumAlgorithm
// hash.Hash generator factory
hasher Hasher
// current hash part
p *HashPart
// previous and current HashPart in the order that they were created
h []*HashPart
}
// NewHashParts initializes a new HashParts using the specified checksum
// algorithm and a maximum part size in bytes.
func NewHashParts(checksumAlgorithm *ChecksumAlgorithm, partSize int64) *HashParts {
return &HashParts{
partSize: partSize,
checksumAlgorithm: checksumAlgorithm,
hasher: NewHasher(checksumAlgorithm),
}
}
// ChecksumAlgorithm returns the checksum algorithm configured for this
// HashParts.
func (hp *HashParts) ChecksumAlgorithm() *ChecksumAlgorithm {
return hp.checksumAlgorithm
}
// Count returns the number of parts hashed so far (including the current one).
func (hp *HashParts) Count() int {
return len(hp.h)
}
// PartSize returns the number of bytes used for part partID. Valid values for
// partID are 1 >= partID <= HashParts.Count().
func (hp *HashParts) PartSize(partID int32) int64 {
return hp.h[int(partID)-1].n
}
// Sum returns the HashSum for partID using the configured checksum algorithm.
// Valid values for partID are 1 >= partID <= HashParts.Count().
func (hp *HashParts) Sum(partID int32) HashSum {
return HashSum(hp.h[int(partID)-1].h.Sum(nil))
}
// SumOfSums returns the hash-of-hashes HashSum for the current parts using the
// configured checksum algorithm.
func (hp *HashParts) SumOfSums() HashSum {
hoh := hp.hasher()
for i := 0; i < len(hp.h); i++ {
hoh.Write(hp.h[i].h.Sum(nil))
}
return HashSum(hoh.Sum(nil))
}
// Write adds more data to the running hashes, appending a new HashPart each
// time partSize bytes are written to the current part. It never returns an
// error.
func (hp *HashParts) Write(buf []byte) (int, error) {
// if hp.p is not set, allocate a new HashPart and add its hash to the
// hp.h slice
if hp.p == nil {
hp.p = &HashPart{
n: 0,
h: hp.hasher(),
}
hp.h = append(hp.h, hp.p)
}
nbuf := len(buf)
for len(buf) > 0 {
// if hp.p was reset to nil after the last write, allocate a
// new HashPart and add its hash to the hp.h slice
if hp.p == nil {
hp.p = &HashPart{
n: 0,
h: hp.hasher(),
}
hp.h = append(hp.h, hp.p)
}
// set n to the number of bytes from buf to write to the
// current hash
n := int64(len(buf))
if hp.p.n+n > hp.partSize {
// reduce n to the remaining bytes available to write
// for this part
n = hp.partSize - hp.p.n
}
hp.p.h.Write(buf[0:n])
// record bytes written
hp.p.n, buf = (hp.p.n + n), buf[n:]
// if we've reached hp.partSize bytes written, reset hp.p for
// the next iteration
if hp.p.n == hp.partSize {
hp.p = nil
}
}
return nbuf, nil
}