github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/bzimage/bzimage_decompress.go (about) 1 // Copyright 2022 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bzimage 6 7 import ( 8 "bytes" 9 "compress/bzip2" 10 "compress/gzip" 11 "fmt" 12 "io" 13 "os/exec" 14 15 "github.com/klauspost/compress/zstd" 16 "github.com/pierrec/lz4/v4" 17 "github.com/ulikunitz/xz/lzma" 18 ) 19 20 // stripSize returns a decompressor which strips off the last 4 bytes of the 21 // data from the reader and copies the bytes to the writer. 22 func stripSize(d decompressor) decompressor { 23 return func(w io.Writer, r io.Reader) error { 24 // Read all of the bytes so that we can determine the size. 25 allBytes, err := io.ReadAll(r) 26 if err != nil { 27 return fmt.Errorf("error reading all bytes: %v", err) 28 } 29 strippedLen := int64(len(allBytes) - 4) 30 Debug("Stripped reader is of length %d bytes", strippedLen) 31 32 reader := bytes.NewReader(allBytes) 33 return d(w, io.LimitReader(reader, strippedLen)) 34 } 35 } 36 37 // execer returns a decompressor which executes the command that reads 38 // compressed bytes from stdin and writes the decompressed bytes to stdout. 39 func execer(command string, args ...string) decompressor { 40 return func(w io.Writer, r io.Reader) error { 41 cmd := exec.Command(command, args...) 42 cmd.Stdin = r 43 cmd.Stdout = w 44 45 stderrPipe, err := cmd.StderrPipe() 46 if err != nil { 47 return fmt.Errorf("error creating Stderr pipe: %v", err) 48 } 49 50 if err := cmd.Start(); err != nil { 51 return fmt.Errorf("error starting decompressor: %v", err) 52 } 53 54 stderr, err := io.ReadAll(stderrPipe) 55 if err != nil { 56 return fmt.Errorf("error reading stderr: %v", err) 57 } 58 59 if err := cmd.Wait(); err != nil || len(stderr) > 0 { 60 return fmt.Errorf("decompressor failed: err=%v, stderr=%q", err, stderr) 61 } 62 return nil 63 } 64 } 65 66 // gunzip reads compressed bytes from the io.Reader and writes the uncompressed bytes to the 67 // writer. gunzip satisfies the decompressor interface. 68 func gunzip(w io.Writer, r io.Reader) error { 69 gzipReader, err := gzip.NewReader(r) 70 if err != nil { 71 return fmt.Errorf("error creating gzip reader: %v", err) 72 } 73 74 if _, err := io.Copy(w, gzipReader); err != nil { 75 return fmt.Errorf("failed writing decompressed bytes to writer: %v", err) 76 } 77 return nil 78 } 79 80 // unlzma reads compressed bytes from the io.Reader and writes the uncompressed bytes to the 81 // writer. unlzma satisfies the decompressor interface. 82 func unlzma(w io.Writer, r io.Reader) error { 83 lzmaReader, err := lzma.NewReader(r) 84 if err != nil { 85 return fmt.Errorf("error creating lzma reader: %v", err) 86 } 87 88 if _, err := io.Copy(w, lzmaReader); err != nil { 89 return fmt.Errorf("failed writing decompressed bytes to writer: %v", err) 90 } 91 return nil 92 } 93 94 // unlz4 reads compressed bytes from the io.Reader and writes the uncompressed bytes to the 95 // writer. unlz4 satisfies the decompressor interface. 96 func unlz4(w io.Writer, r io.Reader) error { 97 lz4Reader := lz4.NewReader(r) 98 99 if _, err := io.Copy(w, lz4Reader); err != nil { 100 return fmt.Errorf("failed writing decompressed bytes to writer: %v", err) 101 } 102 return nil 103 } 104 105 // unbzip2 reads compressed bytes from the io.Reader and writes the uncompressed bytes to the 106 // writer. unbzip2 satisfies the decompressor interface. 107 func unbzip2(w io.Writer, r io.Reader) error { 108 bzip2Reader := bzip2.NewReader(r) 109 110 if _, err := io.Copy(w, bzip2Reader); err != nil { 111 return fmt.Errorf("failed writing decompressed bytes to writer: %v", err) 112 } 113 return nil 114 } 115 116 // unzstd reads compressed bytes from the io.Reader and writes the uncompressed bytes to the 117 // writer. unzstd satisfies the decompressor interface. 118 func unzstd(w io.Writer, r io.Reader) error { 119 zstdReader, err := zstd.NewReader(r) 120 if err != nil { 121 return fmt.Errorf("failed to create new reader: %v", err) 122 } 123 defer zstdReader.Close() 124 125 if _, err := io.Copy(w, zstdReader); err != nil { 126 return fmt.Errorf("failed writing decompressed bytes to writer: %v", err) 127 } 128 return nil 129 }