From b4938aba1d890721cb6b2123fad9d81dfd156180 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 5 Jun 2022 15:22:28 -0600 Subject: So close! --- cmd/btrfs-dump-tree/main.go | 29 ++++++- pkg/btrfs/btrfsitem/item_fileextent.go | 141 +++++++++++++++++++++++++++++++++ pkg/btrfs/btrfsitem/items.txt | 1 + pkg/btrfs/btrfsitem/items_gen.go | 3 + pkg/btrfs/internal/itemtype.go | 2 + 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 pkg/btrfs/btrfsitem/item_fileextent.go 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", -- cgit v1.2.3-2-g168b