github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/internal/unionreader/union_reader.go (about)

     1  package unionreader
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  
     8  	macho "github.com/anchore/go-macholibre"
     9  	"github.com/anchore/syft/internal/log"
    10  )
    11  
    12  // unionReader is a single interface with all reading functions needed by multi-arch binary catalogers
    13  // cataloger.
    14  type UnionReader interface {
    15  	io.Reader
    16  	io.ReaderAt
    17  	io.Seeker
    18  	io.Closer
    19  }
    20  
    21  // getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
    22  func GetReaders(f UnionReader) ([]io.ReaderAt, error) {
    23  	if macho.IsUniversalMachoBinary(f) {
    24  		machoReaders, err := macho.ExtractReaders(f)
    25  		if err != nil {
    26  			log.Debugf("extracting readers: %v", err)
    27  			return nil, err
    28  		}
    29  
    30  		var readers []io.ReaderAt
    31  		for _, e := range machoReaders {
    32  			readers = append(readers, e.Reader)
    33  		}
    34  
    35  		return readers, nil
    36  	}
    37  
    38  	return []io.ReaderAt{f}, nil
    39  }
    40  
    41  func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
    42  	reader, ok := readerCloser.(UnionReader)
    43  	if ok {
    44  		return reader, nil
    45  	}
    46  
    47  	b, err := io.ReadAll(readerCloser)
    48  	if err != nil {
    49  		return nil, fmt.Errorf("unable to read contents from binary: %w", err)
    50  	}
    51  
    52  	bytesReader := bytes.NewReader(b)
    53  
    54  	reader = struct {
    55  		io.ReadCloser
    56  		io.ReaderAt
    57  		io.Seeker
    58  	}{
    59  		ReadCloser: io.NopCloser(bytesReader),
    60  		ReaderAt:   bytesReader,
    61  		Seeker:     bytesReader,
    62  	}
    63  
    64  	return reader, nil
    65  }