summaryrefslogtreecommitdiff
path: root/lib/btrfs/types_superblock.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/btrfs/types_superblock.go')
-rw-r--r--lib/btrfs/types_superblock.go233
1 files changed, 233 insertions, 0 deletions
diff --git a/lib/btrfs/types_superblock.go b/lib/btrfs/types_superblock.go
new file mode 100644
index 0000000..373de48
--- /dev/null
+++ b/lib/btrfs/types_superblock.go
@@ -0,0 +1,233 @@
+package btrfs
+
+import (
+ "fmt"
+ "reflect"
+
+ "git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
+ "git.lukeshu.com/btrfs-progs-ng/lib/util"
+)
+
+type Superblock struct {
+ Checksum btrfssum.CSum `bin:"off=0x0, siz=0x20"` // Checksum of everything past this field (from 0x20 to 0x1000)
+ FSUUID UUID `bin:"off=0x20, siz=0x10"` // FS UUID
+ Self btrfsvol.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 btrfsvol.LogicalAddr `bin:"off=0x50, siz=0x8"` // logical address of the root tree root
+ ChunkTree btrfsvol.LogicalAddr `bin:"off=0x58, siz=0x8"` // logical address of the chunk tree root
+ LogTree btrfsvol.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 btrfssum.CSumType `bin:"off=0xc4, siz=0x2"`
+
+ 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 Generation `bin:"off=0x233, siz=0x8"`
+
+ // FeatureIncompatMetadataUUID
+ MetadataUUID UUID `bin:"off=0x23b, siz=0x10"`
+
+ // FeatureIncompatExtentTreeV2
+ NumGlobalRoots uint64 `bin:"off=0x24b, siz=0x8"`
+
+ // FeatureIncompatExtentTreeV2
+ BlockGroupRoot btrfsvol.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=0x264, siz=0xc7"` // future expansion
+
+ 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=0xdcb, siz=0x235"`
+ binstruct.End `bin:"off=0x1000"`
+}
+
+func (sb Superblock) CalculateChecksum() (btrfssum.CSum, error) {
+ data, err := binstruct.Marshal(sb)
+ if err != nil {
+ return btrfssum.CSum{}, err
+ }
+ return sb.ChecksumType.Sum(data[binstruct.StaticSize(btrfssum.CSum{}):])
+}
+
+func (sb Superblock) ValidateChecksum() error {
+ stored := sb.Checksum
+ calced, err := sb.CalculateChecksum()
+ if err != nil {
+ return err
+ }
+ if calced != stored {
+ return fmt.Errorf("superblock checksum mismatch: stored=%v calculated=%v",
+ stored, calced)
+ }
+ return nil
+}
+
+func (a Superblock) Equal(b Superblock) bool {
+ a.Checksum = btrfssum.CSum{}
+ a.Self = 0
+
+ b.Checksum = btrfssum.CSum{}
+ b.Self = 0
+
+ return reflect.DeepEqual(a, b)
+}
+
+func (sb Superblock) EffectiveMetadataUUID() UUID {
+ if !sb.IncompatFlags.Has(FeatureIncompatMetadataUUID) {
+ return sb.FSUUID
+ }
+ return sb.MetadataUUID
+}
+
+type SysChunk struct {
+ 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) {
+ dat := sb.SysChunkArray[:sb.SysChunkArraySize]
+ var ret []SysChunk
+ for len(dat) > 0 {
+ var pair SysChunk
+ n, err := binstruct.Unmarshal(dat, &pair)
+ dat = dat[n:]
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, pair)
+ }
+ return ret, nil
+}
+
+type RootBackup struct {
+ TreeRoot ObjID `bin:"off=0x0, siz=0x8"`
+ TreeRootGen Generation `bin:"off=0x8, siz=0x8"`
+
+ ChunkRoot ObjID `bin:"off=0x10, siz=0x8"`
+ ChunkRootGen Generation `bin:"off=0x18, siz=0x8"`
+
+ ExtentRoot ObjID `bin:"off=0x20, siz=0x8"`
+ ExtentRootGen Generation `bin:"off=0x28, siz=0x8"`
+
+ FSRoot ObjID `bin:"off=0x30, siz=0x8"`
+ FSRootGen Generation `bin:"off=0x38, siz=0x8"`
+
+ DevRoot ObjID `bin:"off=0x40, siz=0x8"`
+ DevRootGen Generation `bin:"off=0x48, siz=0x8"`
+
+ ChecksumRoot ObjID `bin:"off=0x50, siz=0x8"`
+ ChecksumRootGen Generation `bin:"off=0x58, siz=0x8"`
+
+ 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=0x78, siz=0x20"`
+
+ 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=0x9e, siz=0xa"`
+ binstruct.End `bin:"off=0xa8"`
+}
+
+type IncompatFlags uint64
+
+const (
+ FeatureIncompatMixedBackref = IncompatFlags(1 << iota)
+ FeatureIncompatDefaultSubvol
+ FeatureIncompatMixedGroups
+ FeatureIncompatCompressLZO
+ FeatureIncompatCompressZSTD
+ FeatureIncompatBigMetadata // buggy
+ FeatureIncompatExtendedIRef
+ FeatureIncompatRAID56
+ FeatureIncompatSkinnyMetadata
+ FeatureIncompatNoHoles
+ FeatureIncompatMetadataUUID
+ FeatureIncompatRAID1C34
+ FeatureIncompatZoned
+ FeatureIncompatExtentTreeV2
+)
+
+var incompatFlagNames = []string{
+ "FeatureIncompatMixedBackref",
+ "FeatureIncompatDefaultSubvol",
+ "FeatureIncompatMixedGroups",
+ "FeatureIncompatCompressLZO",
+ "FeatureIncompatCompressZSTD",
+ "FeatureIncompatBigMetadata ",
+ "FeatureIncompatExtendedIRef",
+ "FeatureIncompatRAID56",
+ "FeatureIncompatSkinnyMetadata",
+ "FeatureIncompatNoHoles",
+ "FeatureIncompatMetadataUUID",
+ "FeatureIncompatRAID1C34",
+ "FeatureIncompatZoned",
+ "FeatureIncompatExtentTreeV2",
+}
+
+func (f IncompatFlags) Has(req IncompatFlags) bool { return f&req == req }
+func (f IncompatFlags) String() string {
+ return util.BitfieldString(f, incompatFlagNames, util.HexLower)
+}