diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-04 17:29:23 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-04 17:29:23 -0600 |
commit | 95f1e4c2010fe8fd2a5537904f99082afbd20bf6 (patch) | |
tree | 4169933b8e5736d97bfbd48aba1747737589d13d /pkg/btrfs | |
parent | 10605d5b5109bd796fb456e0a6b91f64e278a00c (diff) |
more
Diffstat (limited to 'pkg/btrfs')
-rw-r--r-- | pkg/btrfs/btrfsitem/item_dir.go | 104 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_empty.go | 2 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_extent.go | 132 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_extentdataref.go | 14 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_inode.go | 38 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_metadata.go | 44 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_root.go | 4 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_shareddataref.go | 10 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/items.txt | 9 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/items_gen.go | 43 | ||||
-rw-r--r-- | pkg/btrfs/internal/itemtype.go | 18 |
11 files changed, 404 insertions, 14 deletions
diff --git a/pkg/btrfs/btrfsitem/item_dir.go b/pkg/btrfs/btrfsitem/item_dir.go new file mode 100644 index 0000000..2e0529e --- /dev/null +++ b/pkg/btrfs/btrfsitem/item_dir.go @@ -0,0 +1,104 @@ +package btrfsitem + +import ( + "fmt" + + "lukeshu.com/btrfs-tools/pkg/binstruct" + "lukeshu.com/btrfs-tools/pkg/btrfs/internal" +) + +type DirList []Dir // DIR_ITEM=84, DIR_INDEX=96, XATTR_ITEM=24 + +func (o *DirList) UnmarshalBinary(dat []byte) (int, error) { + n := 0 + for n < len(dat) { + var ref Dir + _n, err := binstruct.Unmarshal(dat, &ref) + n += _n + if err != nil { + return n, err + } + *o = append(*o, ref) + } + return n, nil +} + +func (o DirList) MarshalBinary() ([]byte, error) { + var ret []byte + for _, ref := range o { + bs, err := binstruct.Marshal(ref) + ret = append(ret, bs...) + if err != nil { + return ret, err + } + } + return ret, nil +} + +type Dir struct { + Location internal.Key `bin:"off=0x0, siz=0x11"` + TransID int64 `bin:"off=0x11, siz=8"` + DataLen uint16 `bin:"off=0x19, siz=2"` + NameLen uint16 `bin:"off=0x1b, siz=2"` + Type FileType `bin:"off=0x1d, siz=1"` + binstruct.End `bin:"off=0x1e"` + Data []byte `bin:"-"` + Name []byte `bin:"-"` +} + +func (o *Dir) UnmarshalBinary(dat []byte) (int, error) { + n, err := binstruct.UnmarshalWithoutInterface(dat, o) + if err != nil { + return n, err + } + o.Data = dat[n : n+int(o.DataLen)] + n += int(o.DataLen) + o.Name = dat[n : n+int(o.NameLen)] + n += int(o.NameLen) + return n, nil +} + +func (o Dir) MarshalBinary() ([]byte, error) { + o.DataLen = uint16(len(o.Data)) + o.NameLen = uint16(len(o.Name)) + dat, err := binstruct.MarshalWithoutInterface(o) + if err != nil { + return dat, err + } + dat = append(dat, o.Data...) + dat = append(dat, o.Name...) + return dat, nil +} + +type FileType uint8 + +const ( + BTRFS_FT_UNKNOWN = FileType(0) + BTRFS_FT_REG_FILE = FileType(1) + BTRFS_FT_DIR = FileType(2) + BTRFS_FT_CHRDEV = FileType(3) + BTRFS_FT_BLKDEV = FileType(4) + BTRFS_FT_FIFO = FileType(5) + BTRFS_FT_SOCK = FileType(6) + BTRFS_FT_SYMLINK = FileType(7) + BTRFS_FT_XATTR = FileType(8) + BTRFS_FT_MAX = FileType(9) +) + +func (ft FileType) String() string { + names := map[FileType]string{ + BTRFS_FT_UNKNOWN: "UNKNOWN", + BTRFS_FT_REG_FILE: "REG_FILE", + BTRFS_FT_DIR: "DIR", + BTRFS_FT_CHRDEV: "CHRDEV", + BTRFS_FT_BLKDEV: "BLKDEV", + BTRFS_FT_FIFO: "FIFO", + BTRFS_FT_SOCK: "SOCK", + BTRFS_FT_SYMLINK: "SYMLINK", + BTRFS_FT_XATTR: "XATTR", + } + if name, ok := names[ft]; ok { + return name + } + return fmt.Sprintf("DIR_ITEM.%d", uint8(ft)) +} diff --git a/pkg/btrfs/btrfsitem/item_empty.go b/pkg/btrfs/btrfsitem/item_empty.go index fe7ae90..5a26104 100644 --- a/pkg/btrfs/btrfsitem/item_empty.go +++ b/pkg/btrfs/btrfsitem/item_empty.go @@ -4,6 +4,6 @@ import ( "lukeshu.com/btrfs-tools/pkg/binstruct" ) -type Empty struct { // UNTYPED=0, QGROUP_RELATION=246 +type Empty struct { // UNTYPED=0, TREE_BLOCK_REF=176, SHARED_BLOCK_REF=182, QGROUP_RELATION=246 binstruct.End `bin:"off=0"` } diff --git a/pkg/btrfs/btrfsitem/item_extent.go b/pkg/btrfs/btrfsitem/item_extent.go new file mode 100644 index 0000000..7d3eb05 --- /dev/null +++ b/pkg/btrfs/btrfsitem/item_extent.go @@ -0,0 +1,132 @@ +package btrfsitem + +import ( + "fmt" + + "lukeshu.com/btrfs-tools/pkg/binstruct" + "lukeshu.com/btrfs-tools/pkg/btrfs/internal" + "lukeshu.com/btrfs-tools/pkg/util" +) + +type Extent struct { // EXTENT_ITEM=168 + Head ExtentHeader + Info TreeBlockInfo // only if .Head.Flags.Has(BTRFS_EXTENT_FLAG_TREE_BLOCK) + Refs []ExtentInlineRef +} + +func (o *Extent) UnmarshalBinary(dat []byte) (int, error) { + n, err := binstruct.Unmarshal(dat, &o.Head) + if err != nil { + return n, err + } + if o.Head.Flags.Has(BTRFS_EXTENT_FLAG_TREE_BLOCK) { + _n, err := binstruct.Unmarshal(dat[n:], &o.Info) + n += _n + if err != nil { + return n, err + } + } + o.Refs = nil + for n < len(dat) { + var ref ExtentInlineRef + _n, err := binstruct.Unmarshal(dat[n:], &ref) + n += _n + o.Refs = append(o.Refs, ref) + if err != nil { + return n, err + } + } + return n, nil +} + +func (o Extent) MarshalBinary() ([]byte, error) { + dat, err := binstruct.Marshal(o.Head) + if err != nil { + return dat, err + } + if o.Head.Flags.Has(BTRFS_EXTENT_FLAG_TREE_BLOCK) { + bs, err := binstruct.Marshal(o.Info) + dat = append(dat, bs...) + if err != nil { + return dat, err + } + } + for _, ref := range o.Refs { + bs, err := binstruct.Marshal(ref) + dat = append(dat, bs...) + if err != nil { + return dat, err + } + } + return dat, nil +} + +type ExtentHeader struct { + Refs int64 `bin:"off=0, siz=8"` + Generation int64 `bin:"off=8, siz=8"` + Flags ExtentFlags `bin:"off=16, siz=8"` + binstruct.End `bin:"off=24"` +} + +type TreeBlockInfo struct { + Key internal.Key `bin:"off=0, siz=0x11"` + Level uint8 `bin:"off=0x11, siz=0x8"` + binstruct.End `bin:"off=0x19"` +} + +type ExtentFlags uint64 + +const ( + BTRFS_EXTENT_FLAG_DATA = ExtentFlags(1 << iota) + BTRFS_EXTENT_FLAG_TREE_BLOCK +) + +var extentFlagNames = []string{ + "DATA", + "TREE_BLOCK", +} + +func (f ExtentFlags) Has(req ExtentFlags) bool { return f&req == req } +func (f ExtentFlags) String() string { return util.BitfieldString(f, extentFlagNames) } + +type ExtentInlineRef struct { + Type Type `bin:"off=0, siz=1"` + Offset uint64 `bin:"off=1, siz=8"` + binstruct.End `bin:"off=9"` + Body Item `bin:"-"` +} + +func (o *ExtentInlineRef) UnmarshalBinary(dat []byte) (int, error) { + n, err := binstruct.UnmarshalWithoutInterface(dat, o) + if err != nil { + return n, err + } + switch o.Type { + case TREE_BLOCK_REF_KEY, SHARED_BLOCK_REF_KEY: + o.Body = Empty{} + case EXTENT_DATA_REF_KEY: + return n, fmt.Errorf("the C code to do this doesn't make any sense") + case SHARED_DATA_REF_KEY: + var sref SharedDataRef + _n, err := binstruct.Unmarshal(dat[n:], &sref) + n += _n + o.Body = sref + if err != nil { + return n, err + } + } + return n, nil +} + +func (o ExtentInlineRef) MarshalBinary() ([]byte, error) { + dat, err := binstruct.MarshalWithoutInterface(o) + if err != nil { + return dat, err + } + bs, err := binstruct.Marshal(o.Body) + dat = append(dat, bs...) + if err != nil { + return dat, err + } + return dat, nil +} diff --git a/pkg/btrfs/btrfsitem/item_extentdataref.go b/pkg/btrfs/btrfsitem/item_extentdataref.go new file mode 100644 index 0000000..c898b72 --- /dev/null +++ b/pkg/btrfs/btrfsitem/item_extentdataref.go @@ -0,0 +1,14 @@ +package btrfsitem + +import ( + "lukeshu.com/btrfs-tools/pkg/binstruct" + "lukeshu.com/btrfs-tools/pkg/btrfs/internal" +) + +type ExtentDataRef struct { // EXTENT_DATA_REF=178 + Root int64 `bin:"off=0, siz=8"` + ObjectID internal.ObjID `bin:"off=8, siz=8"` + Offset int64 `bin:"off=16, siz=8"` + Count int32 `bin:"off=24, siz=4"` + binstruct.End `bin:"off=28"` +} diff --git a/pkg/btrfs/btrfsitem/item_inode.go b/pkg/btrfs/btrfsitem/item_inode.go index 4d38380..175b900 100644 --- a/pkg/btrfs/btrfsitem/item_inode.go +++ b/pkg/btrfs/btrfsitem/item_inode.go @@ -3,6 +3,7 @@ package btrfsitem import ( "lukeshu.com/btrfs-tools/pkg/binstruct" "lukeshu.com/btrfs-tools/pkg/btrfs/internal" + "lukeshu.com/btrfs-tools/pkg/util" ) type Inode struct { // INODE_ITEM=1 @@ -16,7 +17,7 @@ type Inode struct { // INODE_ITEM=1 GID int32 `bin:"off=0x30, siz=0x4"` Mode int32 `bin:"off=0x34, siz=0x4"` RDev int64 `bin:"off=0x38, siz=0x8"` - Flags uint64 `bin:"off=0x40, siz=0x8"` + Flags InodeFlags `bin:"off=0x40, siz=0x8"` Sequence int64 `bin:"off=0x48, siz=0x8"` Reserved [4]int64 `bin:"off=0x50, siz=0x20"` ATime internal.Time `bin:"off=0x70, siz=0xc"` @@ -25,3 +26,38 @@ type Inode struct { // INODE_ITEM=1 OTime internal.Time `bin:"off=0x94, siz=0xc"` binstruct.End `bin:"off=0xa0"` } + +type InodeFlags uint64 + +const ( + BTRFS_INODE_NODATASUM = InodeFlags(1 << iota) + BTRFS_INODE_NODATACOW + BTRFS_INODE_READONLY + BTRFS_INODE_NOCOMPRESS + BTRFS_INODE_PREALLOC + BTRFS_INODE_SYNC + BTRFS_INODE_IMMUTABLE + BTRFS_INODE_APPEND + BTRFS_INODE_NODUMP + BTRFS_INODE_NOATIME + BTRFS_INODE_DIRSYNC + BTRFS_INODE_COMPRESS +) + +var inodeFlagNames = []string{ + "NODATASUM", + "NODATACOW", + "READONLY", + "NOCOMPRESS", + "PREALLOC", + "SYNC", + "IMMUTABLE", + "APPEND", + "NODUMP", + "NOATIME", + "DIRSYNC", + "COMPRESS", +} + +func (f InodeFlags) Has(req InodeFlags) bool { return f&req == req } +func (f InodeFlags) String() string { return util.BitfieldString(f, inodeFlagNames) } diff --git a/pkg/btrfs/btrfsitem/item_metadata.go b/pkg/btrfs/btrfsitem/item_metadata.go new file mode 100644 index 0000000..7bfe677 --- /dev/null +++ b/pkg/btrfs/btrfsitem/item_metadata.go @@ -0,0 +1,44 @@ +package btrfsitem + +import ( + "lukeshu.com/btrfs-tools/pkg/binstruct" +) + +// Metadata is like Extent, but doesn't have .Info. +type Metadata struct { // METADATA_ITEM=169 + Head ExtentHeader + Refs []ExtentInlineRef +} + +func (o *Metadata) UnmarshalBinary(dat []byte) (int, error) { + n, err := binstruct.Unmarshal(dat, &o.Head) + if err != nil { + return n, err + } + o.Refs = nil + for n < len(dat) { + var ref ExtentInlineRef + _n, err := binstruct.Unmarshal(dat[n:], &ref) + n += _n + o.Refs = append(o.Refs, ref) + if err != nil { + return n, err + } + } + return n, nil +} + +func (o Metadata) MarshalBinary() ([]byte, error) { + dat, err := binstruct.Marshal(o.Head) + if err != nil { + return dat, err + } + for _, ref := range o.Refs { + bs, err := binstruct.Marshal(ref) + dat = append(dat, bs...) + if err != nil { + return dat, err + } + } + return dat, nil +} diff --git a/pkg/btrfs/btrfsitem/item_root.go b/pkg/btrfs/btrfsitem/item_root.go index a7867e8..9dd43f8 100644 --- a/pkg/btrfs/btrfsitem/item_root.go +++ b/pkg/btrfs/btrfsitem/item_root.go @@ -42,9 +42,9 @@ const ( BTRFS_ROOT_SUBVOL_RDONLY = RootFlags(1 << iota) ) -var rootItemFlagNames = []string{ +var rootFlagNames = []string{ "SUBVOL_RDONLY", } func (f RootFlags) Has(req RootFlags) bool { return f&req == req } -func (f RootFlags) String() string { return util.BitfieldString(f, rootItemFlagNames) } +func (f RootFlags) String() string { return util.BitfieldString(f, rootFlagNames) } diff --git a/pkg/btrfs/btrfsitem/item_shareddataref.go b/pkg/btrfs/btrfsitem/item_shareddataref.go new file mode 100644 index 0000000..0d73231 --- /dev/null +++ b/pkg/btrfs/btrfsitem/item_shareddataref.go @@ -0,0 +1,10 @@ +package btrfsitem + +import ( + "lukeshu.com/btrfs-tools/pkg/binstruct" +) + +type SharedDataRef struct { // SHARED_DATA_REF=184 + Count int32 `bin:"off=0, siz=4"` + binstruct.End `bin:"off=4"` +} diff --git a/pkg/btrfs/btrfsitem/items.txt b/pkg/btrfs/btrfsitem/items.txt index f38af3f..0cca6df 100644 --- a/pkg/btrfs/btrfsitem/items.txt +++ b/pkg/btrfs/btrfsitem/items.txt @@ -1,12 +1,21 @@ CHUNK_ITEM=228 Chunk DEV_ITEM=216 Dev DEV_EXTENT=204 DevExtent +DIR_ITEM=84, DirList +DIR_INDEX=96, DirList +XATTR_ITEM=24 DirList UNTYPED=0, Empty +TREE_BLOCK_REF=176, Empty +SHARED_BLOCK_REF=182, Empty QGROUP_RELATION=246 Empty +EXTENT_ITEM=168 Extent +EXTENT_DATA_REF=178 ExtentDataRef INODE_ITEM=1 Inode INODE_REF=12 InodeRefList +METADATA_ITEM=169 Metadata ORPHAN_ITEM=48 Orphan PERSISTENT_ITEM=249 DevStats ROOT_ITEM=132 Root +SHARED_DATA_REF=184 SharedDataRef UUID_SUBVOL=251 UUIDMap UUID_RECEIVED_SUBVOL=252 UUIDMap diff --git a/pkg/btrfs/btrfsitem/items_gen.go b/pkg/btrfs/btrfsitem/items_gen.go index 63a5ac1..03faf8a 100644 --- a/pkg/btrfs/btrfsitem/items_gen.go +++ b/pkg/btrfs/btrfsitem/items_gen.go @@ -10,13 +10,22 @@ const ( CHUNK_ITEM_KEY = internal.CHUNK_ITEM_KEY DEV_ITEM_KEY = internal.DEV_ITEM_KEY DEV_EXTENT_KEY = internal.DEV_EXTENT_KEY + DIR_ITEM_KEY = internal.DIR_ITEM_KEY + DIR_INDEX_KEY = internal.DIR_INDEX_KEY + XATTR_ITEM_KEY = internal.XATTR_ITEM_KEY UNTYPED_KEY = internal.UNTYPED_KEY + TREE_BLOCK_REF_KEY = internal.TREE_BLOCK_REF_KEY + SHARED_BLOCK_REF_KEY = internal.SHARED_BLOCK_REF_KEY QGROUP_RELATION_KEY = internal.QGROUP_RELATION_KEY + EXTENT_ITEM_KEY = internal.EXTENT_ITEM_KEY + EXTENT_DATA_REF_KEY = internal.EXTENT_DATA_REF_KEY INODE_ITEM_KEY = internal.INODE_ITEM_KEY INODE_REF_KEY = internal.INODE_REF_KEY + METADATA_ITEM_KEY = internal.METADATA_ITEM_KEY ORPHAN_ITEM_KEY = internal.ORPHAN_ITEM_KEY PERSISTENT_ITEM_KEY = internal.PERSISTENT_ITEM_KEY ROOT_ITEM_KEY = internal.ROOT_ITEM_KEY + SHARED_DATA_REF_KEY = internal.SHARED_DATA_REF_KEY UUID_SUBVOL_KEY = internal.UUID_SUBVOL_KEY UUID_RECEIVED_SUBVOL_KEY = internal.UUID_RECEIVED_SUBVOL_KEY ) @@ -25,24 +34,38 @@ var keytype2gotype = map[Type]reflect.Type{ CHUNK_ITEM_KEY: reflect.TypeOf(Chunk{}), DEV_ITEM_KEY: reflect.TypeOf(Dev{}), DEV_EXTENT_KEY: reflect.TypeOf(DevExtent{}), + DIR_ITEM_KEY: reflect.TypeOf(DirList{}), + DIR_INDEX_KEY: reflect.TypeOf(DirList{}), + XATTR_ITEM_KEY: reflect.TypeOf(DirList{}), UNTYPED_KEY: reflect.TypeOf(Empty{}), + TREE_BLOCK_REF_KEY: reflect.TypeOf(Empty{}), + SHARED_BLOCK_REF_KEY: reflect.TypeOf(Empty{}), QGROUP_RELATION_KEY: reflect.TypeOf(Empty{}), + EXTENT_ITEM_KEY: reflect.TypeOf(Extent{}), + EXTENT_DATA_REF_KEY: reflect.TypeOf(ExtentDataRef{}), INODE_ITEM_KEY: reflect.TypeOf(Inode{}), INODE_REF_KEY: reflect.TypeOf(InodeRefList{}), + METADATA_ITEM_KEY: reflect.TypeOf(Metadata{}), ORPHAN_ITEM_KEY: reflect.TypeOf(Orphan{}), PERSISTENT_ITEM_KEY: reflect.TypeOf(DevStats{}), ROOT_ITEM_KEY: reflect.TypeOf(Root{}), + SHARED_DATA_REF_KEY: reflect.TypeOf(SharedDataRef{}), UUID_SUBVOL_KEY: reflect.TypeOf(UUIDMap{}), UUID_RECEIVED_SUBVOL_KEY: reflect.TypeOf(UUIDMap{}), } -func (Chunk) isItem() {} -func (Dev) isItem() {} -func (DevExtent) isItem() {} -func (DevStats) isItem() {} -func (Empty) isItem() {} -func (Inode) isItem() {} -func (InodeRefList) isItem() {} -func (Orphan) isItem() {} -func (Root) isItem() {} -func (UUIDMap) isItem() {} +func (Chunk) isItem() {} +func (Dev) isItem() {} +func (DevExtent) isItem() {} +func (DevStats) isItem() {} +func (DirList) isItem() {} +func (Empty) isItem() {} +func (Extent) isItem() {} +func (ExtentDataRef) isItem() {} +func (Inode) isItem() {} +func (InodeRefList) isItem() {} +func (Metadata) isItem() {} +func (Orphan) isItem() {} +func (Root) isItem() {} +func (SharedDataRef) isItem() {} +func (UUIDMap) isItem() {} diff --git a/pkg/btrfs/internal/itemtype.go b/pkg/btrfs/internal/itemtype.go index d780b60..90fb2a7 100644 --- a/pkg/btrfs/internal/itemtype.go +++ b/pkg/btrfs/internal/itemtype.go @@ -8,13 +8,22 @@ const ( CHUNK_ITEM_KEY = ItemType(228) DEV_ITEM_KEY = ItemType(216) DEV_EXTENT_KEY = ItemType(204) + DIR_ITEM_KEY = ItemType(84) + DIR_INDEX_KEY = ItemType(96) + XATTR_ITEM_KEY = ItemType(24) UNTYPED_KEY = ItemType(0) + TREE_BLOCK_REF_KEY = ItemType(176) + SHARED_BLOCK_REF_KEY = ItemType(182) QGROUP_RELATION_KEY = ItemType(246) + EXTENT_ITEM_KEY = ItemType(168) + EXTENT_DATA_REF_KEY = ItemType(178) INODE_ITEM_KEY = ItemType(1) INODE_REF_KEY = ItemType(12) + METADATA_ITEM_KEY = ItemType(169) ORPHAN_ITEM_KEY = ItemType(48) PERSISTENT_ITEM_KEY = ItemType(249) ROOT_ITEM_KEY = ItemType(132) + SHARED_DATA_REF_KEY = ItemType(184) UUID_SUBVOL_KEY = ItemType(251) UUID_RECEIVED_SUBVOL_KEY = ItemType(252) ) @@ -24,13 +33,22 @@ func (t ItemType) String() string { CHUNK_ITEM_KEY: "CHUNK_ITEM", DEV_ITEM_KEY: "DEV_ITEM", DEV_EXTENT_KEY: "DEV_EXTENT", + DIR_ITEM_KEY: "DIR_ITEM", + DIR_INDEX_KEY: "DIR_INDEX", + XATTR_ITEM_KEY: "XATTR_ITEM", UNTYPED_KEY: "UNTYPED", + TREE_BLOCK_REF_KEY: "TREE_BLOCK_REF", + SHARED_BLOCK_REF_KEY: "SHARED_BLOCK_REF", QGROUP_RELATION_KEY: "QGROUP_RELATION", + EXTENT_ITEM_KEY: "EXTENT_ITEM", + EXTENT_DATA_REF_KEY: "EXTENT_DATA_REF", INODE_ITEM_KEY: "INODE_ITEM", INODE_REF_KEY: "INODE_REF", + METADATA_ITEM_KEY: "METADATA_ITEM", ORPHAN_ITEM_KEY: "ORPHAN_ITEM", PERSISTENT_ITEM_KEY: "PERSISTENT_ITEM", ROOT_ITEM_KEY: "ROOT_ITEM", + SHARED_DATA_REF_KEY: "SHARED_DATA_REF", UUID_SUBVOL_KEY: "UUID_SUBVOL", UUID_RECEIVED_SUBVOL_KEY: "UUID_RECEIVED_SUBVOL", } |