From bde202f286461ab575dc7e3d83f996d9a5f4a6ec Mon Sep 17 00:00:00 2001
From: Luke Shumaker <lukeshu@lukeshu.com>
Date: Sun, 10 Jul 2022 17:24:51 -0600
Subject: Have a go at rearranging things in to a lib/btrfsprogs

---
 lib/btrfsprogs/btrfsrepair/clearnodes.go | 91 ++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 lib/btrfsprogs/btrfsrepair/clearnodes.go

(limited to 'lib/btrfsprogs/btrfsrepair')

diff --git a/lib/btrfsprogs/btrfsrepair/clearnodes.go b/lib/btrfsprogs/btrfsrepair/clearnodes.go
new file mode 100644
index 0000000..595fef0
--- /dev/null
+++ b/lib/btrfsprogs/btrfsrepair/clearnodes.go
@@ -0,0 +1,91 @@
+// Copyright (C) 2022  Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package btrfsrepair
+
+import (
+	"errors"
+	"fmt"
+
+	"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
+	"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
+	"git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
+	"git.lukeshu.com/btrfs-progs-ng/lib/util"
+)
+
+func ClearBadNodes(fs *btrfs.FS) error {
+	var uuidsInited bool
+	var metadataUUID, chunkTreeUUID btrfs.UUID
+
+	var treeName string
+	var treeID btrfs.ObjID
+	btrfsutil.WalkAllTrees(fs, btrfsutil.WalkAllTreesHandler{
+		PreTree: func(name string, id btrfs.ObjID) {
+			treeName = name
+			treeID = id
+		},
+		Err: func(err error) {
+			fmt.Printf("error: %v\n", err)
+		},
+		UnsafeNodes: true,
+		TreeWalkHandler: btrfs.TreeWalkHandler{
+			Node: func(path btrfs.TreePath, node *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error {
+				if err == nil {
+					if !uuidsInited {
+						metadataUUID = node.Data.Head.MetadataUUID
+						chunkTreeUUID = node.Data.Head.ChunkTreeUUID
+						uuidsInited = true
+					}
+					return nil
+				}
+				if !errors.Is(err, btrfs.ErrNotANode) {
+					err = btrfsutil.WalkErr{
+						TreeName: treeName,
+						Path:     path,
+						Err:      err,
+					}
+					fmt.Printf("error: %v\n", err)
+					return nil
+				}
+				origErr := err
+				if !uuidsInited {
+					// TODO(lukeshu): Is there a better way to get the chunk
+					// tree UUID?
+					return fmt.Errorf("cannot repair node@%v: not (yet?) sure what the chunk tree UUID is", node.Addr)
+				}
+				node.Data = btrfs.Node{
+					Size:         node.Data.Size,
+					ChecksumType: node.Data.ChecksumType,
+					Head: btrfs.NodeHeader{
+						//Checksum:   filled below,
+						MetadataUUID:  metadataUUID,
+						Addr:          node.Addr,
+						Flags:         btrfs.NodeWritten,
+						BackrefRev:    btrfs.MixedBackrefRev,
+						ChunkTreeUUID: chunkTreeUUID,
+						Generation:    0,
+						Owner:         treeID,
+						NumItems:      0,
+						Level:         path[len(path)-1].NodeLevel,
+					},
+				}
+				node.Data.Head.Checksum, err = node.Data.CalculateChecksum()
+				if err != nil {
+					return btrfsutil.WalkErr{
+						TreeName: treeName,
+						Path:     path,
+						Err:      err,
+					}
+				}
+				if err := node.Write(); err != nil {
+					return err
+				}
+
+				fmt.Printf("fixed node@%v (err was %v)\n", node.Addr, origErr)
+				return nil
+			},
+		},
+	})
+	return nil
+}
-- 
cgit v1.2.3-2-g168b