-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzip_reader.go
More file actions
91 lines (78 loc) · 2.06 KB
/
zip_reader.go
File metadata and controls
91 lines (78 loc) · 2.06 KB
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
package main
import (
"archive/zip"
"bytes"
"fmt"
"io"
"io/fs"
"os"
)
type BufferedZipEntry struct {
fs.File
*bytes.Reader
}
func (b *BufferedZipEntry) Read(p []byte) (n int, err error) {
return b.Reader.Read(p)
}
func (b *BufferedZipEntry) ReadDir(n int) ([]fs.DirEntry, error) {
if rdf, ok := b.File.(fs.ReadDirFile); ok {
return rdf.ReadDir(n)
}
return nil, fmt.Errorf("fs.File instance does not implement ReadDir")
}
func NewBufferedZipEntry(f fs.File) *BufferedZipEntry {
if f == nil {
return nil
}
var buf bytes.Buffer
io.Copy(&buf, f)
return &BufferedZipEntry{f, bytes.NewReader(buf.Bytes())}
}
var (
_ io.ReadSeeker = &BufferedZipEntry{}
_ fs.File = &BufferedZipEntry{}
)
var errBufferSizeExceeded = fmt.Errorf("size exceeds maximum allowed buffer size")
type BufferingZipFS struct {
*zip.Reader
maxBufferSize int64
}
// Name() returns the name of this implementation. This exists for test purpose.
func (z BufferingZipFS) Name() string {
return "BufferingZipFS"
}
func (z BufferingZipFS) Open(name string) (fs.File, error) {
verbose("open: %s", name)
f, err := z.Reader.Open(name)
if err != nil || f == nil {
verbose("error opening %s: %v", name, err)
return nil, err
}
stat, err := f.Stat()
if err != nil {
return nil, err
}
if !stat.IsDir() && stat.Size() >= z.maxBufferSize {
verbose("Buffer size exceeded for entry: %s, size: %d", name, stat.Size())
return nil, errBufferSizeExceeded
}
return NewBufferedZipEntry(f), nil
}
var _ fs.FS = &BufferingZipFS{}
func OpenZipReaderFS(path string, options *Options) fs.FS {
f, err := os.Open(path)
checkError(err, "cannot open input file")
fstat, err := f.Stat()
checkError(err, "Cannot stat input file")
if options.BufferFiles {
return GetBufferingZipFS(f, fstat.Size(), options.MaxBufferSize)
}
return GetStreamingZipFs(f, fstat.Size())
}
func GetBufferingZipFS(reader io.ReaderAt, size int64,
maxBufferSize int64,
) BufferingZipFS {
zipReader, err := zip.NewReader(reader, size)
checkError(err, "cannot open input ZIP file")
return BufferingZipFS{zipReader, maxBufferSize}
}