diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/btrfs/types_btree.go | 73 | ||||
-rw-r--r-- | pkg/btrfsmisc/fsck.go | 34 | ||||
-rw-r--r-- | pkg/btrfsmisc/print_tree.go | 2 |
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 |