Skip to content
This repository was archived by the owner on Apr 20, 2021. It is now read-only.

Commit acbe1bc

Browse files
committed
implement non-extent inodes
1 parent 9e732e3 commit acbe1bc

File tree

1 file changed

+102
-3
lines changed

1 file changed

+102
-3
lines changed

ext4/inode.go

+102-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"encoding/binary"
66
"fmt"
7+
"github.com/Sirupsen/logrus"
78
"io"
89
)
910

@@ -26,17 +27,115 @@ func (er *Reader) GetInode(n uint32) (inode Inode, err error) {
2627
return
2728
}
2829

30+
var log = logrus.New()
31+
2932
func (er *Reader) GetInodeReader(inode Inode) (io.Reader, error) {
3033
indr := inodeDataReader{
3134
er: er,
3235
length: int64(inode.Size()),
3336
}
34-
extents, err := er.GetExtents(inode)
37+
if inode.Flags&InodeFlagExtents > 0 {
38+
extents, err := er.GetExtents(inode)
39+
if err != nil {
40+
return nil, err
41+
}
42+
indr.extents = extents
43+
return &indr, nil
44+
} else {
45+
log.Infoln("Trying to read block map")
46+
47+
blocks, err := er.readBlockMap(inode)
48+
if err != nil {
49+
return nil, err
50+
}
51+
log.Infof(" block pointers: %+v", blocks)
52+
for i, p := range blocks {
53+
indr.extents = append(indr.extents, Extent{
54+
Block: uint32(i),
55+
Len: 1,
56+
StartLo: p,
57+
StartHi: 0,
58+
})
59+
}
60+
return &indr, nil
61+
}
62+
}
63+
64+
func (er *Reader) readBlockMap(inode Inode) ([]uint32, error) {
65+
// the inode block map is layed out as 12 direct pointers to
66+
// blocks, followed by three indirect pointers with increasing
67+
// levels of indirection. The first 0-pointer encountered walking
68+
// the structure indicates the end of the pointer array.
69+
// See https://en.wikipedia.org/wiki/Inode_pointer_structure
70+
71+
nodeData := inode.GetDataReader()
72+
blocks := make([]uint32, 12)
73+
err := binary.Read(nodeData, binary.LittleEndian, &blocks)
3574
if err != nil {
3675
return nil, err
3776
}
38-
indr.extents = extents
39-
return &indr, nil
77+
log.Infof(" direct block pointers: %+v", blocks)
78+
for i, b := range blocks {
79+
if b == 0 {
80+
return blocks[:i], nil
81+
}
82+
}
83+
84+
// if no 0-pointer encountered, then dig into indirect pointers
85+
pointers := make([]uint32, 3)
86+
if err := binary.Read(nodeData, binary.LittleEndian, &pointers); err != nil {
87+
return nil, err
88+
}
89+
for i, p := range pointers {
90+
if p == 0 {
91+
break
92+
}
93+
indirectblocks, err, done := er.readIndirectBlockMap(p, i+1)
94+
if err != nil {
95+
return nil, err
96+
}
97+
blocks = append(blocks, indirectblocks...)
98+
if done {
99+
break
100+
}
101+
}
102+
103+
for i, b := range blocks {
104+
if b == 0 {
105+
return blocks[:i], nil
106+
}
107+
}
108+
return blocks, nil
109+
}
110+
111+
func (er *Reader) readIndirectBlockMap(pointer uint32, level int) ([]uint32, error, bool) {
112+
if level == 0 {
113+
if pointer == 0 {
114+
return []uint32{}, nil, true
115+
}
116+
return []uint32{pointer}, nil, false
117+
}
118+
log.Infof(" reading one block of indirect block pointers with indirection level %d", level)
119+
pointers := make([]uint32, er.super.blockSize())
120+
if _, err := er.s.Seek(er.blockOffset(int64(pointer)), 0); err != nil {
121+
return nil, err, false
122+
}
123+
if err := binary.Read(er.s, binary.LittleEndian, &pointers); err != nil {
124+
return nil, err, false
125+
}
126+
var blocks []uint32
127+
for i, p := range pointers {
128+
indirectblocks, err, done := er.readIndirectBlockMap(p, level-1)
129+
if err != nil {
130+
return nil, err, false
131+
}
132+
blocks = append(blocks, indirectblocks...)
133+
if done {
134+
log.Infof(" end of block map found after following %d pointers at level %d", i, level)
135+
return blocks, nil, done
136+
}
137+
}
138+
return blocks, nil, false
40139
}
41140

42141
func (er *Reader) GetInodeContent(inode Inode) ([]byte, error) {

0 commit comments

Comments
 (0)