-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathtar.go
126 lines (103 loc) · 3.18 KB
/
tar.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package xtractr
import (
"archive/tar"
"compress/bzip2"
"compress/gzip"
"errors"
"fmt"
"io"
"os"
"strings"
lzw "github.com/sshaman1101/dcompress"
"github.com/therootcompany/xz"
)
// ExtractTar extracts a raw (non-compressed) tar archive.
func ExtractTar(xFile *XFile) (int64, []string, error) {
tarFile, err := os.Open(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
}
defer tarFile.Close()
return xFile.untar(tar.NewReader(tarFile))
}
// ExtractTarBzip extracts a bzip2-compressed tar archive.
func ExtractTarBzip(xFile *XFile) (int64, []string, error) {
compressedFile, err := os.Open(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
}
defer compressedFile.Close()
return xFile.untar(tar.NewReader(bzip2.NewReader(compressedFile)))
}
// ExtractTarXZ extracts an XZ-compressed tar archive (txz).
func ExtractTarXZ(xFile *XFile) (int64, []string, error) {
compressedFile, err := os.Open(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
}
defer compressedFile.Close()
zipStream, err := xz.NewReader(compressedFile, 0)
if err != nil {
return 0, nil, fmt.Errorf("xz.NewReader: %w", err)
}
return xFile.untar(tar.NewReader(zipStream))
}
// ExtractTarZ extracts an LZW-compressed tar archive (tz).
func ExtractTarZ(xFile *XFile) (int64, []string, error) {
compressedFile, err := os.Open(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
}
defer compressedFile.Close()
zipStream, err := lzw.NewReader(compressedFile)
if err != nil {
return 0, nil, fmt.Errorf("lzw.NewReader: %w", err)
}
return xFile.untar(tar.NewReader(zipStream))
}
// ExtractTarGzip extracts a gzip-compressed tar archive (tgz).
func ExtractTarGzip(xFile *XFile) (int64, []string, error) {
compressedFile, err := os.Open(xFile.FilePath)
if err != nil {
return 0, nil, fmt.Errorf("os.Open: %w", err)
}
defer compressedFile.Close()
zipStream, err := gzip.NewReader(compressedFile)
if err != nil {
return 0, nil, fmt.Errorf("gzip.NewReader: %w", err)
}
defer zipStream.Close()
return xFile.untar(tar.NewReader(zipStream))
}
func (x *XFile) untar(tarReader *tar.Reader) (int64, []string, error) {
files := []string{}
size := int64(0)
for {
header, err := tarReader.Next()
switch {
case errors.Is(err, io.EOF):
return size, files, nil
case err != nil:
return size, files, fmt.Errorf("%s: tarReader.Next: %w", x.FilePath, err)
case header == nil:
return size, files, fmt.Errorf("%w: %s", ErrInvalidHead, x.FilePath)
}
wfile := x.clean(header.Name)
if !strings.HasPrefix(wfile, x.OutputDir) {
// The file being written is trying to write outside of our base path. Malicious archive?
return size, files, fmt.Errorf("%s: %w: %s (from: %s)", x.FilePath, ErrInvalidPath, wfile, header.Name)
}
if header.Typeflag == tar.TypeDir {
if err = os.MkdirAll(wfile, header.FileInfo().Mode()); err != nil {
return size, files, fmt.Errorf("os.MkdirAll: %w", err)
}
continue
}
fSize, err := writeFile(wfile, tarReader, header.FileInfo().Mode(), x.DirMode)
if err != nil {
return size, files, err
}
files = append(files, wfile)
size += fSize
}
}