Skip to content

Commit

Permalink
Replace github.com/pierrec/lz4 library with lz4 cli wrapper
Browse files Browse the repository at this point in the history
github.com/pierrec/lz4 has numerous problems with its legacy writer
(e.g. pierrec/lz4#156) that prevents it using
for initramfs compression.

Replace it with a cli tool ('lz4') wrapper.

Fixes #117
  • Loading branch information
anatol committed Mar 8, 2022
1 parent 02afc85 commit fe41972
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 14 deletions.
1 change: 0 additions & 1 deletion generator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ require (
github.com/google/renameio v1.0.1
github.com/jessevdk/go-flags v1.5.0
github.com/klauspost/compress v1.14.3
github.com/pierrec/lz4/v4 v4.1.15-0.20220212190856-bc1239ba9073
github.com/stretchr/testify v1.7.0
github.com/ulikunitz/xz v0.5.10
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
Expand Down
2 changes: 0 additions & 2 deletions generator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LF
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/klauspost/compress v1.14.3 h1:DQv1WP+iS4srNjibdnHtqu8JNWCDMluj5NzPnFJsnvk=
github.com/klauspost/compress v1.14.3/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/pierrec/lz4/v4 v4.1.15-0.20220212190856-bc1239ba9073 h1:ttbN8g6bKEufjaBwMwqPs4txLXxV3njCrpWkGT8f7CY=
github.com/pierrec/lz4/v4 v4.1.15-0.20220212190856-bc1239ba9073/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
7 changes: 1 addition & 6 deletions generator/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/cavaliercoder/go-cpio"
"github.com/google/renameio"
"github.com/klauspost/compress/zstd"
"github.com/pierrec/lz4/v4"
"github.com/ulikunitz/xz"
)

Expand Down Expand Up @@ -52,11 +51,7 @@ func NewImage(path string, compression string, stripBinaries bool) (*Image, erro
}
compressor, err = conf.NewWriter(file)
case "lz4":
writer := lz4.NewWriter(file)
if err := writer.Apply(lz4.LegacyOption(true)); err != nil {
return nil, err
}
compressor = writer
compressor, err = newLz4Writer(file, true)
case "none":
compressor = file
default:
Expand Down
3 changes: 1 addition & 2 deletions generator/kmod.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"sync"

"github.com/klauspost/compress/zstd"
"github.com/pierrec/lz4/v4"
"github.com/xi2/xz" // github.com/xi2/xz is faster so we use it here https://github.com/ulikunitz/xz/issues/23
)

Expand Down Expand Up @@ -300,7 +299,7 @@ func (k *Kmod) addModulesToImage(img *Image) error {
case ".zst":
r, err = zstd.NewReader(f)
case ".lz4":
r = lz4.NewReader(f)
r, err = newLz4Reader(f)
case ".gz":
r, err = gzip.NewReader(f)
default:
Expand Down
21 changes: 21 additions & 0 deletions generator/lz4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"io"
)

// lz4 compressor/decompressor library, wrapper over command-line 'lz4' tool

func newLz4Reader(r io.Reader) (io.ReadCloser, error) {
return newPipeCommandReader(r, "lz4", "-d", "-c", "-")
}

func newLz4Writer(w io.Writer, legacy bool) (io.WriteCloser, error) {
args := []string{"-z", "-c"}
if legacy {
args = append(args, "-l")
}
args = append(args, "-")

return newPipeCommandWriter(w, "lz4", args...)
}
31 changes: 31 additions & 0 deletions generator/lz4_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"bytes"
"io"
"testing"

"github.com/stretchr/testify/require"
)

func TestLz4Writer(t *testing.T) {
w := bytes.NewBuffer(nil)
c, err := newLz4Writer(w, true)
require.NoError(t, err)
_, err = c.Write([]byte("hello"))
require.NoError(t, err)
c.Close()

require.Equal(t, []byte("\x02!L\x18\x06\x00\x00\x00Phello"), w.Bytes())
}

func TestLz4Reader(t *testing.T) {
r := bytes.NewBuffer([]byte("\x02!L\x18\x06\x00\x00\x00Phello"))
c, err := newLz4Reader(r)
require.NoError(t, err)
plain, err := io.ReadAll(c)
require.NoError(t, err)
c.Close()

require.Equal(t, "hello", string(plain))
}
71 changes: 71 additions & 0 deletions generator/pipecommand.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

// utility class that helps to wrap a command line tool into a pipe-like structure

import (
"io"
"os/exec"
)

type pipeCommandReader struct {
cmd *exec.Cmd
pipe io.ReadCloser
}

func (r pipeCommandReader) Read(p []byte) (n int, err error) {
return r.pipe.Read(p)
}

func (r pipeCommandReader) Close() error {
_ = r.pipe.Close()
return r.cmd.Wait()
}

// newPipeCommandReader creates a new pipe command
// r becomes STDIN for the command
// the function returns a reader that contains information from the command STDOUT
func newPipeCommandReader(r io.Reader, app string, args ...string) (io.ReadCloser, error) {
cmd := exec.Command(app, args...)
cmd.Stdin = r
pipe, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}

return pipeCommandReader{cmd, pipe}, nil
}

type pipeCommandWriter struct {
cmd *exec.Cmd
pipe io.WriteCloser
}

func (w pipeCommandWriter) Write(p []byte) (n int, err error) {
return w.pipe.Write(p)
}

func (w pipeCommandWriter) Close() error {
_ = w.pipe.Close()
return w.cmd.Wait()
}

// newPipeCommandWriter creates a new pipe command
// w becomes STDOUT for the command
// the function returns a writer that becomes STDIN for the command
func newPipeCommandWriter(w io.Writer, app string, args ...string) (io.WriteCloser, error) {
cmd := exec.Command(app, args...)
cmd.Stdout = w
pipe, err := cmd.StdinPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}

return pipeCommandWriter{cmd, pipe}, nil

}
6 changes: 3 additions & 3 deletions generator/unpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/cavaliercoder/go-cpio"
"github.com/klauspost/compress/zstd"
"github.com/pierrec/lz4/v4"
"github.com/ulikunitz/xz"
)

Expand Down Expand Up @@ -58,10 +57,11 @@ func processImage(file string, fn processCpioEntryFn) error {
}
img = cpio.NewReader(x)
case "lz4":
lz := lz4.NewReader(input)
if err := lz.Apply(lz4.LegacyOption(true)); err != nil {
lz, err := newLz4Reader(input)
if err != nil {
return err
}
defer lz.Close()
img = cpio.NewReader(lz)
}

Expand Down

0 comments on commit fe41972

Please sign in to comment.