From cd46b6b734d833a9e2d83ba92e8f7348e63afe7e Mon Sep 17 00:00:00 2001
From: Luke Shumaker <lukeshu@lukeshu.com>
Date: Sat, 2 Jul 2022 16:42:13 -0600
Subject: implement EXTENT_CSUM

---
 pkg/btrfs/btrfsitem/item_extentcsum.go | 39 ++++++++++++++++++++++++++++++++++
 pkg/btrfs/btrfsitem/items.go           |  6 +++++-
 pkg/btrfs/btrfsitem/items.txt          |  1 +
 pkg/btrfs/btrfsitem/items_gen.go       |  3 +++
 4 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 pkg/btrfs/btrfsitem/item_extentcsum.go

(limited to 'pkg/btrfs/btrfsitem')

diff --git a/pkg/btrfs/btrfsitem/item_extentcsum.go b/pkg/btrfs/btrfsitem/item_extentcsum.go
new file mode 100644
index 0000000..27c7c9b
--- /dev/null
+++ b/pkg/btrfs/btrfsitem/item_extentcsum.go
@@ -0,0 +1,39 @@
+package btrfsitem
+
+import (
+	"fmt"
+
+	"lukeshu.com/btrfs-tools/pkg/btrfs/btrfssum"
+)
+
+// key.objectid = BTRFS_EXTENT_CSUM_OBJECTID
+// key.offset = laddr of checksummed region
+type ExtentCSum struct { // EXTENT_CSUM=128
+	ChecksumSize int
+	// Checksum of each sector starting at key.offset
+	Sums []btrfssum.CSum
+}
+
+func (o *ExtentCSum) UnmarshalBinary(dat []byte) (int, error) {
+	if o.ChecksumSize == 0 {
+		return 0, fmt.Errorf("btrfs.ExtentCSum.UnmarshalBinary: .ChecksumSize must be set")
+	}
+	for len(dat) >= o.ChecksumSize {
+		var csum btrfssum.CSum
+		copy(csum[:], dat[:o.ChecksumSize])
+		dat = dat[o.ChecksumSize:]
+		o.Sums = append(o.Sums, csum)
+	}
+	return len(o.Sums) * o.ChecksumSize, nil
+}
+
+func (o ExtentCSum) MarshalBinary() ([]byte, error) {
+	if o.ChecksumSize == 0 {
+		return nil, fmt.Errorf("btrfs.ExtentCSum.MarshalBinary: .ChecksumSize must be set")
+	}
+	var dat []byte
+	for _, csum := range o.Sums {
+		dat = append(dat, csum[:o.ChecksumSize]...)
+	}
+	return dat, nil
+}
diff --git a/pkg/btrfs/btrfsitem/items.go b/pkg/btrfs/btrfsitem/items.go
index 1a3b883..5ad3471 100644
--- a/pkg/btrfs/btrfsitem/items.go
+++ b/pkg/btrfs/btrfsitem/items.go
@@ -5,6 +5,7 @@ import (
 	"reflect"
 
 	"lukeshu.com/btrfs-tools/pkg/binstruct"
+	"lukeshu.com/btrfs-tools/pkg/btrfs/btrfssum"
 	"lukeshu.com/btrfs-tools/pkg/btrfs/internal"
 )
 
@@ -31,7 +32,7 @@ func (o *Error) UnmarshalBinary(dat []byte) (int, error) {
 }
 
 // Rather than returning a separate error  value, return an Error item.
-func UnmarshalItem(key internal.Key, dat []byte) Item {
+func UnmarshalItem(key internal.Key, csumType btrfssum.CSumType, dat []byte) Item {
 	var gotyp reflect.Type
 	if key.ItemType == UNTYPED_KEY {
 		var ok bool
@@ -54,6 +55,9 @@ func UnmarshalItem(key internal.Key, dat []byte) Item {
 		}
 	}
 	retPtr := reflect.New(gotyp)
+	if csums, ok := retPtr.Interface().(*ExtentCSum); ok {
+		csums.ChecksumSize = csumType.Size()
+	}
 	n, err := binstruct.Unmarshal(dat, retPtr.Interface())
 	if err != nil {
 		return Error{
diff --git a/pkg/btrfs/btrfsitem/items.txt b/pkg/btrfs/btrfsitem/items.txt
index 59e3e76..dbcd260 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_CSUM=128 ExtentCSum
 EXTENT_DATA=108 FileExtent
 EXTENT_DATA_REF=178 ExtentDataRef
 EXTENT_ITEM=168 Extent
diff --git a/pkg/btrfs/btrfsitem/items_gen.go b/pkg/btrfs/btrfsitem/items_gen.go
index e60c50e..f0a4274 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_CSUM_KEY          = internal.EXTENT_CSUM_KEY
 	EXTENT_DATA_KEY          = internal.EXTENT_DATA_KEY
 	EXTENT_DATA_REF_KEY      = internal.EXTENT_DATA_REF_KEY
 	EXTENT_ITEM_KEY          = internal.EXTENT_ITEM_KEY
@@ -44,6 +45,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_CSUM_KEY:          reflect.TypeOf(ExtentCSum{}),
 	EXTENT_DATA_KEY:          reflect.TypeOf(FileExtent{}),
 	EXTENT_DATA_REF_KEY:      reflect.TypeOf(ExtentDataRef{}),
 	EXTENT_ITEM_KEY:          reflect.TypeOf(Extent{}),
@@ -76,6 +78,7 @@ func (DevStats) isItem()        {}
 func (DirList) isItem()         {}
 func (Empty) isItem()           {}
 func (Extent) isItem()          {}
+func (ExtentCSum) isItem()      {}
 func (ExtentDataRef) isItem()   {}
 func (FileExtent) isItem()      {}
 func (FreeSpaceBitmap) isItem() {}
-- 
cgit v1.2.3-2-g168b