forked from hashicorp/go-getter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decompress_tbz2.go
95 lines (80 loc) · 1.75 KB
/
decompress_tbz2.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package getter
import (
"archive/tar"
"compress/bzip2"
"fmt"
"io"
"os"
"path/filepath"
)
// TarBzip2Decompressor is an implementation of Decompressor that can
// decompress tar.bz2 files.
type TarBzip2Decompressor struct{}
func (d *TarBzip2Decompressor) 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()
// Bzip2 compression is second
bzipR := bzip2.NewReader(f)
// Once bzip decompressed we have a tar format
tarR := tar.NewReader(bzipR)
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
}
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
}
// 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
}
}
}