mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-09-07 01:26:43 +00:00
113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
![]() |
package getter
|
||
|
|
||
|
import (
|
||
|
"archive/tar"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
)
|
||
|
|
||
|
// untar is a shared helper for untarring an archive. The reader should provide
|
||
|
// an uncompressed view of the tar archive.
|
||
|
func untar(input io.Reader, dst, src string, dir bool) error {
|
||
|
tarR := tar.NewReader(input)
|
||
|
done := false
|
||
|
for {
|
||
|
hdr, err := tarR.Next()
|
||
|
if err == io.EOF {
|
||
|
if !done {
|
||
|
// Empty archive
|
||
|
return fmt.Errorf("empty archive: %s", src)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if hdr.Typeflag == tar.TypeXGlobalHeader || hdr.Typeflag == tar.TypeXHeader {
|
||
|
// don't unpack extended headers as files
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
path := dst
|
||
|
if dir {
|
||
|
path = filepath.Join(path, hdr.Name)
|
||
|
}
|
||
|
|
||
|
if hdr.FileInfo().IsDir() {
|
||
|
if !dir {
|
||
|
return fmt.Errorf("expected a single file: %s", src)
|
||
|
}
|
||
|
|
||
|
// A directory, just make the directory and continue unarchiving...
|
||
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
continue
|
||
|
} else {
|
||
|
// There is no ordering guarantee that a file in a directory is
|
||
|
// listed before the directory
|
||
|
dstPath := filepath.Dir(path)
|
||
|
|
||
|
// Check that the directory exists, otherwise create it
|
||
|
if _, err := os.Stat(dstPath); os.IsNotExist(err) {
|
||
|
if err := os.MkdirAll(dstPath, 0755); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We have a file. If we already decoded, then it is an error
|
||
|
if !dir && done {
|
||
|
return fmt.Errorf("expected a single file, got multiple: %s", src)
|
||
|
}
|
||
|
|
||
|
// Mark that we're done so future in single file mode errors
|
||
|
done = true
|
||
|
|
||
|
// Open the file for writing
|
||
|
dstF, err := os.Create(path)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = io.Copy(dstF, tarR)
|
||
|
dstF.Close()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Chmod the file
|
||
|
if err := os.Chmod(path, hdr.FileInfo().Mode()); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// tarDecompressor is an implementation of Decompressor that can
|
||
|
// unpack tar files.
|
||
|
type tarDecompressor struct{}
|
||
|
|
||
|
func (d *tarDecompressor) Decompress(dst, src string, dir bool) error {
|
||
|
// If we're going into a directory we should make that first
|
||
|
mkdir := dst
|
||
|
if !dir {
|
||
|
mkdir = filepath.Dir(dst)
|
||
|
}
|
||
|
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// File first
|
||
|
f, err := os.Open(src)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
return untar(f, dst, src, dir)
|
||
|
}
|