diff options
Diffstat (limited to 'vendor/github.com/hashicorp/go-getter/decompress_tar.go')
-rw-r--r-- | vendor/github.com/hashicorp/go-getter/decompress_tar.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-getter/decompress_tar.go b/vendor/github.com/hashicorp/go-getter/decompress_tar.go new file mode 100644 index 0000000..39cb392 --- /dev/null +++ b/vendor/github.com/hashicorp/go-getter/decompress_tar.go | |||
@@ -0,0 +1,138 @@ | |||
1 | package getter | ||
2 | |||
3 | import ( | ||
4 | "archive/tar" | ||
5 | "fmt" | ||
6 | "io" | ||
7 | "os" | ||
8 | "path/filepath" | ||
9 | ) | ||
10 | |||
11 | // untar is a shared helper for untarring an archive. The reader should provide | ||
12 | // an uncompressed view of the tar archive. | ||
13 | func untar(input io.Reader, dst, src string, dir bool) error { | ||
14 | tarR := tar.NewReader(input) | ||
15 | done := false | ||
16 | dirHdrs := []*tar.Header{} | ||
17 | for { | ||
18 | hdr, err := tarR.Next() | ||
19 | if err == io.EOF { | ||
20 | if !done { | ||
21 | // Empty archive | ||
22 | return fmt.Errorf("empty archive: %s", src) | ||
23 | } | ||
24 | |||
25 | break | ||
26 | } | ||
27 | if err != nil { | ||
28 | return err | ||
29 | } | ||
30 | |||
31 | if hdr.Typeflag == tar.TypeXGlobalHeader || hdr.Typeflag == tar.TypeXHeader { | ||
32 | // don't unpack extended headers as files | ||
33 | continue | ||
34 | } | ||
35 | |||
36 | path := dst | ||
37 | if dir { | ||
38 | // Disallow parent traversal | ||
39 | if containsDotDot(hdr.Name) { | ||
40 | return fmt.Errorf("entry contains '..': %s", hdr.Name) | ||
41 | } | ||
42 | |||
43 | path = filepath.Join(path, hdr.Name) | ||
44 | } | ||
45 | |||
46 | if hdr.FileInfo().IsDir() { | ||
47 | if !dir { | ||
48 | return fmt.Errorf("expected a single file: %s", src) | ||
49 | } | ||
50 | |||
51 | // A directory, just make the directory and continue unarchiving... | ||
52 | if err := os.MkdirAll(path, 0755); err != nil { | ||
53 | return err | ||
54 | } | ||
55 | |||
56 | // Record the directory information so that we may set its attributes | ||
57 | // after all files have been extracted | ||
58 | dirHdrs = append(dirHdrs, hdr) | ||
59 | |||
60 | continue | ||
61 | } else { | ||
62 | // There is no ordering guarantee that a file in a directory is | ||
63 | // listed before the directory | ||
64 | dstPath := filepath.Dir(path) | ||
65 | |||
66 | // Check that the directory exists, otherwise create it | ||
67 | if _, err := os.Stat(dstPath); os.IsNotExist(err) { | ||
68 | if err := os.MkdirAll(dstPath, 0755); err != nil { | ||
69 | return err | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | // We have a file. If we already decoded, then it is an error | ||
75 | if !dir && done { | ||
76 | return fmt.Errorf("expected a single file, got multiple: %s", src) | ||
77 | } | ||
78 | |||
79 | // Mark that we're done so future in single file mode errors | ||
80 | done = true | ||
81 | |||
82 | // Open the file for writing | ||
83 | dstF, err := os.Create(path) | ||
84 | if err != nil { | ||
85 | return err | ||
86 | } | ||
87 | _, err = io.Copy(dstF, tarR) | ||
88 | dstF.Close() | ||
89 | if err != nil { | ||
90 | return err | ||
91 | } | ||
92 | |||
93 | // Chmod the file | ||
94 | if err := os.Chmod(path, hdr.FileInfo().Mode()); err != nil { | ||
95 | return err | ||
96 | } | ||
97 | |||
98 | // Set the access and modification time | ||
99 | if err := os.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil { | ||
100 | return err | ||
101 | } | ||
102 | } | ||
103 | |||
104 | // Adding a file or subdirectory changes the mtime of a directory | ||
105 | // We therefore wait until we've extracted everything and then set the mtime and atime attributes | ||
106 | for _, dirHdr := range dirHdrs { | ||
107 | path := filepath.Join(dst, dirHdr.Name) | ||
108 | if err := os.Chtimes(path, dirHdr.AccessTime, dirHdr.ModTime); err != nil { | ||
109 | return err | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return nil | ||
114 | } | ||
115 | |||
116 | // tarDecompressor is an implementation of Decompressor that can | ||
117 | // unpack tar files. | ||
118 | type tarDecompressor struct{} | ||
119 | |||
120 | func (d *tarDecompressor) Decompress(dst, src string, dir bool) error { | ||
121 | // If we're going into a directory we should make that first | ||
122 | mkdir := dst | ||
123 | if !dir { | ||
124 | mkdir = filepath.Dir(dst) | ||
125 | } | ||
126 | if err := os.MkdirAll(mkdir, 0755); err != nil { | ||
127 | return err | ||
128 | } | ||
129 | |||
130 | // File first | ||
131 | f, err := os.Open(src) | ||
132 | if err != nil { | ||
133 | return err | ||
134 | } | ||
135 | defer f.Close() | ||
136 | |||
137 | return untar(f, dst, src, dir) | ||
138 | } | ||