| 93 | } |
| 94 | |
| 95 | func (b *DataBuilder) Complete() ([]byte, error) { |
| 96 | b.mu.Lock() |
| 97 | defer b.mu.Unlock() |
| 98 | |
| 99 | if !b.done() { |
| 100 | return nil, xerrors.Errorf("data upload is not complete, expected %d chunks, got %d", b.ChunkCount, b.chunkIndex) |
| 101 | } |
| 102 | |
| 103 | if len(b.data) != int(b.Size) { |
| 104 | return nil, xerrors.Errorf("data size mismatch, expected %d bytes, got %d bytes", b.Size, len(b.data)) |
| 105 | } |
| 106 | |
| 107 | hash := sha256.Sum256(b.data) |
| 108 | if !bytes.Equal(hash[:], b.Hash) { |
| 109 | return nil, xerrors.Errorf("data hash mismatch, expected %x, got %x", b.Hash, hash[:]) |
| 110 | } |
| 111 | |
| 112 | // A safe method would be to return a copy of the data, but that would have to |
| 113 | // allocate double the memory. Just return the original slice, and let the caller |
| 114 | // handle the memory management. |
| 115 | return b.data, nil |
| 116 | } |
| 117 | |
| 118 | func (b *DataBuilder) done() bool { |
| 119 | return b.chunkIndex >= b.ChunkCount |