-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtablereader.go
More file actions
128 lines (108 loc) · 2.6 KB
/
tablereader.go
File metadata and controls
128 lines (108 loc) · 2.6 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
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
127
128
package squashfs
import (
"fmt"
"io"
)
// TODO add buf cache to allow multiple accesses to same block without re-reading
type tableReader struct {
sb *Superblock
buf []byte
offt int64
tofft int64 // position of table block list (when blocks aren't one after another)
}
func (sb *Superblock) newInodeReader(ino inodeRef) (*tableReader, error) {
return sb.newTableReader(int64(sb.InodeTableStart)+int64(ino.Index()), int(ino.Offset()))
}
func (sb *Superblock) newTableReader(base int64, start int) (*tableReader, error) {
ir := &tableReader{
sb: sb,
offt: base,
}
err := ir.readBlock()
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, fmt.Errorf("failed to read initial block at base=%d: %w", base, err)
}
if start != 0 {
// need to cut offset
if start > len(ir.buf) {
return nil, fmt.Errorf("start offset %d exceeds block size %d (base=%d)", start, len(ir.buf), base)
}
ir.buf = ir.buf[start:]
}
return ir, nil
}
func (sb *Superblock) newIndirectTableReader(base int64, start int) (*tableReader, error) {
ir := &tableReader{
sb: sb,
tofft: base,
}
err := ir.readBlock()
if err != nil {
return nil, err
}
if start != 0 {
// need to cut offset
ir.buf = ir.buf[start:]
}
return ir, nil
}
func (i *tableReader) readBlock() error {
if i.tofft != 0 {
// tofft mode
buf := make([]byte, 8)
_, err := i.sb.fs.ReadAt(buf, i.tofft)
if err != nil {
return err
}
i.offt = int64(i.sb.order.Uint64(buf))
}
buf := make([]byte, 2)
_, err := i.sb.fs.ReadAt(buf, i.offt)
if err != nil {
return fmt.Errorf("readBlock header at offset %d: %w", i.offt, err)
}
lenN := i.sb.order.Uint16(buf)
nocompressFlag := false
if lenN&0x8000 == 0x8000 {
// not compressed
nocompressFlag = true
lenN = lenN & 0x7fff
}
buf = make([]byte, int(lenN))
// read data
_, err = i.sb.fs.ReadAt(buf, i.offt+2)
if err != nil {
return fmt.Errorf("readBlock data at offset %d, len %d: %w", i.offt+2, lenN, err)
}
i.offt += int64(lenN) + 2
if !nocompressFlag {
// decompress
buf, err = i.sb.Comp.decompress(buf)
if err != nil {
//log.Printf("squashfs: failed to read compressed data: %s", err)
return err
}
}
i.buf = buf
//fmt.Printf("readBlock: offset=%d, compressedSize=%d, decompressedSize=%d\n", i.offt-int64(lenN)-2, lenN, len(buf))
return nil
}
func (i *tableReader) Read(p []byte) (int, error) {
// read from buf, if empty call readBlock()
if i.buf == nil {
err := i.readBlock()
if err != nil {
return 0, err
}
}
n := copy(p, i.buf)
if n == len(i.buf) {
i.buf = nil
} else {
i.buf = i.buf[n:]
}
return n, nil
}