diff --git a/filesystem/squashfs/compressor.go b/filesystem/squashfs/compressor.go index 42c0819d..4076a471 100644 --- a/filesystem/squashfs/compressor.go +++ b/filesystem/squashfs/compressor.go @@ -7,6 +7,7 @@ import ( "fmt" "io" + "github.com/klauspost/compress/zstd" "github.com/pierrec/lz4/v4" "github.com/ulikunitz/xz" "github.com/ulikunitz/xz/lzma" @@ -328,6 +329,32 @@ func (c *CompressorZstd) optionsBytes() []byte { func (c *CompressorZstd) flavour() compression { return compressionZstd } +func (c *CompressorZstd) compress(in []byte) ([]byte, error) { + var b bytes.Buffer + z, err := zstd.NewWriter(&b) + if err != nil { + return nil, fmt.Errorf("failed to create zstd compressor: %w", err) + } + if _, err := z.Write(in); err != nil { + return nil, err + } + if err := z.Close(); err != nil { + return nil, err + } + return b.Bytes(), nil +} +func (c *CompressorZstd) decompress(in []byte) ([]byte, error) { + z, err := zstd.NewReader(nil) + if err != nil { + return nil, fmt.Errorf("failed to create zstd decompressor: %w", err) + } + defer z.Close() + p, err := z.DecodeAll(in, nil) + if err != nil { + return nil, fmt.Errorf("error decompressing zstd: %w", err) + } + return p, nil +} func newCompressor(flavour compression) (Compressor, error) { var c Compressor @@ -345,7 +372,7 @@ func newCompressor(flavour compression) (Compressor, error) { case compressionLz4: c = &CompressorLz4{} case compressionZstd: - return nil, fmt.Errorf("zstd compression not yet supported") + c = &CompressorZstd{} default: return nil, fmt.Errorf("unknown compression type: %d", flavour) } diff --git a/filesystem/squashfs/compressor_internal_test.go b/filesystem/squashfs/compressor_internal_test.go index d0a4efe6..136e4e33 100644 --- a/filesystem/squashfs/compressor_internal_test.go +++ b/filesystem/squashfs/compressor_internal_test.go @@ -19,7 +19,7 @@ func TestNewCompressor(t *testing.T) { {compressionLzo, nil, fmt.Errorf("LZO compression not yet supported")}, {compressionXz, &CompressorXz{}, nil}, {compressionLz4, &CompressorLz4{}, nil}, - {compressionZstd, nil, fmt.Errorf("zstd compression not yet supported")}, + {compressionZstd, &CompressorZstd{}, nil}, {100, nil, fmt.Errorf("unknown compression type")}, } @@ -153,3 +153,19 @@ func TestCompressionLz4(t *testing.T) { c := CompressorLz4{} testCompressAndDecompress(t, &c, compressed) } +func TestCompressionZstd(t *testing.T) { + compressed := []byte{ + 0x28, 0xb5, 0x2f, 0xfd, 0x04, 0x00, 0x21, 0x03, 0x00, 0xde, 0xc9, 0x4e, + 0xd0, 0xef, 0x19, 0xdb, 0x0a, 0x6a, 0x35, 0x26, 0x61, 0x86, 0x2d, 0xa0, + 0x42, 0x18, 0xa8, 0x89, 0xe9, 0xc4, 0x7b, 0x1a, 0xc7, 0x85, 0x8e, 0xd6, + 0x36, 0xd6, 0x83, 0x84, 0x21, 0xf4, 0x06, 0x38, 0x07, 0x7b, 0x33, 0x3f, + 0x72, 0x4c, 0xae, 0xcd, 0xfd, 0xa0, 0xb0, 0x71, 0x2f, 0x64, 0x62, 0x62, + 0x2f, 0xc3, 0x5f, 0xa1, 0x21, 0xc6, 0xbf, 0x2c, 0x39, 0xef, 0x56, 0x23, + 0x61, 0xb0, 0x98, 0x84, 0xcd, 0x24, 0xc4, 0xbf, 0x30, 0xae, 0xd9, 0x9e, + 0xb0, 0x7b, 0xc5, 0xa3, 0x8d, 0xf7, 0x4f, 0xb8, 0xdd, 0x7b, 0x77, 0xb6, + 0x8c, 0x5a, 0x10, 0xa4, 0xce, 0xc2, 0x0a, 0x3d, 0x51, 0x23, 0x8c, 0x10, + 0x1a, 0x18, 0x20, 0x19, 0x3b, + } + c := CompressorZstd{} + testCompressAndDecompress(t, &c, compressed) +} diff --git a/filesystem/squashfs/squashfs.go b/filesystem/squashfs/squashfs.go index d67c61ca..ce4cbf2f 100644 --- a/filesystem/squashfs/squashfs.go +++ b/filesystem/squashfs/squashfs.go @@ -147,7 +147,7 @@ func Read(file util.File, size, start, blocksize int64) (*FileSystem, error) { // create the compressor function we will use compress, err := newCompressor(s.compression) if err != nil { - return nil, fmt.Errorf("unable to create compressor") + return nil, fmt.Errorf("unable to create compressor: %v", err) } // load fragments diff --git a/go.mod b/go.mod index b77b8b33..b2a0a59d 100644 --- a/go.mod +++ b/go.mod @@ -13,3 +13,5 @@ require ( golang.org/x/sys v0.5.0 gopkg.in/djherbis/times.v1 v1.3.0 ) + +require github.com/klauspost/compress v1.17.4 // indirect diff --git a/go.sum b/go.sum index 553f78d3..2b4e172b 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=