summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-06-01 02:41:36 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-06-01 02:41:36 -0600
commitcf314d3f1f96e2c07b68a7171e27f58c899bcdbb (patch)
tree85a3e4769700d054a5deaccc71c691645e029b09 /pkg
parentd6243eb7afd5d9d91686bce2e02c252be456b38c (diff)
fix
Diffstat (limited to 'pkg')
-rw-r--r--pkg/binstruct/structs.go6
-rw-r--r--pkg/btrfs/btrfsitem/item_chunk.go11
-rw-r--r--pkg/btrfs/internal/misc.go14
-rw-r--r--pkg/btrfs/io2_fs.go4
-rw-r--r--pkg/btrfs/types_btree.go16
-rw-r--r--pkg/btrfs/types_superblock.go184
6 files changed, 128 insertions, 107 deletions
diff --git a/pkg/binstruct/structs.go b/pkg/binstruct/structs.go
index 7a0c74b..8ecea6a 100644
--- a/pkg/binstruct/structs.go
+++ b/pkg/binstruct/structs.go
@@ -113,6 +113,12 @@ func genStructHandler(structInfo reflect.Type) (structHandler, error) {
for i := 0; i < structInfo.NumField(); i++ {
var fieldInfo reflect.StructField = structInfo.Field(i)
+ if fieldInfo.Anonymous && fieldInfo.Type != endType {
+ err := fmt.Errorf("binstruct does not support embedded fields")
+ return ret, fmt.Errorf("struct %q field %d %q: %w",
+ ret.name, i, fieldInfo.Name, err)
+ }
+
fieldTag, err := parseStructTag(fieldInfo.Tag.Get("bin"))
if err != nil {
return ret, fmt.Errorf("struct %q field %d %q: %w",
diff --git a/pkg/btrfs/btrfsitem/item_chunk.go b/pkg/btrfs/btrfsitem/item_chunk.go
index 5c573b0..7bb65b1 100644
--- a/pkg/btrfs/btrfsitem/item_chunk.go
+++ b/pkg/btrfs/btrfsitem/item_chunk.go
@@ -1,6 +1,8 @@
package btrfsitem
import (
+ "fmt"
+
"lukeshu.com/btrfs-tools/pkg/binstruct"
"lukeshu.com/btrfs-tools/pkg/btrfs/internal"
)
@@ -21,11 +23,10 @@ type Chunk struct { // CHUNK_ITEM=228
}
type ChunkStripe struct {
- // Stripes follow (for each number of stripes):
- DeviceID internal.ObjID `bin:"off=0, siz=8"` // device ID
- Offset uint64 `bin:"off=8, siz=8"` // offset
- DeviceUUID internal.UUID `bin:"off=10, siz=10"` // device UUID
- binstruct.End `bin:"off=20"`
+ DeviceID internal.ObjID `bin:"off=0x0, siz=0x8"`
+ Offset uint64 `bin:"off=0x8, siz=0x8"`
+ DeviceUUID internal.UUID `bin:"off=0x10, siz=0x10"`
+ binstruct.End `bin:"off=0x20"`
}
func (chunk *Chunk) UnmarshalBinary(dat []byte) (int, error) {
diff --git a/pkg/btrfs/internal/misc.go b/pkg/btrfs/internal/misc.go
index e7d9dd6..de8120a 100644
--- a/pkg/btrfs/internal/misc.go
+++ b/pkg/btrfs/internal/misc.go
@@ -13,16 +13,16 @@ type (
)
type Key struct {
- ObjectID ObjID `bin:"off=0, siz=8"` // Each tree has its own set of Object IDs.
- ItemType ItemType `bin:"off=8, siz=1"`
- Offset uint64 `bin:"off=9, siz=8"` // The meaning depends on the item type.
- binstruct.End `bin:"off=11"`
+ ObjectID ObjID `bin:"off=0x0, siz=0x8"` // Each tree has its own set of Object IDs.
+ ItemType ItemType `bin:"off=0x8, siz=0x1"`
+ Offset uint64 `bin:"off=0x9, siz=0x8"` // The meaning depends on the item type.
+ binstruct.End `bin:"off=0x11"`
}
type Time struct {
- Sec int64 `bin:"off=0, siz=8"` // Number of seconds since 1970-01-01T00:00:00Z.
- NSec uint32 `bin:"off=8, siz=4"` // Number of nanoseconds since the beginning of the second.
- binstruct.End `bin:"off=c"`
+ Sec int64 `bin:"off=0x0, siz=0x8"` // Number of seconds since 1970-01-01T00:00:00Z.
+ NSec uint32 `bin:"off=0x8, siz=0x4"` // Number of nanoseconds since the beginning of the second.
+ binstruct.End `bin:"off=0xc"`
}
func (t Time) ToStd() time.Time {
diff --git a/pkg/btrfs/io2_fs.go b/pkg/btrfs/io2_fs.go
index bf19d4b..bcf9777 100644
--- a/pkg/btrfs/io2_fs.go
+++ b/pkg/btrfs/io2_fs.go
@@ -164,8 +164,8 @@ func (fs *FS) maybeShortReadAt(dat []byte, laddr LogicalAddr) (int, error) {
paddrs := make(map[physicalAddr]struct{})
for _, chunk := range fs.chunks {
- if chunk.Offset <= uint64(laddr) && uint64(laddr) < chunk.Offset+uint64(chunk.Chunk.Size) {
- offsetWithinChunk := uint64(laddr) - chunk.Offset
+ if chunk.Key.Offset <= uint64(laddr) && uint64(laddr) < chunk.Key.Offset+uint64(chunk.Chunk.Size) {
+ offsetWithinChunk := uint64(laddr) - chunk.Key.Offset
if offsetWithinChunk+uint64(len(dat)) > chunk.Chunk.Size {
dat = dat[:chunk.Chunk.Size-offsetWithinChunk]
}
diff --git a/pkg/btrfs/types_btree.go b/pkg/btrfs/types_btree.go
index b8ad14b..8e25eb4 100644
--- a/pkg/btrfs/types_btree.go
+++ b/pkg/btrfs/types_btree.go
@@ -72,17 +72,17 @@ func (f NodeFlags) Has(req NodeFlags) bool { return f&req == req }
func (f NodeFlags) String() string { return util.BitfieldString(f, nodeFlagNames) }
type KeyPointer struct {
- Key Key `bin:"off=0, siz=11"`
- BlockPtr LogicalAddr `bin:"off=11, siz=8"`
- Generation Generation `bin:"off=19, siz=8"`
- binstruct.End `bin:"off=21"`
+ Key Key `bin:"off=0x0, siz=0x11"`
+ BlockPtr LogicalAddr `bin:"off=0x11, siz=0x8"`
+ Generation Generation `bin:"off=0x19, siz=0x8"`
+ binstruct.End `bin:"off=0x21"`
}
type ItemHeader struct {
- Key Key `bin:"off=0, siz=11"`
- DataOffset uint32 `bin:"off=11, siz=4"` // relative to the end of the header (0x65)
- DataSize uint32 `bin:"off=15, siz=4"`
- binstruct.End `bin:"off=19"`
+ Key Key `bin:"off=0x0, siz=0x11"`
+ DataOffset uint32 `bin:"off=0x11, siz=0x4"` // relative to the end of the header (0x65)
+ DataSize uint32 `bin:"off=0x15, siz=0x4"`
+ binstruct.End `bin:"off=0x19"`
}
type Item struct {
diff --git a/pkg/btrfs/types_superblock.go b/pkg/btrfs/types_superblock.go
index 47dd3b0..a8db86c 100644
--- a/pkg/btrfs/types_superblock.go
+++ b/pkg/btrfs/types_superblock.go
@@ -10,63 +10,63 @@ import (
)
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 Generation `bin:"off=48, siz=8"`
-
- 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 ObjID `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"`
- NodeSize uint32 `bin:"off=94, siz=4"`
- LeafSize uint32 `bin:"off=98, siz=4"` // unused; must be the same as NodeSize
- StripeSize uint32 `bin:"off=9c, siz=4"`
- SysChunkArraySize uint32 `bin:"off=a0, siz=4"`
-
- ChunkRootGeneration Generation `bin:"off=a4, siz=8"`
- 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 IncompatFlags `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 btrfsitem.Dev `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 Generation `bin:"off=22b, siz=8"`
- UUIDTreeGeneration uint64 `bin:"off=233, siz=8"` // uuid_tree_generation
+ Checksum CSum `bin:"off=0x0, siz=0x20"` // Checksum of everything past this field (from 20 to 1000)
+ FSUUID UUID `bin:"off=0x20, siz=0x10"` // FS UUID
+ Self PhysicalAddr `bin:"off=0x30, siz=0x8"` // physical address of this block (different for mirrors)
+ Flags uint64 `bin:"off=0x38, siz=0x8"` // flags
+ Magic [8]byte `bin:"off=0x40, siz=0x8"` // magic ('_BHRfS_M')
+ Generation Generation `bin:"off=0x48, siz=0x8"`
+
+ RootTree LogicalAddr `bin:"off=0x50, siz=0x8"` // logical address of the root tree root
+ ChunkTree LogicalAddr `bin:"off=0x58, siz=0x8"` // logical address of the chunk tree root
+ LogTree LogicalAddr `bin:"off=0x60, siz=0x8"` // logical address of the log tree root
+
+ LogRootTransID uint64 `bin:"off=0x68, siz=0x8"` // log_root_transid
+ TotalBytes uint64 `bin:"off=0x70, siz=0x8"` // total_bytes
+ BytesUsed uint64 `bin:"off=0x78, siz=0x8"` // bytes_used
+ RootDirObjectID ObjID `bin:"off=0x80, siz=0x8"` // root_dir_objectid (usually 6)
+ NumDevices uint64 `bin:"off=0x88, siz=0x8"` // num_devices
+
+ SectorSize uint32 `bin:"off=0x90, siz=0x4"`
+ NodeSize uint32 `bin:"off=0x94, siz=0x4"`
+ LeafSize uint32 `bin:"off=0x98, siz=0x4"` // unused; must be the same as NodeSize
+ StripeSize uint32 `bin:"off=0x9c, siz=0x4"`
+ SysChunkArraySize uint32 `bin:"off=0xa0, siz=0x4"`
+
+ ChunkRootGeneration Generation `bin:"off=0xa4, siz=0x8"`
+ CompatFlags uint64 `bin:"off=0xac, siz=0x8"` // compat_flags
+ CompatROFlags uint64 `bin:"off=0xb4, siz=0x8"` // compat_ro_flags - only implementations that support the flags can write to the filesystem
+ IncompatFlags IncompatFlags `bin:"off=0xbc, siz=0x8"` // incompat_flags - only implementations that support the flags can use the filesystem
+ ChecksumType uint16 `bin:"off=0xc4, siz=0x2"` // csum_type - Btrfs currently uses the CRC32c little-endian hash function with seed -1.
+
+ RootLevel uint8 `bin:"off=0xc6, siz=0x1"` // root_level
+ ChunkLevel uint8 `bin:"off=0xc7, siz=0x1"` // chunk_root_level
+ LogLevel uint8 `bin:"off=0xc8, siz=0x1"` // log_root_level
+
+ DevItem btrfsitem.Dev `bin:"off=0xc9, siz=0x62"` // DEV_ITEM data for this device
+ Label [0x100]byte `bin:"off=0x12b, siz=0x100"` // label (may not contain '/' or '\\')
+ CacheGeneration Generation `bin:"off=0x22b, siz=0x8"`
+ UUIDTreeGeneration uint64 `bin:"off=0x233, siz=0x8"` // uuid_tree_generation
// FeatureIncompatMetadataUUID
- MetadataUUID UUID `bin:"off=23b, siz=10"`
+ MetadataUUID UUID `bin:"off=0x23b, siz=0x10"`
// FeatureIncompatExtentTreeV2
- NumGlobalRoots uint64 `bin:"off=24b, siz=8"`
+ NumGlobalRoots uint64 `bin:"off=0x24b, siz=0x8"`
// FeatureIncompatExtentTreeV2
- BlockGroupRoot LogicalAddr `bin:"off=253, siz=8"`
- BlockGroupRootGeneration Generation `bin:"off=25b, siz=8"`
- BlockGroupRootLevel uint8 `bin:"off=263, siz=1"`
+ BlockGroupRoot LogicalAddr `bin:"off=0x253, siz=0x8"`
+ BlockGroupRootGeneration Generation `bin:"off=0x25b, siz=0x8"`
+ BlockGroupRootLevel uint8 `bin:"off=0x263, siz=0x1"`
- Reserved [199]byte `bin:"off=264, siz=c7"` // future expansion
+ Reserved [199]byte `bin:"off=0x264, siz=0xc7"` // 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.
- SuperRoots [4]RootBackup `bin:"off=b2b, siz=2a0"`
+ SysChunkArray [0x800]byte `bin:"off=0x32b, siz=0x800"` // 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.
+ SuperRoots [4]RootBackup `bin:"off=0xb2b, siz=0x2a0"`
// Padded to 4096 bytes
- Padding [565]byte `bin:"off=dcb, siz=235"`
- binstruct.End `bin:"off=1000"`
+ Padding [565]byte `bin:"off=0xdcb, siz=0x235"`
+ binstruct.End `bin:"off=0x1000"`
}
func (sb Superblock) CalculateChecksum() (CSum, error) {
@@ -108,9 +108,34 @@ func (sb Superblock) EffectiveMetadataUUID() UUID {
}
type SysChunk struct {
- Key `bin:"off=0, siz=11"`
- btrfsitem.Chunk `bin:"off=11, siz=30"`
- binstruct.End `bin:"off=41"`
+ Key Key
+ Chunk btrfsitem.Chunk
+}
+
+func (sc SysChunk) MarshalBinary() ([]byte, error) {
+ dat, err := binstruct.Marshal(sc.Key)
+ if err != nil {
+ return dat, fmt.Errorf("%T.MarshalBinary: %w", sc, err)
+ }
+ _dat, err := binstruct.Marshal(sc.Chunk)
+ dat = append(dat, _dat...)
+ if err != nil {
+ return dat, fmt.Errorf("%T.MarshalBinary: %w", sc, err)
+ }
+ return dat, nil
+}
+
+func (sc *SysChunk) UnmarshalBinary(dat []byte) (int, error) {
+ n, err := binstruct.Unmarshal(dat, &sc.Key)
+ if err != nil {
+ return n, fmt.Errorf("%T.UnmarshalBinary: %w", *sc, err)
+ }
+ _n, err := binstruct.Unmarshal(dat[n:], &sc.Chunk)
+ n += _n
+ if err != nil {
+ return n, fmt.Errorf("%T.UnmarshalBinary: %w", *sc, err)
+ }
+ return n, nil
}
func (sb Superblock) ParseSysChunkArray() ([]SysChunk, error) {
@@ -123,56 +148,45 @@ func (sb Superblock) ParseSysChunkArray() ([]SysChunk, error) {
if err != nil {
return nil, err
}
-
- for i := 0; i < int(pair.Chunk.NumStripes); i++ {
- var stripe btrfsitem.ChunkStripe
- n, err := binstruct.Unmarshal(dat, &stripe)
- dat = dat[n:]
- if err != nil {
- return nil, err
- }
- pair.Chunk.Stripes = append(pair.Chunk.Stripes, stripe)
- }
-
ret = append(ret, pair)
}
return ret, nil
}
type RootBackup struct {
- TreeRoot ObjID `bin:"off=0, siz=8"`
- TreeRootGen Generation `bin:"off=8, siz=8"`
+ TreeRoot ObjID `bin:"off=0x0, siz=0x8"`
+ TreeRootGen Generation `bin:"off=0x8, siz=0x8"`
- ChunkRoot ObjID `bin:"off=10, siz=8"`
- ChunkRootGen Generation `bin:"off=18, siz=8"`
+ ChunkRoot ObjID `bin:"off=0x10, siz=0x8"`
+ ChunkRootGen Generation `bin:"off=0x18, siz=0x8"`
- ExtentRoot ObjID `bin:"off=20, siz=8"`
- ExtentRootGen Generation `bin:"off=28, siz=8"`
+ ExtentRoot ObjID `bin:"off=0x20, siz=0x8"`
+ ExtentRootGen Generation `bin:"off=0x28, siz=0x8"`
- FSRoot ObjID `bin:"off=30, siz=8"`
- FSRootGen Generation `bin:"off=38, siz=8"`
+ FSRoot ObjID `bin:"off=0x30, siz=0x8"`
+ FSRootGen Generation `bin:"off=0x38, siz=0x8"`
- DevRoot ObjID `bin:"off=40, siz=8"`
- DevRootGen Generation `bin:"off=48, siz=8"`
+ DevRoot ObjID `bin:"off=0x40, siz=0x8"`
+ DevRootGen Generation `bin:"off=0x48, siz=0x8"`
- ChecksumRoot ObjID `bin:"off=50, siz=8"`
- ChecksumRootGen Generation `bin:"off=58, siz=8"`
+ ChecksumRoot ObjID `bin:"off=0x50, siz=0x8"`
+ ChecksumRootGen Generation `bin:"off=0x58, siz=0x8"`
- TotalBytes uint64 `bin:"off=60, siz=8"`
- BytesUsed uint64 `bin:"off=68, siz=8"`
- NumDevices uint64 `bin:"off=70, siz=8"`
+ TotalBytes uint64 `bin:"off=0x60, siz=0x8"`
+ BytesUsed uint64 `bin:"off=0x68, siz=0x8"`
+ NumDevices uint64 `bin:"off=0x70, siz=0x8"`
- Unused [8 * 4]byte `bin:"off=78, siz=20"`
+ Unused [8 * 4]byte `bin:"off=0x78, siz=0x20"`
- TreeRootLevel uint8 `bin:"off=98, siz=1"`
- ChunkRootLevel uint8 `bin:"off=99, siz=1"`
- ExtentRootLevel uint8 `bin:"off=9a, siz=1"`
- FSRootLevel uint8 `bin:"off=9b, siz=1"`
- DevRootLevel uint8 `bin:"off=9c, siz=1"`
- ChecksumRootLevel uint8 `bin:"off=9d, siz=1"`
+ TreeRootLevel uint8 `bin:"off=0x98, siz=0x1"`
+ ChunkRootLevel uint8 `bin:"off=0x99, siz=0x1"`
+ ExtentRootLevel uint8 `bin:"off=0x9a, siz=0x1"`
+ FSRootLevel uint8 `bin:"off=0x9b, siz=0x1"`
+ DevRootLevel uint8 `bin:"off=0x9c, siz=0x1"`
+ ChecksumRootLevel uint8 `bin:"off=0x9d, siz=0x1"`
- Padding [10]byte `bin:"off=9e, siz=a"`
- binstruct.End `bin:"off=a8"`
+ Padding [10]byte `bin:"off=0x9e, siz=0xa"`
+ binstruct.End `bin:"off=0xa8"`
}
type IncompatFlags uint64