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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
package btrfs
import (
"time"
"lukeshu.com/btrfs-tools/pkg/binstruct"
)
type (
PhysicalAddr int64
LogicalAddr int64
ObjID int64
)
type Key struct {
ObjectID ObjID `bin:"off=0, siz=8"` // Object ID. Each tree has its own set of Object IDs.
ItemType uint8 `bin:"off=8, siz=1"` // Item type.
Offset uint64 `bin:"off=9, siz=8"` // Offset. The meaning depends on the item type.
binstruct.End `bin:"off=11"`
}
type Time struct {
Sec int64 `bin:"off=0, siz=8"` // Number of seconds since 1970-01-01T00:00:00Z.
NSec uint64 `bin:"off=8, siz=4"` // Number of nanoseconds since the beginning of the second.
binstruct.End `bin:"off=c"`
}
func (t Time) ToStd() time.Time {
return time.Unix(t.Sec, int64(t.NSec))
}
type Superblock struct {
Checksum CSum `bin:"off=0, siz=20"` // Checksum of everything past this field (from 20 to 1000)
FSUUID UUID `bin:"off=20, siz=10"` // FS UUID
Self PhysicalAddr `bin:"off=30, siz=8"` // physical address of this block (different for mirrors)
Flags uint64 `bin:"off=38, siz=8"` // flags
Magic [8]byte `bin:"off=40, siz=8"` // magic ('_BHRfS_M')
Generation uint64 `bin:"off=48, siz=8"` // generation
RootTree LogicalAddr `bin:"off=50, siz=8"` // logical address of the root tree root
ChunkTree LogicalAddr `bin:"off=58, siz=8"` // logical address of the chunk tree root
LogTree LogicalAddr `bin:"off=60, siz=8"` // logical address of the log tree root
LogRootTransID uint64 `bin:"off=68, siz=8"` // log_root_transid
TotalBytes uint64 `bin:"off=70, siz=8"` // total_bytes
BytesUsed uint64 `bin:"off=78, siz=8"` // bytes_used
RootDirObjectID uint64 `bin:"off=80, siz=8"` // root_dir_objectid (usually 6)
NumDevices uint64 `bin:"off=88, siz=8"` // num_devices
SectorSize uint32 `bin:"off=90, siz=4"` // sectorsize
NodeSize uint32 `bin:"off=94, siz=4"` // nodesize
LeafSize uint32 `bin:"off=98, siz=4"` // leafsize
StripeSize uint32 `bin:"off=9c, siz=4"` // stripesize
SysChunkArraySize uint32 `bin:"off=a0, siz=4"` // sys_chunk_array_size
ChunkRootGeneration uint64 `bin:"off=a4, siz=8"` // chunk_root_generation
CompatFlags uint64 `bin:"off=ac, siz=8"` // compat_flags
CompatROFlags uint64 `bin:"off=b4, siz=8"` // compat_ro_flags - only implementations that support the flags can write to the filesystem
IncompatFlags uint64 `bin:"off=bc, siz=8"` // incompat_flags - only implementations that support the flags can use the filesystem
ChecksumType uint16 `bin:"off=c4, siz=2"` // csum_type - Btrfs currently uses the CRC32c little-endian hash function with seed -1.
RootLevel uint8 `bin:"off=c6, siz=1"` // root_level
ChunkLevel uint8 `bin:"off=c7, siz=1"` // chunk_root_level
LogLevel uint8 `bin:"off=c8, siz=1"` // log_root_level
DevItem DevItem `bin:"off=c9, siz=62"` // DEV_ITEM data for this device
Label [0x100]byte `bin:"off=12b, siz=100"` // label (may not contain '/' or '\\')
CacheGeneration uint64 `bin:"off=22b, siz=8"` // cache_generation
UUIDTreeGeneration uint64 `bin:"off=233, siz=8"` // uuid_tree_generation
Reserved [0xf0]byte `bin:"off=23b, siz=f0"` // reserved /* future expansion */
SysChunkArray [0x800]byte `bin:"off=32b, siz=800"` // sys_chunk_array:(n bytes valid) Contains (KEY . CHUNK_ITEM) pairs for all SYSTEM chunks. This is needed to bootstrap the mapping from logical addresses to physical.
TODOSuperRoots [0x2a0]byte `bin:"off=b2b, siz=2a0"` // Contain super_roots (4 btrfs_root_backup)
Unused [0x235]byte `bin:"off=dcb, siz=235"` // current unused
binstruct.End `bin:"off=1000"`
}
func (sb Superblock) CalculateChecksum() (CSum, error) {
data, err := binstruct.Marshal(sb)
if err != nil {
return CSum{}, err
}
return CRC32c(data[0x20:]), nil
}
type SysChunk struct {
Key `bin:"off=0, siz=11"`
ChunkItem `bin:"off=11, siz=30"`
binstruct.End `bin:"off=41"`
}
func (sb Superblock) ParseSysChunkArray() ([]SysChunk, error) {
dat := sb.SysChunkArray[:sb.SysChunkArraySize]
var ret []SysChunk
for len(dat) > 0 {
var pair SysChunk
if err := binstruct.Unmarshal(dat, &pair); err != nil {
return nil, err
}
dat = dat[0x41:]
for i := 0; i < int(pair.ChunkItem.NumStripes); i++ {
var stripe ChunkItemStripe
if err := binstruct.Unmarshal(dat, &stripe); err != nil {
return nil, err
}
pair.ChunkItem.Stripes = append(pair.ChunkItem.Stripes, stripe)
dat = dat[0x20:]
}
ret = append(ret, pair)
}
return ret, nil
}
type DevItem struct {
DeviceID uint64 `bin:"off=0, siz=8"` // device id
NumBytes uint64 `bin:"off=8, siz=8"` // number of bytes
NumBytesUsed uint64 `bin:"off=10, siz=8"` // number of bytes used
IOOptimalAlign uint32 `bin:"off=18, siz=4"` // optimal I/O align
IOOptimalWidth uint32 `bin:"off=1c, siz=4"` // optimal I/O width
IOMinSize uint32 `bin:"off=20, siz=4"` // minimal I/O size (sector size)
Type uint64 `bin:"off=24, siz=8"` // type
Generation uint64 `bin:"off=2c, siz=8"` // generation
StartOffset uint64 `bin:"off=34, siz=8"` // start offset
DevGroup uint32 `bin:"off=3c, siz=4"` // dev group
SeekSpeed uint8 `bin:"off=40, siz=1"` // seek speed
Bandwidth uint8 `bin:"off=41, siz=1"` // bandwidth
DevUUID UUID `bin:"off=42, siz=10"` // device UUID
FSUUID UUID `bin:"off=52, siz=10"` // FS UUID
binstruct.End `bin:"off=62"`
}
type ChunkItem struct {
// Maps logical address to physical.
Size uint64 `bin:"off=0, siz=8"` // size of chunk (bytes)
Root ObjID `bin:"off=8, siz=8"` // root referencing this chunk (2)
StripeLen uint64 `bin:"off=10, siz=8"` // stripe length
Type uint64 `bin:"off=18, siz=8"` // type (same as flags for block group?)
IOOptimalAlign uint32 `bin:"off=20, siz=4"` // optimal io alignment
IOOptimalWidth uint32 `bin:"off=24, siz=4"` // optimal io width
IoMinSize uint32 `bin:"off=28, siz=4"` // minimal io size (sector size)
NumStripes uint16 `bin:"off=2c, siz=2"` // number of stripes
SubStripes uint16 `bin:"off=2e, siz=2"` // sub stripes
binstruct.End `bin:"off=30"`
Stripes []ChunkItemStripe `bin:"-"`
}
type ChunkItemStripe struct {
// Stripes follow (for each number of stripes):
DeviceID ObjID `bin:"off=0, siz=8"` // device id
Offset uint64 `bin:"off=8, siz=8"` // offset
DeviceUUID UUID `bin:"off=10, siz=10"` // device UUID
binstruct.End `bin:"off=20"`
}
|