go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/fsutil/tar.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package fsutil
     5  
     6  import (
     7  	"archive/tar"
     8  	"errors"
     9  	"io"
    10  	"os"
    11  
    12  	"github.com/rs/zerolog/log"
    13  	"github.com/spf13/afero"
    14  )
    15  
    16  func Tar(fs afero.Fs, f afero.File) (io.ReadCloser, error) {
    17  	stat, err := f.Stat()
    18  	if err != nil {
    19  		return nil, errors.New("could not retrieve file stats")
    20  	}
    21  
    22  	afutil := afero.Afero{Fs: fs}
    23  
    24  	// determine all files that we need to transfer
    25  	fileList := map[string]os.FileInfo{}
    26  	if stat.IsDir() == true {
    27  
    28  		err = afutil.Walk(f.Name(), func(path string, f os.FileInfo, err error) error {
    29  			fileList[path] = f
    30  			return nil
    31  		})
    32  		if err != nil {
    33  			return nil, err
    34  		}
    35  	} else {
    36  		fileList[f.Name()] = stat
    37  	}
    38  
    39  	// pipe content to a tar stream
    40  	tarReader, tarWriter := io.Pipe()
    41  
    42  	// stream content into the pipe
    43  	tw := tar.NewWriter(tarWriter)
    44  
    45  	// copy file content in the background
    46  	go func() {
    47  		for path, fileinfo := range fileList {
    48  			// we ignore the error for now but log them
    49  			fReader, err := os.Open(path)
    50  			if err == nil {
    51  				// send tar header
    52  				hdr := &tar.Header{
    53  					Name: path,
    54  					Mode: int64(fileinfo.Mode()),
    55  					Size: fileinfo.Size(),
    56  				}
    57  
    58  				if err := tw.WriteHeader(hdr); err != nil {
    59  					log.Error().Str("file", path).Err(err).Msg("local> could not write tar header")
    60  				}
    61  
    62  				_, err := io.Copy(tw, fReader)
    63  				if err != nil {
    64  					log.Error().Str("file", path).Err(err).Msg("local> could not write tar data")
    65  				}
    66  			} else {
    67  				log.Error().Str("file", path).Err(err).Msg("local> could not stream file")
    68  			}
    69  		}
    70  		tarWriter.Close()
    71  	}()
    72  
    73  	return tarReader, nil
    74  }