summaryrefslogtreecommitdiff
path: root/pkg/btrfs
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-06-03 22:51:43 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-06-03 22:51:43 -0600
commit10605d5b5109bd796fb456e0a6b91f64e278a00c (patch)
tree34470a92e722edc07a98961fb7899d724e31eca1 /pkg/btrfs
parent774b5baa5aa5772b29865e8a570025d94ec34d2a (diff)
implement node checksums
Diffstat (limited to 'pkg/btrfs')
-rw-r--r--pkg/btrfs/types_btree.go75
-rw-r--r--pkg/btrfs/types_superblock.go2
2 files changed, 75 insertions, 2 deletions
diff --git a/pkg/btrfs/types_btree.go b/pkg/btrfs/types_btree.go
index 88b9eb2..f609b8c 100644
--- a/pkg/btrfs/types_btree.go
+++ b/pkg/btrfs/types_btree.go
@@ -147,7 +147,80 @@ func (node *Node) UnmarshalBinary(nodeBuf []byte) (int, error) {
}
func (node Node) MarshalBinary() ([]byte, error) {
- panic("TODO")
+ if node.Size == 0 {
+ return nil, fmt.Errorf("Node.MarshalBinary: .Size must be set")
+ }
+
+ ret := make([]byte, node.Size)
+
+ dat, err := binstruct.Marshal(node.Head)
+ if err != nil {
+ return dat, err
+ }
+ if node.Head.Level > 0 {
+ // internal node
+ for _, item := range node.BodyInternal {
+ bs, err := binstruct.Marshal(item)
+ dat = append(dat, bs...)
+ if err != nil {
+ return dat, err
+ }
+ }
+ if copy(ret, dat) < len(dat) {
+ return ret, fmt.Errorf("btrfs.Node.MarshalBinary: need at least %d bytes, but .Size is only %d",
+ len(dat), node.Size)
+ }
+ } else {
+ // leaf node
+ if copy(ret, dat) < len(dat) {
+ return ret, fmt.Errorf("btrfs.Node.MarshalBinary: need at least %d bytes, but .Size is only %d",
+ len(dat), node.Size)
+ }
+ n := len(dat)
+ for _, item := range node.BodyLeaf {
+ dat, err = binstruct.Marshal(item.Head)
+ if err != nil {
+ return ret, err
+ }
+ if copy(ret[n:], dat) < len(dat) {
+ return ret, fmt.Errorf("btrfs.Node.MarshalBinary: need at least %d bytes, but .Size is only %d",
+ n+len(dat), node.Size)
+ }
+ n += len(dat)
+
+ dat, err := binstruct.Marshal(item.Body)
+ if err != nil {
+ return ret, err
+ }
+ dataOff := binstruct.StaticSize(NodeHeader{}) + int(item.Head.DataOffset)
+ if copy(ret[dataOff:], dat) < len(dat) {
+ return ret, fmt.Errorf("btrfs.Node.MarshalBinary: need at least %d bytes, but .Size is only %d",
+ dataOff+len(dat), node.Size)
+ }
+ }
+ }
+ return ret, nil
+}
+
+func (node Node) CalculateChecksum() (CSum, error) {
+ data, err := binstruct.Marshal(node)
+ if err != nil {
+ return CSum{}, err
+ }
+ return CRC32c(data[binstruct.StaticSize(CSum{}):]), nil
+}
+
+func (node Node) ValidateChecksum() error {
+ stored := node.Head.Checksum
+ calced, err := node.CalculateChecksum()
+ if err != nil {
+ return err
+ }
+ if !calced.Equal(stored) {
+ return fmt.Errorf("node checksum mismatch: stored=%s calculated=%s",
+ stored, calced)
+ }
+ return nil
}
func (node *Node) LeafFreeSpace() uint32 {
diff --git a/pkg/btrfs/types_superblock.go b/pkg/btrfs/types_superblock.go
index a8db86c..609ebc6 100644
--- a/pkg/btrfs/types_superblock.go
+++ b/pkg/btrfs/types_superblock.go
@@ -74,7 +74,7 @@ func (sb Superblock) CalculateChecksum() (CSum, error) {
if err != nil {
return CSum{}, err
}
- return CRC32c(data[0x20:]), nil
+ return CRC32c(data[binstruct.StaticSize(CSum{}):]), nil
}
func (sb Superblock) ValidateChecksum() error {