diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-05-26 02:08:58 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-05-26 02:08:58 -0600 |
commit | 04d6677e52352a7e3ec791e3e817cfe3865e7d6d (patch) | |
tree | b6184f86084cf61cf5066b3c42b9a32e5455e9df | |
parent | f11acf5f5a8c72af59712cf3cda62c47d1a80e5d (diff) |
more
-rw-r--r-- | cmd/btrfs-dump-tree/main.go | 128 | ||||
-rw-r--r-- | pkg/btrfs/types_bitfields.go | 16 | ||||
-rw-r--r-- | pkg/btrfs/types_item.go | 86 | ||||
-rw-r--r-- | pkg/btrfs/types_objid.go | 10 | ||||
-rw-r--r-- | pkg/btrfs/types_structs.go | 25 |
5 files changed, 231 insertions, 34 deletions
diff --git a/cmd/btrfs-dump-tree/main.go b/cmd/btrfs-dump-tree/main.go index 7dac40e..ca9d527 100644 --- a/cmd/btrfs-dump-tree/main.go +++ b/cmd/btrfs-dump-tree/main.go @@ -5,6 +5,7 @@ import ( "os" "strings" + "lukeshu.com/btrfs-tools/pkg/binstruct" "lukeshu.com/btrfs-tools/pkg/btrfs" ) @@ -79,7 +80,15 @@ func printTree(fs *btrfs.FS, root btrfs.LogicalAddr) { printHeaderInfo(node) switch node := node.(type) { case *btrfs.InternalNode: - // TODO + for _, item := range node.Body { + fmt.Printf("\t%s block %d gen %d\n", + fmtKey(item.Data.Key), + item.Data.BlockPtr, + item.Data.Generation) + } + for _, item := range node.Body { + printTree(fs, item.Data.BlockPtr) + } case *btrfs.LeafNode: for i, item := range node.Body { fmt.Printf("\titem %d %s itemoff %d itemsize %d\n", @@ -87,6 +96,112 @@ func printTree(fs *btrfs.FS, root btrfs.LogicalAddr) { fmtKey(item.Data.Key), item.Data.DataOffset, item.Data.DataSize) + switch item.Data.Key.ItemType { + case btrfs.BTRFS_UNTYPED_KEY: + // TODO + case btrfs.BTRFS_INODE_ITEM_KEY: + // TODO(!) + case btrfs.BTRFS_INODE_REF_KEY: + dat := item.Data.Data.Data + for len(dat) > 0 { + var ref btrfs.InodeRefItem + if err := binstruct.Unmarshal(dat, &ref); err != nil { + fmt.Printf("error: %v\n", err) + return + } + dat = dat[0xA:] + ref.Name = dat[:ref.NameLen] + dat = dat[ref.NameLen:] + + fmt.Printf("\t\tindex %d namelen %d name: %s\n", + ref.Index, ref.NameLen, ref.Name) + } + case btrfs.BTRFS_INODE_EXTREF_KEY: + // TODO + case btrfs.BTRFS_DIR_ITEM_KEY, btrfs.BTRFS_DIR_INDEX_KEY, btrfs.BTRFS_XATTR_ITEM_KEY: + // TODO + case btrfs.BTRFS_DIR_LOG_INDEX_KEY, btrfs.BTRFS_DIR_LOG_ITEM_KEY: + // TODO + case btrfs.BTRFS_ORPHAN_ITEM_KEY: + fmt.Printf("\t\torphan item\n") + case btrfs.BTRFS_ROOT_ITEM_KEY: + var obj btrfs.RootItem + if err := binstruct.Unmarshal(item.Data.Data.Data, &obj); err != nil { + fmt.Printf("error: %v\n", err) + return + } + fmt.Printf("\t\tgeneration %d root_dirid %d bytenr %d byte_limit %d bytes_used %d\n", + obj.Generation, obj.RootDirID, obj.ByteNr, obj.ByteLimit, obj.BytesUsed) + fmt.Printf("\t\tlast_snapshot %d flags %s refs %d\n", + obj.LastSnapshot, obj.Flags, obj.Refs) + fmt.Printf("\t\tdrop_progress %s drop_level %d\n", + fmtKey(obj.DropProgress), obj.DropLevel) + fmt.Printf("\t\tlevel %d generation_v2 %d\n", + obj.Level, obj.GenerationV2) + if obj.Generation == obj.GenerationV2 { + fmt.Printf("\t\tuuid %s\n", obj.UUID) + fmt.Printf("\t\tparent_uuid %s\n", obj.ParentUUID) + fmt.Printf("\t\treceived_uuid %s\n", obj.ReceivedUUID) + fmt.Printf("\t\tctransid %d otransid %d stransid %d rtransid %d\n", + obj.CTransID, obj.OTransID, obj.STransID, obj.RTransID) + fmt.Printf("\t\tctime %s\n", fmtTime(obj.CTime)) + fmt.Printf("\t\totime %s\n", fmtTime(obj.OTime)) + fmt.Printf("\t\tstime %s\n", fmtTime(obj.STime)) + fmt.Printf("\t\trtime %s\n", fmtTime(obj.RTime)) + } + case btrfs.BTRFS_ROOT_REF_KEY: + // TODO + case btrfs.BTRFS_ROOT_BACKREF_KEY: + // TODO + case btrfs.BTRFS_EXTENT_ITEM_KEY: + // TODO + case btrfs.BTRFS_METADATA_ITEM_KEY: + // TODO + case btrfs.BTRFS_TREE_BLOCK_REF_KEY: + fmt.Printf("\t\ttree block backref\n") + case btrfs.BTRFS_SHARED_BLOCK_REF_KEY: + fmt.Printf("\t\tshared block backref\n") + case btrfs.BTRFS_EXTENT_DATA_REF_KEY: + // TODO + case btrfs.BTRFS_SHARED_DATA_REF_KEY: + // TODO + case btrfs.BTRFS_EXTENT_REF_V0_KEY: + fmt.Printf("\t\textent ref v0 (deprecated)\n") + case btrfs.BTRFS_CSUM_ITEM_KEY: + fmt.Printf("\t\tcsum item\n") + case btrfs.BTRFS_EXTENT_CSUM_KEY: + // TODO + case btrfs.BTRFS_EXTENT_DATA_KEY: + // TODO + case btrfs.BTRFS_BLOCK_GROUP_ITEM_KEY: + // TODO + case btrfs.BTRFS_FREE_SPACE_INFO_KEY: + // TODO + case btrfs.BTRFS_FREE_SPACE_EXTENT_KEY: + fmt.Printf("\t\tfree space extent\n") + case btrfs.BTRFS_FREE_SPACE_BITMAP_KEY: + fmt.Printf("\t\tfree space bitmap\n") + case btrfs.BTRFS_CHUNK_ITEM_KEY: + // TODO(!) + case btrfs.BTRFS_DEV_ITEM_KEY: + // TODO + case btrfs.BTRFS_DEV_EXTENT_KEY: + // TODO + case btrfs.BTRFS_QGROUP_STATUS_KEY: + // TODO + case btrfs.BTRFS_QGROUP_RELATION_KEY, btrfs.BTRFS_QGROUP_INFO_KEY: + // TODO + case btrfs.BTRFS_QGROUP_LIMIT_KEY: + // TODO + case btrfs.BTRFS_UUID_KEY_SUBVOL, btrfs.BTRFS_UUID_KEY_RECEIVED_SUBVOL: + // TODO + case btrfs.BTRFS_STRING_ITEM_KEY: + // TODO + case btrfs.BTRFS_PERSISTENT_ITEM_KEY: + // TODO + case btrfs.BTRFS_TEMPORARY_ITEM_KEY: + // TODO + } } } } @@ -118,6 +233,12 @@ func printHeaderInfo(node btrfs.Node) { node.GetNodeHeader().Addr, node.GetNodeHeader().Data.Flags, node.GetNodeHeader().Data.BackrefRev) + + fmt.Printf("checksum stored %x\n", node.GetNodeHeader().Data.Checksum) + fmt.Printf("checksum calced %v\n", "TODO") + + fmt.Printf("fs uuid %s\n", node.GetNodeHeader().Data.MetadataUUID) + fmt.Printf("chunk uuid %s\n", node.GetNodeHeader().Data.ChunkTreeUUID) } // mimics print-tree.c:btrfs_print_key() @@ -140,3 +261,8 @@ func fmtKey(key btrfs.Key) string { } return out.String() } + +func fmtTime(t btrfs.Time) string { + return fmt.Sprintf("%d.%d (%s)", + t.Sec, t.NSec, t.ToStd().Format("2006-01-02 15:04:05")) +} diff --git a/pkg/btrfs/types_bitfields.go b/pkg/btrfs/types_bitfields.go index 5c09b0a..391ac15 100644 --- a/pkg/btrfs/types_bitfields.go +++ b/pkg/btrfs/types_bitfields.go @@ -9,9 +9,6 @@ import ( ) func bitfieldString[T ~uint8 | ~uint16 | ~uint32 | ~uint64](bitfield T, bitnames []string) string { - if bitfield == 0 { - return "0" - } var out strings.Builder fmt.Fprintf(&out, "0x%0X", uint64(bitfield)) if bitfield == 0 { @@ -108,3 +105,16 @@ var nodeFlagNames = []string{ func (f NodeFlags) Has(req NodeFlags) bool { return f&req == req } func (f NodeFlags) String() string { return bitfieldString(f, nodeFlagNames) } + +type RootItemFlags uint64 + +const ( + BTRFS_ROOT_SUBVOL_RDONLY = RootItemFlags(1 << iota) +) + +var rootItemFlagNames = []string{ + "SUBVOL_RDONLY", +} + +func (f RootItemFlags) Has(req RootItemFlags) bool { return f&req == req } +func (f RootItemFlags) String() string { return bitfieldString(f, rootItemFlagNames) } diff --git a/pkg/btrfs/types_item.go b/pkg/btrfs/types_item.go index 3db4174..7678c5d 100644 --- a/pkg/btrfs/types_item.go +++ b/pkg/btrfs/types_item.go @@ -2,11 +2,15 @@ package btrfs import ( "fmt" + + "lukeshu.com/btrfs-tools/pkg/binstruct" ) type ItemType uint8 const ( + BTRFS_UNTYPED_KEY = ItemType(0) + // inode items have the data typically returned from stat and store other // info about object characteristics. There is one for every file and dir in // the FS @@ -139,6 +143,7 @@ const ( func (t ItemType) String() string { names := map[ItemType]string{ + BTRFS_UNTYPED_KEY: "UNTYPED", BTRFS_INODE_ITEM_KEY: "INODE_ITEM", BTRFS_INODE_REF_KEY: "INODE_REF", BTRFS_INODE_EXTREF_KEY: "INODE_EXTREF", @@ -186,3 +191,84 @@ func (t ItemType) String() string { } return fmt.Sprintf("%d", t) } + +type DevItem struct { + DeviceID ObjID `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 Generation `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 InodeRefItem struct { + Index int64 `bin:"off=0, siz=8"` + NameLen int16 `bin:"off=8, siz=2"` + binstruct.End `bin:"off=a"` + Name []byte `bin:"-"` +} + +type InodeItem struct { + Generation int64 `bin:"off=0, siz=8"` + TransID int64 `bin:"off=8, siz=8"` + Size int64 `bin:"off=10, siz=8"` + NumBytes int64 `bin:"off=18, siz=8"` + BlockGroup int64 `bin:"off=20, siz=8"` + NLink int32 `bin:"off=28, siz=4"` + UID int32 `bin:"off=2C, siz=4"` + GID int32 `bin:"off=30, siz=4"` + Mode int32 `bin:"off=34, siz=4"` + RDev int64 `bin:"off=38, siz=8"` + Flags uint64 `bin:"off=40, siz=8"` + Sequence int64 `bin:"off=48, siz=8"` + Reserved [4]int64 `bin:"off=50, siz=20"` + ATime Time `bin:"off=70, siz=c"` + CTime Time `bin:"off=7c, siz=c"` + MTime Time `bin:"off=88, siz=c"` + OTime Time `bin:"off=94, siz=c"` + binstruct.End `bin:"off=a0"` +} + +type RootItem struct { + Inode InodeItem `bin:"off=0, siz=a0"` + Generation int64 `bin:"off=a0, siz=8"` + RootDirID int64 `bin:"off=a8, siz=8"` + ByteNr LogicalAddr `bin:"off=b0, siz=8"` + ByteLimit int64 `bin:"off=b8, siz=8"` + BytesUsed int64 `bin:"off=c0, siz=8"` + LastSnapshot int64 `bin:"off=c8, siz=8"` + Flags RootItemFlags `bin:"off=d0, siz=8"` + Refs int32 `bin:"off=d8, siz=4"` + DropProgress Key `bin:"off=dc, siz=11"` + DropLevel uint8 `bin:"off=ed, siz=1"` + Level uint8 `bin:"off=ee, siz=1"` + GenerationV2 int64 `bin:"off=ef, siz=8"` + UUID UUID `bin:"off=F7, siz=10"` + ParentUUID UUID `bin:"off=107, siz=10"` + ReceivedUUID UUID `bin:"off=117, siz=10"` + CTransID int64 `bin:"off=127, siz=8"` + OTransID int64 `bin:"off=12f, siz=8"` + STransID int64 `bin:"off=137, siz=8"` + RTransID int64 `bin:"off=13f, siz=8"` + CTime Time `bin:"off=147, siz=c"` + OTime Time `bin:"off=153, siz=c"` + STime Time `bin:"off=15F, siz=c"` + RTime Time `bin:"off=16b, siz=c"` + GlobalTreeID ObjID `bin:"off=177, siz=8"` + Reserved [7]int64 `bin:"off=17f, siz=38"` + binstruct.End `bin:"off=1b7"` +} diff --git a/pkg/btrfs/types_objid.go b/pkg/btrfs/types_objid.go index b08cf3a..bcaac9a 100644 --- a/pkg/btrfs/types_objid.go +++ b/pkg/btrfs/types_objid.go @@ -6,7 +6,7 @@ import ( type ObjID uint64 -const MaxUint64pp = 0x1_0000_0000 +const MaxUint64pp = 0x1_00000000_00000000 const ( // The IDs of the various trees @@ -132,15 +132,13 @@ func (id ObjID) Format(typ ItemType) string { BTRFS_FREE_SPACE_TREE_OBJECTID: "FREE_SPACE_TREE", BTRFS_BLOCK_GROUP_TREE_OBJECTID: "BLOCK_GROUP_TREE", } - if names != nil { - if name, ok := names[id]; ok { - return name - } + if name, ok := names[id]; ok { + return name } return fmt.Sprintf("%d", int64(id)) } } func (id ObjID) String() string { - return id.Format(BTRFS_STRING_ITEM_KEY) + return id.Format(BTRFS_UNTYPED_KEY) } diff --git a/pkg/btrfs/types_structs.go b/pkg/btrfs/types_structs.go index 22e3f73..bfaa0e6 100644 --- a/pkg/btrfs/types_structs.go +++ b/pkg/btrfs/types_structs.go @@ -23,7 +23,7 @@ type Key struct { 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. + NSec uint32 `bin:"off=8, siz=4"` // Number of nanoseconds since the beginning of the second. binstruct.End `bin:"off=c"` } @@ -259,29 +259,6 @@ type Item struct { Data Ref[LogicalAddr, []byte] `bin:"-"` } -type DevItem struct { - DeviceID ObjID `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 Generation `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 Chunk struct { // Maps logical address to physical. Size uint64 `bin:"off=0, siz=8"` // size of chunk (bytes) |