CompressStream had both a defer w.Close() and an explicit w.Close() call, causing the compressor and encryptor to be closed twice. The second close on the zstd encoder returns an error, and the age encryptor may write duplicate finalization bytes, potentially corrupting the output stream. Use a closed flag to prevent the deferred close from running after the explicit close succeeds.
75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package blobgen
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// CompressResult contains the results of compression
|
|
type CompressResult struct {
|
|
Data []byte
|
|
UncompressedSize int64
|
|
CompressedSize int64
|
|
SHA256 string
|
|
}
|
|
|
|
// CompressData compresses and encrypts data, returning the result with hash
|
|
func CompressData(data []byte, compressionLevel int, recipients []string) (*CompressResult, error) {
|
|
var buf bytes.Buffer
|
|
|
|
// Create writer
|
|
w, err := NewWriter(&buf, compressionLevel, recipients)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating writer: %w", err)
|
|
}
|
|
|
|
// Write data
|
|
if _, err := w.Write(data); err != nil {
|
|
_ = w.Close()
|
|
return nil, fmt.Errorf("writing data: %w", err)
|
|
}
|
|
|
|
// Close to flush
|
|
if err := w.Close(); err != nil {
|
|
return nil, fmt.Errorf("closing writer: %w", err)
|
|
}
|
|
|
|
return &CompressResult{
|
|
Data: buf.Bytes(),
|
|
UncompressedSize: int64(len(data)),
|
|
CompressedSize: int64(buf.Len()),
|
|
SHA256: hex.EncodeToString(w.Sum256()),
|
|
}, nil
|
|
}
|
|
|
|
// CompressStream compresses and encrypts from reader to writer, returning hash
|
|
func CompressStream(dst io.Writer, src io.Reader, compressionLevel int, recipients []string) (written int64, hash string, err error) {
|
|
// Create writer
|
|
w, err := NewWriter(dst, compressionLevel, recipients)
|
|
if err != nil {
|
|
return 0, "", fmt.Errorf("creating writer: %w", err)
|
|
}
|
|
|
|
closed := false
|
|
defer func() {
|
|
if !closed {
|
|
_ = w.Close()
|
|
}
|
|
}()
|
|
|
|
// Copy data
|
|
if _, err := io.Copy(w, src); err != nil {
|
|
return 0, "", fmt.Errorf("copying data: %w", err)
|
|
}
|
|
|
|
// Close to flush
|
|
if err := w.Close(); err != nil {
|
|
return 0, "", fmt.Errorf("closing writer: %w", err)
|
|
}
|
|
closed = true
|
|
|
|
return w.BytesWritten(), hex.EncodeToString(w.Sum256()), nil
|
|
}
|