mirror of https://github.com/portainer/portainer
				
				
				
			
		
			
				
	
	
		
			129 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
package archive
 | 
						|
 | 
						|
import (
 | 
						|
	"archive/tar"
 | 
						|
	"compress/gzip"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// TarGzDir creates a tar.gz archive and returns it's path.
 | 
						|
// abosolutePath should be an absolute path to a directory.
 | 
						|
// Archive name will be <directoryName>.tar.gz and will be placed next to the directory.
 | 
						|
func TarGzDir(absolutePath string) (string, error) {
 | 
						|
	targzPath := filepath.Join(absolutePath, filepath.Base(absolutePath)+".tar.gz")
 | 
						|
	outFile, err := os.Create(targzPath)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	defer outFile.Close()
 | 
						|
 | 
						|
	zipWriter := gzip.NewWriter(outFile)
 | 
						|
	defer zipWriter.Close()
 | 
						|
	tarWriter := tar.NewWriter(zipWriter)
 | 
						|
	defer tarWriter.Close()
 | 
						|
 | 
						|
	err = filepath.Walk(absolutePath, func(path string, info os.FileInfo, err error) error {
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if path == targzPath {
 | 
						|
			return nil // skip archive file
 | 
						|
		}
 | 
						|
 | 
						|
		pathInArchive := filepath.Clean(strings.TrimPrefix(path, absolutePath))
 | 
						|
		if pathInArchive == "" {
 | 
						|
			return nil // skip root dir
 | 
						|
		}
 | 
						|
 | 
						|
		return addToArchive(tarWriter, pathInArchive, path, info)
 | 
						|
	})
 | 
						|
 | 
						|
	return targzPath, err
 | 
						|
}
 | 
						|
 | 
						|
func addToArchive(tarWriter *tar.Writer, pathInArchive string, path string, info os.FileInfo) error {
 | 
						|
	if info.IsDir() {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	file, err := os.Open(path)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	stat, err := file.Stat()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	header, err := tar.FileInfoHeader(stat, stat.Name())
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	header.Name = pathInArchive // use relative paths in archive
 | 
						|
 | 
						|
	err = tarWriter.WriteHeader(header)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if stat.IsDir() {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = io.Copy(tarWriter, file)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// ExtractTarGz reads a .tar.gz archive from the reader and extracts it into outputDirPath directory
 | 
						|
func ExtractTarGz(r io.Reader, outputDirPath string) error {
 | 
						|
	zipReader, err := gzip.NewReader(r)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer zipReader.Close()
 | 
						|
 | 
						|
	tarReader := tar.NewReader(zipReader)
 | 
						|
 | 
						|
	for {
 | 
						|
		header, err := tarReader.Next()
 | 
						|
 | 
						|
		if errors.Is(err, io.EOF) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		switch header.Typeflag {
 | 
						|
		case tar.TypeDir:
 | 
						|
			// skip, dir will be created with a file
 | 
						|
		case tar.TypeReg:
 | 
						|
			p := filepath.Clean(filepath.Join(outputDirPath, header.Name))
 | 
						|
			if err := os.MkdirAll(filepath.Dir(p), 0o744); err != nil {
 | 
						|
				return fmt.Errorf("Failed to extract dir %s", filepath.Dir(p))
 | 
						|
			}
 | 
						|
			outFile, err := os.Create(p)
 | 
						|
			if err != nil {
 | 
						|
				return fmt.Errorf("Failed to create file %s", header.Name)
 | 
						|
			}
 | 
						|
			if _, err := io.Copy(outFile, tarReader); err != nil {
 | 
						|
				return fmt.Errorf("Failed to extract file %s", header.Name)
 | 
						|
			}
 | 
						|
			outFile.Close()
 | 
						|
		default:
 | 
						|
			return fmt.Errorf("tar: unknown type: %v in %s",
 | 
						|
				header.Typeflag,
 | 
						|
				header.Name)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |