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  }