diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-01 02:41:36 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-01 02:41:36 -0600 |
commit | cf314d3f1f96e2c07b68a7171e27f58c899bcdbb (patch) | |
tree | 85a3e4769700d054a5deaccc71c691645e029b09 /pkg | |
parent | d6243eb7afd5d9d91686bce2e02c252be456b38c (diff) |
fix
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/binstruct/structs.go | 6 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_chunk.go | 11 | ||||
-rw-r--r-- | pkg/btrfs/internal/misc.go | 14 | ||||
-rw-r--r-- | pkg/btrfs/io2_fs.go | 4 | ||||
-rw-r--r-- | pkg/btrfs/types_btree.go | 16 | ||||
-rw-r--r-- | pkg/btrfs/types_superblock.go | 184 |
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 |