github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/utils/extract.go (about)

     1  // Copyright (c) 2017-present Xenia, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package utils
     5  
     6  import (
     7  	"archive/tar"
     8  	"compress/gzip"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"path/filepath"
    13  )
    14  
    15  // ExtractTarGz takes in an io.Reader containing the bytes for a .tar.gz file and
    16  // a destination string to extract to.
    17  func ExtractTarGz(gzipStream io.Reader, dst string) error {
    18  	uncompressedStream, err := gzip.NewReader(gzipStream)
    19  	if err != nil {
    20  		return fmt.Errorf("ExtractTarGz: NewReader failed: %s", err.Error())
    21  	}
    22  	defer uncompressedStream.Close()
    23  
    24  	tarReader := tar.NewReader(uncompressedStream)
    25  
    26  	for {
    27  		header, err := tarReader.Next()
    28  
    29  		if err == io.EOF {
    30  			break
    31  		}
    32  
    33  		if err != nil {
    34  			return fmt.Errorf("ExtractTarGz: Next() failed: %s", err.Error())
    35  		}
    36  
    37  		switch header.Typeflag {
    38  		case tar.TypeDir:
    39  			if PathTraversesUpward(header.Name) {
    40  				return fmt.Errorf("ExtractTarGz: path attempts to traverse upwards")
    41  			}
    42  
    43  			path := filepath.Join(dst, header.Name)
    44  			if err := os.Mkdir(path, 0744); err != nil && !os.IsExist(err) {
    45  				return fmt.Errorf("ExtractTarGz: Mkdir() failed: %s", err.Error())
    46  			}
    47  		case tar.TypeReg:
    48  			if PathTraversesUpward(header.Name) {
    49  				return fmt.Errorf("ExtractTarGz: path attempts to traverse upwards")
    50  			}
    51  
    52  			path := filepath.Join(dst, header.Name)
    53  			dir := filepath.Dir(path)
    54  
    55  			if err := os.MkdirAll(dir, 0744); err != nil {
    56  				return fmt.Errorf("ExtractTarGz: MkdirAll() failed: %s", err.Error())
    57  			}
    58  
    59  			outFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode))
    60  			if err != nil {
    61  				return fmt.Errorf("ExtractTarGz: Create() failed: %s", err.Error())
    62  			}
    63  			defer outFile.Close()
    64  			if _, err := io.Copy(outFile, tarReader); err != nil {
    65  				return fmt.Errorf("ExtractTarGz: Copy() failed: %s", err.Error())
    66  			}
    67  		default:
    68  			return fmt.Errorf(
    69  				"ExtractTarGz: unknown type: %v in %v",
    70  				header.Typeflag,
    71  				header.Name)
    72  		}
    73  	}
    74  
    75  	return nil
    76  }