summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-05-26 02:08:58 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-05-26 02:08:58 -0600
commit04d6677e52352a7e3ec791e3e817cfe3865e7d6d (patch)
treeb6184f86084cf61cf5066b3c42b9a32e5455e9df
parentf11acf5f5a8c72af59712cf3cda62c47d1a80e5d (diff)
more
-rw-r--r--cmd/btrfs-dump-tree/main.go128
-rw-r--r--pkg/btrfs/types_bitfields.go16
-rw-r--r--pkg/btrfs/types_item.go86
-rw-r--r--pkg/btrfs/types_objid.go10
-rw-r--r--pkg/btrfs/types_structs.go25
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)