-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtarfs.go
95 lines (83 loc) · 1.82 KB
/
tarfs.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
// In memory http.FileSystem from tar archives
package tarfs
import (
"archive/tar"
"bytes"
"errors"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
// New returns an http.FileSystem that holds all the files in the tar,
// It reads the whole archive from the Reader. It is the caller's responsibility to call Close on the Reader when done.
func New(tarstream io.Reader) (http.FileSystem, error) {
tr := tar.NewReader(tarstream)
tarfs := tarfs{make(map[string]file)}
// Iterate through the files in the archive.
for {
hdr, err := tr.Next()
if err == io.EOF {
// end of tar archive
break
}
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(tr)
if err != nil {
return nil, err
}
tarfs.files[path.Join("/", hdr.Name)] = file{
data: data,
fi: hdr.FileInfo(),
}
}
return &tarfs, nil
}
type file struct {
*bytes.Reader
data []byte
fi os.FileInfo
files []os.FileInfo
}
type tarfs struct {
files map[string]file
}
func (tf *tarfs) Open(name string) (http.File, error) {
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
strings.Contains(name, "\x00") {
return nil, errors.New("http: invalid character in file path")
}
f, ok := tf.files[path.Join("/", name)]
if !ok {
return nil, os.ErrNotExist
}
if f.fi.IsDir() {
f.files = []os.FileInfo{}
for path, file := range tf.files {
if strings.HasPrefix(path, name) {
s, _ := file.Stat()
f.files = append(f.files, s)
}
}
}
f.Reader = bytes.NewReader(f.data)
return &f, nil
}
// A noop-closer.
func (f *file) Close() error {
return nil
}
func (f *file) Readdir(count int) ([]os.FileInfo, error) {
if f.fi.IsDir() && f.files != nil {
return f.files, nil
}
return nil, os.ErrNotExist
}
func (f *file) Stat() (os.FileInfo, error) {
return f.fi, nil
}