summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-06-05 15:22:28 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-06-05 15:22:28 -0600
commitb4938aba1d890721cb6b2123fad9d81dfd156180 (patch)
treefacf483375c4fbacf85eb6be2961b21564ec8ff3
parente992b909f79ef5e8523052745207ba12c8b510a1 (diff)
So close!
-rw-r--r--cmd/btrfs-dump-tree/main.go29
-rw-r--r--pkg/btrfs/btrfsitem/item_fileextent.go141
-rw-r--r--pkg/btrfs/btrfsitem/items.txt1
-rw-r--r--pkg/btrfs/btrfsitem/items_gen.go3
-rw-r--r--pkg/btrfs/internal/itemtype.go2
5 files changed, 174 insertions, 2 deletions
diff --git a/cmd/btrfs-dump-tree/main.go b/cmd/btrfs-dump-tree/main.go
index 2428a6c..f5eb6c7 100644
--- a/cmd/btrfs-dump-tree/main.go
+++ b/cmd/btrfs-dump-tree/main.go
@@ -217,8 +217,33 @@ func printTree(fs *btrfs.FS, root btrfs.LogicalAddr) error {
// // TODO
//case btrfsitem.EXTENT_CSUM_KEY:
// // TODO
- //case btrfsitem.EXTENT_DATA_KEY:
- // // TODO
+ case btrfsitem.FileExtent:
+ fmt.Printf("\t\tgeneration %d type %v\n",
+ body.Generation, body.Type)
+ switch body.Type {
+ case btrfsitem.FILE_EXTENT_INLINE:
+ fmt.Printf("\t\tinline extent data size %d ram_bytes %d compression %v\n",
+ len(body.BodyInline), body.RAMBytes, body.Compression)
+ case btrfsitem.FILE_EXTENT_PREALLOC:
+ fmt.Printf("\t\tprealloc data disk byte %d nr %d\n",
+ body.BodyPrealloc.DiskByteNr,
+ body.BodyPrealloc.DiskNumBytes)
+ fmt.Printf("\t\tprealloc data offset %d nr %d\n",
+ body.BodyPrealloc.Offset,
+ body.BodyPrealloc.NumBytes)
+ case btrfsitem.FILE_EXTENT_REG:
+ fmt.Printf("\t\textent data disk byte %d nr %d\n",
+ body.BodyReg.DiskByteNr,
+ body.BodyReg.DiskNumBytes)
+ fmt.Printf("\t\textenti data offset %d nr %d ram %d\n",
+ body.BodyReg.Offset,
+ body.BodyReg.NumBytes,
+ body.RAMBytes)
+ fmt.Printf("\t\textent compression %v\n",
+ body.Compression)
+ default:
+ fmt.Printf("\t\t(error) unknown file extent type %v", body.Type)
+ }
case btrfsitem.BlockGroup:
fmt.Printf("\t\tblock group used %d chunk_objectid %d flags %v\n",
body.Used, body.ChunkObjectID, body.Flags)
diff --git a/pkg/btrfs/btrfsitem/item_fileextent.go b/pkg/btrfs/btrfsitem/item_fileextent.go
new file mode 100644
index 0000000..0f7fab4
--- /dev/null
+++ b/pkg/btrfs/btrfsitem/item_fileextent.go
@@ -0,0 +1,141 @@
+package btrfsitem
+
+import (
+ "fmt"
+
+ "lukeshu.com/btrfs-tools/pkg/binstruct"
+)
+
+type FileExtent struct { // EXTENT_DATA=108
+ Generation int64 `bin:"off=0x0, siz=0x8"` // transaction ID that created this extent
+ RAMBytes int64 `bin:"off=0x8, siz=0x8"` // upper bound of what compressed data will decompress to
+
+ // 32 bits describing the data encoding
+ Compression CompressionType `bin:"off=0x10, siz=0x1"`
+ Encryption uint8 `bin:"off=0x11, siz=0x1"`
+ OtherEncoding uint16 `bin:"off=0x12, siz=0x2"` // reserved for later use
+
+ Type FileExtentType `bin:"off=0x14, siz=0x1"` // inline data or real extent
+
+ binstruct.End `bin:"off=0x15"`
+
+ // only one of these, depending on .Type
+ BodyInline []byte `bin:"-"`
+ BodyReg struct {
+ // Position within the device
+ DiskByteNr int64 `bin:"off=0x0, siz=0x8"`
+ DiskNumBytes int64 `bin:"off=0x8, siz=0x8"`
+
+ // Position within the file
+ Offset int64 `bin:"off=0x10, siz=0x8"`
+ NumBytes int64 `bin:"off=0x18, siz=0x8"`
+ binstruct.End `bin:"off=0x20"`
+ } `bin:"-"`
+ BodyPrealloc struct {
+ // Position within the device
+ DiskByteNr int64 `bin:"off=0x0, siz=0x8"`
+ DiskNumBytes int64 `bin:"off=0x8, siz=0x8"`
+
+ // Position within the file
+ Offset int64 `bin:"off=0x10, siz=0x8"`
+ NumBytes int64 `bin:"off=0x18, siz=0x8"`
+ binstruct.End `bin:"off=0x20"`
+ } `bin:"-"`
+}
+
+func (o *FileExtent) UnmarshalBinary(dat []byte) (int, error) {
+ n, err := binstruct.UnmarshalWithoutInterface(dat, o)
+ if err != nil {
+ return n, err
+ }
+ switch o.Type {
+ case FILE_EXTENT_INLINE:
+ o.BodyInline = dat[n:]
+ n += len(o.BodyInline)
+ case FILE_EXTENT_REG:
+ _n, err := binstruct.Unmarshal(dat[n:], &o.BodyReg)
+ n += _n
+ if err != nil {
+ return n, err
+ }
+ case FILE_EXTENT_PREALLOC:
+ _n, err := binstruct.Unmarshal(dat[n:], &o.BodyPrealloc)
+ n += _n
+ if err != nil {
+ return n, err
+ }
+ default:
+ return n, fmt.Errorf("unknown file extent type %v", o.Type)
+ }
+ return n, nil
+}
+
+func (o FileExtent) MarshalBinary() ([]byte, error) {
+ dat, err := binstruct.MarshalWithoutInterface(o)
+ if err != nil {
+ return dat, err
+ }
+ switch o.Type {
+ case FILE_EXTENT_INLINE:
+ dat = append(dat, o.BodyInline...)
+ case FILE_EXTENT_REG:
+ bs, err := binstruct.Marshal(o.BodyReg)
+ dat = append(dat, bs...)
+ if err != nil {
+ return dat, err
+ }
+ case FILE_EXTENT_PREALLOC:
+ bs, err := binstruct.Marshal(o.BodyPrealloc)
+ dat = append(dat, bs...)
+ if err != nil {
+ return dat, err
+ }
+ default:
+ return dat, fmt.Errorf("unknown file extent type %v", o.Type)
+ }
+ return dat, nil
+}
+
+type FileExtentType uint8
+
+const (
+ FILE_EXTENT_INLINE = FileExtentType(iota)
+ FILE_EXTENT_REG
+ FILE_EXTENT_PREALLOC
+)
+
+func (fet FileExtentType) String() string {
+ names := map[FileExtentType]string{
+ FILE_EXTENT_INLINE: "inline",
+ FILE_EXTENT_REG: "regular",
+ FILE_EXTENT_PREALLOC: "prealloc",
+ }
+ name, ok := names[fet]
+ if !ok {
+ name = "unknown"
+ }
+ return fmt.Sprintf("%d (%s)", fet, name)
+}
+
+type CompressionType uint8
+
+const (
+ COMPRESS_NONE = CompressionType(iota)
+ COMPRESS_ZLIB
+ COMPRESS_LZO
+ COMPRESS_ZSTD
+)
+
+func (ct CompressionType) String() string {
+ names := map[CompressionType]string{
+ COMPRESS_NONE: "none",
+ COMPRESS_ZLIB: "zlib",
+ COMPRESS_LZO: "lzo",
+ COMPRESS_ZSTD: "zstd",
+ }
+ name, ok := names[ct]
+ if !ok {
+ name = "unknown"
+ }
+ return fmt.Sprintf("%d (%s)", ct, name)
+}
diff --git a/pkg/btrfs/btrfsitem/items.txt b/pkg/btrfs/btrfsitem/items.txt
index e09c866..8320650 100644
--- a/pkg/btrfs/btrfsitem/items.txt
+++ b/pkg/btrfs/btrfsitem/items.txt
@@ -4,6 +4,7 @@ DEV_EXTENT=204 DevExtent
DEV_ITEM=216 Dev
DIR_INDEX=96 DirList
DIR_ITEM=84 DirList
+EXTENT_DATA=108 FileExtent
EXTENT_DATA_REF=178 ExtentDataRef
EXTENT_ITEM=168 Extent
FREE_SPACE_BITMAP=200 FreeSpaceBitmap
diff --git a/pkg/btrfs/btrfsitem/items_gen.go b/pkg/btrfs/btrfsitem/items_gen.go
index 27fc5c2..02e2915 100644
--- a/pkg/btrfs/btrfsitem/items_gen.go
+++ b/pkg/btrfs/btrfsitem/items_gen.go
@@ -15,6 +15,7 @@ const (
DEV_ITEM_KEY = internal.DEV_ITEM_KEY
DIR_INDEX_KEY = internal.DIR_INDEX_KEY
DIR_ITEM_KEY = internal.DIR_ITEM_KEY
+ EXTENT_DATA_KEY = internal.EXTENT_DATA_KEY
EXTENT_DATA_REF_KEY = internal.EXTENT_DATA_REF_KEY
EXTENT_ITEM_KEY = internal.EXTENT_ITEM_KEY
FREE_SPACE_BITMAP_KEY = internal.FREE_SPACE_BITMAP_KEY
@@ -43,6 +44,7 @@ var keytype2gotype = map[Type]reflect.Type{
DEV_ITEM_KEY: reflect.TypeOf(Dev{}),
DIR_INDEX_KEY: reflect.TypeOf(DirList{}),
DIR_ITEM_KEY: reflect.TypeOf(DirList{}),
+ EXTENT_DATA_KEY: reflect.TypeOf(FileExtent{}),
EXTENT_DATA_REF_KEY: reflect.TypeOf(ExtentDataRef{}),
EXTENT_ITEM_KEY: reflect.TypeOf(Extent{}),
FREE_SPACE_BITMAP_KEY: reflect.TypeOf(FreeSpaceBitmap{}),
@@ -73,6 +75,7 @@ func (DirList) isItem() {}
func (Empty) isItem() {}
func (Extent) isItem() {}
func (ExtentDataRef) isItem() {}
+func (FileExtent) isItem() {}
func (FreeSpaceBitmap) isItem() {}
func (FreeSpaceInfo) isItem() {}
func (Inode) isItem() {}
diff --git a/pkg/btrfs/internal/itemtype.go b/pkg/btrfs/internal/itemtype.go
index aa6e4f9..842f5b6 100644
--- a/pkg/btrfs/internal/itemtype.go
+++ b/pkg/btrfs/internal/itemtype.go
@@ -13,6 +13,7 @@ const (
DEV_ITEM_KEY = ItemType(216)
DIR_INDEX_KEY = ItemType(96)
DIR_ITEM_KEY = ItemType(84)
+ EXTENT_DATA_KEY = ItemType(108)
EXTENT_DATA_REF_KEY = ItemType(178)
EXTENT_ITEM_KEY = ItemType(168)
FREE_SPACE_BITMAP_KEY = ItemType(200)
@@ -42,6 +43,7 @@ func (t ItemType) String() string {
DEV_ITEM_KEY: "DEV_ITEM",
DIR_INDEX_KEY: "DIR_INDEX",
DIR_ITEM_KEY: "DIR_ITEM",
+ EXTENT_DATA_KEY: "EXTENT_DATA",
EXTENT_DATA_REF_KEY: "EXTENT_DATA_REF",
EXTENT_ITEM_KEY: "EXTENT_ITEM",
FREE_SPACE_BITMAP_KEY: "FREE_SPACE_BITMAP",