clair/vendor/github.com/mholt/archiver/targz.go
2016-09-28 15:24:38 +02:00

139 lines
3.0 KiB
Go

package archiver
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
// TarGz creates a .tar.gz file at targzPath containing
// the contents of files listed in filePaths. File paths
// can be those of regular files or directories. Regular
// files are stored at the 'root' of the archive, and
// directories are recursively added.
func TarGz(targzPath string, filePaths []string) error {
out, err := os.Create(targzPath)
if err != nil {
return fmt.Errorf("error creating %s: %v", targzPath, err)
}
defer out.Close()
gzWriter := gzip.NewWriter(out)
defer gzWriter.Close()
tarWriter := tar.NewWriter(gzWriter)
defer tarWriter.Close()
for _, fpath := range filePaths {
err := tarGzFile(tarWriter, fpath)
if err != nil {
return err
}
}
return nil
}
func tarGzFile(tarWriter *tar.Writer, source string) error {
sourceInfo, err := os.Stat(source)
if err != nil {
return fmt.Errorf("%s: stat: %v", source, err)
}
var baseDir string
if sourceInfo.IsDir() {
baseDir = filepath.Base(source)
}
return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error walking to %s: %v", path, err)
}
header, err := tar.FileInfoHeader(info, path)
if err != nil {
return fmt.Errorf("%s: making header: %v", path, err)
}
if baseDir != "" {
header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
}
if info.IsDir() {
header.Name += "/"
}
err = tarWriter.WriteHeader(header)
if err != nil {
return fmt.Errorf("%s: writing header: %v", path, err)
}
if info.IsDir() {
return nil
}
if header.Typeflag == tar.TypeReg {
file, err := os.Open(path)
if err != nil {
return fmt.Errorf("%s: open: %v", path, err)
}
defer file.Close()
_, err = io.Copy(tarWriter, file)
if err != nil {
return fmt.Errorf("%s: copying contents: %v", path, err)
}
}
return nil
})
}
// UntarGz untars source and decompresses the contents into destination.
func UntarGz(source, destination string) error {
f, err := os.Open(source)
if err != nil {
return fmt.Errorf("%s: failed to open archive: %v", source, err)
}
defer f.Close()
gzf, err := gzip.NewReader(f)
if err != nil {
return fmt.Errorf("%s: create new gzip reader: %v", source, err)
}
defer gzf.Close()
tr := tar.NewReader(gzf)
for {
header, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
return err
}
if err := untarGzFile(tr, header, destination); err != nil {
return err
}
}
return nil
}
func untarGzFile(tr *tar.Reader, header *tar.Header, destination string) error {
switch header.Typeflag {
case tar.TypeDir:
return mkdir(filepath.Join(destination, header.Name))
case tar.TypeReg:
return writeNewFile(filepath.Join(destination, header.Name), tr, header.FileInfo().Mode())
case tar.TypeSymlink:
return writeNewSymbolicLink(filepath.Join(destination, header.Name), header.Linkname)
default:
return fmt.Errorf("%s: unknown type flag: %c", header.Name, header.Typeflag)
}
}