github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/archiver/targz.go (about)

     1  package archiver
     2  
     3  import (
     4  	"compress/gzip"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"strings"
     9  )
    10  
    11  // TarGz is for TarGz format
    12  var TarGz tarGzFormat
    13  
    14  func init() {
    15  	RegisterFormat("TarGz", TarGz)
    16  }
    17  
    18  type tarGzFormat struct{}
    19  
    20  func (tarGzFormat) Match(filename string) bool {
    21  	return strings.HasSuffix(strings.ToLower(filename), ".tar.gz") ||
    22  		strings.HasSuffix(strings.ToLower(filename), ".tgz") ||
    23  		isTarGz(filename)
    24  }
    25  
    26  // isTarGz checks the file has the gzip compressed Tar format header by reading
    27  // its beginning block.
    28  func isTarGz(targzPath string) bool {
    29  	f, err := os.Open(targzPath)
    30  	if err != nil {
    31  		return false
    32  	}
    33  	defer f.Close()
    34  
    35  	gzr, err := gzip.NewReader(f)
    36  	if err != nil {
    37  		return false
    38  	}
    39  	defer gzr.Close()
    40  
    41  	buf := make([]byte, tarBlockSize)
    42  	n, err := gzr.Read(buf)
    43  	if err != nil || n < tarBlockSize {
    44  		return false
    45  	}
    46  
    47  	return hasTarHeader(buf)
    48  }
    49  
    50  // Write outputs a .tar.gz file to a Writer containing
    51  // the contents of files listed in filePaths. It works
    52  // the same way Tar does, but with gzip compression.
    53  func (tarGzFormat) Write(output io.Writer, filePaths []string) error {
    54  	return writeTarGz(filePaths, output, "")
    55  }
    56  
    57  // Make creates a .tar.gz file at targzPath containing
    58  // the contents of files listed in filePaths. It works
    59  // the same way Tar does, but with gzip compression.
    60  func (tarGzFormat) Make(targzPath string, filePaths []string) error {
    61  	out, err := os.Create(targzPath)
    62  	if err != nil {
    63  		return fmt.Errorf("error creating %s: %v", targzPath, err)
    64  	}
    65  	defer out.Close()
    66  
    67  	return writeTarGz(filePaths, out, targzPath)
    68  }
    69  
    70  func writeTarGz(filePaths []string, output io.Writer, dest string) error {
    71  	gzw := gzip.NewWriter(output)
    72  	defer gzw.Close()
    73  
    74  	return writeTar(filePaths, gzw, dest)
    75  }
    76  
    77  // Read untars a .tar.gz file read from a Reader and decompresses
    78  // the contents into destination.
    79  func (tarGzFormat) Read(input io.Reader, destination string) error {
    80  	gzr, err := gzip.NewReader(input)
    81  	if err != nil {
    82  		return fmt.Errorf("error decompressing: %v", err)
    83  	}
    84  	defer gzr.Close()
    85  
    86  	return Tar.Read(gzr, destination)
    87  }
    88  
    89  // Open untars source and decompresses the contents into destination.
    90  func (tarGzFormat) Open(source, destination string) error {
    91  	f, err := os.Open(source)
    92  	if err != nil {
    93  		return fmt.Errorf("%s: failed to open archive: %v", source, err)
    94  	}
    95  	defer f.Close()
    96  
    97  	return TarGz.Read(f, destination)
    98  }