/
file.go
115 lines (94 loc) · 1.99 KB
/
file.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
package pkg
import (
"crypto/cipher"
"errors"
"io"
"io/ioutil"
)
func (pr *Reader) Read(b []byte) (int, error) {
if pr.err != nil {
return 0, pr.err
}
if pr.current == nil {
return 0, io.EOF
}
n, err := pr.current.Read(b)
if err != nil && err != io.EOF {
pr.err = err
}
return n, err
}
func (pr *Reader) Next() (*fileEntry, error) {
if pr.err != nil {
return nil, pr.err
}
hdr, err := pr.next()
pr.err = err
return hdr, err
}
func (pr *Reader) numBytes() int64 {
if pr.current == nil {
// No current file, so no bytes
return 0
}
return pr.current.numBytes()
}
func (pr *Reader) skipUnread() error {
dataSkip := pr.numBytes()
totalSkip := dataSkip + pr.pad
pr.current, pr.pad = nil, 0
copySkipped, err := io.CopyN(ioutil.Discard, pr.reader, totalSkip)
if err == io.EOF && copySkipped < dataSkip {
err = io.ErrUnexpectedEOF
}
return err
}
func (pr *Reader) next() (*fileEntry, error) {
if err := pr.skipUnread(); err != nil {
return nil, err
}
entry, err := pr.readNextEntry()
if err != nil {
return nil, err
}
if err := pr.handleRegularFile(entry); err != nil {
return nil, err
}
return entry, nil
}
func (pr *Reader) readNextEntry() (*fileEntry, error) {
e := &pr.index
if e.idx >= len(e.itemRecords) {
err := pr.readTail()
if err != nil {
return nil, err
} else {
return nil, io.EOF
}
}
entry := e.itemRecords[e.idx]
e.idx++
return &entry, nil
}
func (pr *Reader) handleRegularFile(entry *fileEntry) error {
nb := entry.Size
if entry.IsDirectory() {
nb = 0
}
if nb < 0 {
return errors.New("pkg: invalid pkg header")
}
e := &pr.index
curr := e.itemRecords[e.idx-1].Offset
var next int64
if e.idx < len(e.itemRecords) {
next = e.itemRecords[e.idx].Offset
} else {
next = pr.FileHeader.DataSize
}
r := NewCTR(entry.Key, pr.FileHeader.DataIV[:], entry.Offset/16)
reader := cipher.StreamReader{S: r, R: pr.aesReader.RawReader()}
pr.pad = next - curr - entry.Size
pr.current = ®FileReader{r: reader, nb: nb}
return nil
}