summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-06-05 22:12:51 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-06-05 22:12:51 -0600
commit5626918663de1d3f606850e25a5b39f940ceb7a2 (patch)
treec15d6b037078106cfa87192bbefedb944e5e466b /pkg
parent7b8cdb995ecce81e4603a31e3304f6a2b9401c4c (diff)
better error handling
Diffstat (limited to 'pkg')
-rw-r--r--pkg/btrfs/types_btree.go73
-rw-r--r--pkg/btrfsmisc/fsck.go34
-rw-r--r--pkg/btrfsmisc/print_tree.go2
3 files changed, 58 insertions, 51 deletions
diff --git a/pkg/btrfs/types_btree.go b/pkg/btrfs/types_btree.go
index 89901c3..70737e7 100644
--- a/pkg/btrfs/types_btree.go
+++ b/pkg/btrfs/types_btree.go
@@ -107,6 +107,9 @@ func (node Node) MaxItems() uint32 {
}
func (node *Node) UnmarshalBinary(nodeBuf []byte) (int, error) {
+ node.BodyInternal = nil
+ node.BodyLeaf = nil
+ node.Padding = nil
n, err := binstruct.Unmarshal(nodeBuf, &node.Head)
if err != nil {
return n, err
@@ -264,52 +267,58 @@ func (fs *FS) ReadNode(addr LogicalAddr) (*util.Ref[LogicalAddr, Node], error) {
return nil, err
}
- var node Node
- node.Size = sb.Data.NodeSize
+ // parse (early)
- if _, err := node.UnmarshalBinary(nodeBuf); err != nil {
- return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: %w", addr, err)
+ nodeRef := &util.Ref[LogicalAddr, Node]{
+ File: fs,
+ Addr: addr,
+ Data: Node{
+ Size: sb.Data.NodeSize,
+ },
+ }
+ if _, err := binstruct.Unmarshal(nodeBuf, &nodeRef.Data.Head); err != nil {
+ return nodeRef, fmt.Errorf("btrfs.FS.ReadNode: node@%d: %w", addr, err)
}
// sanity checking
- if node.Head.MetadataUUID != sb.Data.EffectiveMetadataUUID() {
+ if nodeRef.Data.Head.MetadataUUID != sb.Data.EffectiveMetadataUUID() {
return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: does not look like a node", addr)
}
- if node.Head.Addr != addr {
- return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: read from laddr=%d but claims to be at laddr=%d",
- addr, addr, node.Head.Addr)
- }
-
- stored := node.Head.Checksum
+ stored := nodeRef.Data.Head.Checksum
calced := CRC32c(nodeBuf[binstruct.StaticSize(CSum{}):])
- if calced != stored {
- return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: checksum mismatch: stored=%s calculated=%s",
+ if stored != calced {
+ return nodeRef, fmt.Errorf("btrfs.FS.ReadNode: node@%d: checksum mismatch: stored=%s calculated=%s",
addr, stored, calced)
}
+ if nodeRef.Data.Head.Addr != addr {
+ return nodeRef, fmt.Errorf("btrfs.FS.ReadNode: node@%d: read from laddr=%d but claims to be at laddr=%d",
+ addr, addr, nodeRef.Data.Head.Addr)
+ }
+
+ // parse (main)
+
+ if _, err := nodeRef.Data.UnmarshalBinary(nodeBuf); err != nil {
+ return nodeRef, fmt.Errorf("btrfs.FS.ReadNode: node@%d: %w", addr, err)
+ }
+
// return
- return &util.Ref[LogicalAddr, Node]{
- File: fs,
- Addr: addr,
- Data: node,
- }, nil
+ return nodeRef, nil
}
type WalkTreeHandler struct {
// Callbacks for entire nodes
PreNode func(LogicalAddr) error
- MidNode func(*util.Ref[LogicalAddr, Node]) error
+ Node func(*util.Ref[LogicalAddr, Node], error) error
PostNode func(*util.Ref[LogicalAddr, Node]) error
// Callbacks for items on internal nodes
PreKeyPointer func(KeyPointer) error
PostKeyPointer func(KeyPointer) error
// Callbacks for items on leaf nodes
Item func(Key, btrfsitem.Item) error
- // Error handler
- NodeError func(error) error
}
func (fs *FS) WalkTree(nodeAddr LogicalAddr, cbs WalkTreeHandler) error {
@@ -325,24 +334,14 @@ func (fs *FS) WalkTree(nodeAddr LogicalAddr, cbs WalkTreeHandler) error {
}
}
node, err := fs.ReadNode(nodeAddr)
- if err != nil {
- if cbs.NodeError != nil {
- err = cbs.NodeError(err)
- }
- if err != nil {
- if errors.Is(err, iofs.SkipDir) {
- return nil
- }
- return fmt.Errorf("btrfs.FS.WalkTree: %w", err)
- }
+ if cbs.Node != nil {
+ err = cbs.Node(node, err)
}
- if cbs.MidNode != nil {
- if err := cbs.MidNode(node); err != nil {
- if errors.Is(err, iofs.SkipDir) {
- return nil
- }
- return err
+ if err != nil {
+ if errors.Is(err, iofs.SkipDir) {
+ return nil
}
+ return fmt.Errorf("btrfs.FS.WalkTree: %w", err)
}
for _, item := range node.Data.BodyInternal {
if cbs.PreKeyPointer != nil {
diff --git a/pkg/btrfsmisc/fsck.go b/pkg/btrfsmisc/fsck.go
index 8d20e6e..a771cf4 100644
--- a/pkg/btrfsmisc/fsck.go
+++ b/pkg/btrfsmisc/fsck.go
@@ -36,26 +36,37 @@ func ScanForNodes(dev *btrfs.Device, sb btrfs.Superblock, fn func(*util.Ref[btrf
continue
}
- // does it look like a node?
+ // parse (early)
+ nodeRef := &util.Ref[btrfs.PhysicalAddr, btrfs.Node]{
+ File: dev,
+ Addr: pos,
+ Data: btrfs.Node{
+ Size: sb.NodeSize,
+ },
+ }
var nodeHeader btrfs.NodeHeader
if _, err := binstruct.Unmarshal(nodeBuf, &nodeHeader); err != nil {
fn(nil, fmt.Errorf("sector@%d: %w", pos, err))
}
+
+ // sanity checking
+
if nodeHeader.MetadataUUID != sb.EffectiveMetadataUUID() {
//fmt.Printf("sector@%d does not look like a node\n", pos)
continue
}
- // ok, it looks like a node; go ahead and read it as a node
-
- nodeRef := &util.Ref[btrfs.PhysicalAddr, btrfs.Node]{
- File: dev,
- Addr: pos,
- Data: btrfs.Node{
- Size: sb.NodeSize,
- },
+ stored := nodeRef.Data.Head.Checksum
+ calced := btrfs.CRC32c(nodeBuf[binstruct.StaticSize(btrfs.CSum{}):])
+ if stored != calced {
+ fn(nodeRef, fmt.Errorf("sector@%d: looks like a node but is corrupt: checksum doesn't match: stored=%s calculated=%s",
+ pos, stored, calced))
+ continue
}
+
+ // parse (main)
+
if _, err := nodeRef.Data.UnmarshalBinary(nodeBuf); err != nil {
fn(nil, fmt.Errorf("sector@%d: %w", pos, err))
continue
@@ -63,11 +74,6 @@ func ScanForNodes(dev *btrfs.Device, sb btrfs.Superblock, fn func(*util.Ref[btrf
// finally, process the node
- if nodeRef.Data.Head.Checksum != btrfs.CRC32c(nodeBuf[0x20:]) {
- fn(nodeRef, fmt.Errorf("sector@%d looks like a node but is corrupt (checksum doesn't match)", pos))
- continue
- }
-
fn(nodeRef, nil)
pos += btrfs.PhysicalAddr(sb.NodeSize) - btrfs.PhysicalAddr(sb.SectorSize)
diff --git a/pkg/btrfsmisc/print_tree.go b/pkg/btrfsmisc/print_tree.go
index b7c3103..a771b65 100644
--- a/pkg/btrfsmisc/print_tree.go
+++ b/pkg/btrfsmisc/print_tree.go
@@ -17,6 +17,8 @@ func PrintTree(fs *btrfs.FS, root btrfs.LogicalAddr) error {
nodeRef, err := fs.ReadNode(root)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
+ }
+ if nodeRef == nil {
return nil
}
node := nodeRef.Data