...

Source file src/edge-infra.dev/pkg/lib/compression/txz.go

Documentation: edge-infra.dev/pkg/lib/compression

     1  package compression
     2  
     3  import (
     4  	"archive/tar"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"github.com/xi2/xz"
    12  )
    13  
    14  // DecompressTarXz originally from
    15  // https://github.com/fergusstrange/embedded-postgres/blob/9f87ef1ab3ab1faff3d85dddc9f86e30f3f06dc9/decompression.go#L23
    16  func DecompressTarXz(txzFilePath, outputPath string) error {
    17  	tarFile, err := os.Open(txzFilePath)
    18  	if err != nil {
    19  		return errorUnableToExtract(txzFilePath, outputPath)
    20  	}
    21  
    22  	defer func() {
    23  		if err := tarFile.Close(); err != nil {
    24  			log.Printf("could not close txz tar file: %s, error %v\n", txzFilePath, err)
    25  		}
    26  	}()
    27  
    28  	xzReader, err := xz.NewReader(tarFile, 0)
    29  	if err != nil {
    30  		return errorUnableToExtract(txzFilePath, outputPath)
    31  	}
    32  
    33  	readNext, reader := defaultTarReader(xzReader)
    34  
    35  	for {
    36  		header, err := readNext()
    37  
    38  		if err == io.EOF {
    39  			return nil
    40  		}
    41  
    42  		if err != nil {
    43  			return errorExtractingPostgres(err)
    44  		}
    45  
    46  		targetPath := filepath.Join(outputPath, header.Name) // nolint:gosec
    47  
    48  		if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
    49  			return errorExtractingPostgres(err)
    50  		}
    51  
    52  		switch header.Typeflag {
    53  		case tar.TypeReg:
    54  			fsMode := os.FileMode(header.Mode) /* #nosec G115 */
    55  			outFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_RDWR, fsMode)
    56  			if err != nil {
    57  				return errorExtractingPostgres(err)
    58  			}
    59  
    60  			if _, err := io.Copy(outFile, reader()); err != nil {
    61  				return errorExtractingPostgres(err)
    62  			}
    63  
    64  			if err := outFile.Close(); err != nil {
    65  				return errorExtractingPostgres(err)
    66  			}
    67  		case tar.TypeSymlink:
    68  			if err := os.RemoveAll(targetPath); err != nil {
    69  				return errorExtractingPostgres(err)
    70  			}
    71  
    72  			if err := os.Symlink(header.Linkname, targetPath); err != nil {
    73  				return errorExtractingPostgres(err)
    74  			}
    75  		}
    76  	}
    77  }
    78  
    79  func defaultTarReader(xzReader *xz.Reader) (func() (*tar.Header, error), func() io.Reader) {
    80  	tarReader := tar.NewReader(xzReader)
    81  
    82  	return func() (*tar.Header, error) {
    83  			return tarReader.Next()
    84  		}, func() io.Reader {
    85  			return tarReader
    86  		}
    87  }
    88  
    89  func errorUnableToExtract(cacheLocation, binariesPath string) error {
    90  	return fmt.Errorf("unable to extract postgres archive %s to %s, if running parallel tests, configure RuntimePath to isolate testing directories", cacheLocation, binariesPath)
    91  }
    92  
    93  func errorExtractingPostgres(err error) error {
    94  	return fmt.Errorf("unable to extract postgres archive: %s", err)
    95  }
    96  

View as plain text