summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-03-15 15:17:11 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2023-03-15 15:40:25 -0600
commit56e44b0630448d44f7aa7f85b2098007ddbae06f (patch)
tree2fef6ed9553472c9ff251c27c30ca7dcba16abcc
parent8387d36fac1f01505b37d90d675609460202310d (diff)
btrfstree: Distinguish between tree-not-found and item-not-found
-rw-r--r--lib/btrfs/btrfstree/btree.go5
-rw-r--r--lib/btrfs/btrfstree/btree_err.go32
-rw-r--r--lib/btrfs/btrfstree/btree_err_test.go64
-rw-r--r--lib/btrfs/btrfstree/btree_forrest.go4
-rw-r--r--lib/btrfs/btrfstree/btree_tree.go8
-rw-r--r--lib/btrfsutil/old_rebuilt_forrest.go5
6 files changed, 110 insertions, 8 deletions
diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go
index 2fd7c39..7b3721b 100644
--- a/lib/btrfs/btrfstree/btree.go
+++ b/lib/btrfs/btrfstree/btree.go
@@ -45,7 +45,10 @@ type TreeOperator interface {
// If some items are able to be read, but there is an error reading the
// full set, then it might return *both* a list of items and an error.
//
- // If no such item is found, an error that is io/fs.ErrNotExist is
+ // If the tree is not found, an error that is ErrNoTree is
+ // returned.
+ //
+ // If no such item is found, an error that is ErrNoItem is
// returned.
TreeSearchAll(treeID btrfsprim.ObjID, fn func(key btrfsprim.Key, size uint32) int) ([]Item, error) // size is math.MaxUint32 for key-pointers
}
diff --git a/lib/btrfs/btrfstree/btree_err.go b/lib/btrfs/btrfstree/btree_err.go
new file mode 100644
index 0000000..57fb283
--- /dev/null
+++ b/lib/btrfs/btrfstree/btree_err.go
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package btrfstree
+
+import (
+ iofs "io/fs"
+)
+
+// For both ErrNoItem and ErrNoTree, `errors.Is(err,
+// io/fs.ErrNotExist)` returns true.
+var (
+ ErrNoItem = errNotExist("item")
+ ErrNoTree = errNotExist("tree")
+)
+
+func errNotExist(thing string) error {
+ return &notExistError{thing}
+}
+
+type notExistError struct {
+ thing string
+}
+
+func (e *notExistError) Error() string {
+ return e.thing + " does not exist"
+}
+
+func (*notExistError) Is(target error) bool {
+ return target == iofs.ErrNotExist
+}
diff --git a/lib/btrfs/btrfstree/btree_err_test.go b/lib/btrfs/btrfstree/btree_err_test.go
new file mode 100644
index 0000000..381bd56
--- /dev/null
+++ b/lib/btrfs/btrfstree/btree_err_test.go
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package btrfstree_test
+
+import (
+ "errors"
+ "fmt"
+ iofs "io/fs"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree"
+)
+
+func TestErrs(t *testing.T) {
+ t.Parallel()
+
+ errItem := fmt.Errorf("my item: %w", btrfstree.ErrNoItem)
+ errTree := fmt.Errorf("my tree: %w", btrfstree.ErrNoTree)
+
+ // 1. errItem
+ // 2. errTree
+ // 3. btrfstree.ErrNoItem
+ // 4. btrfstree.ErrNoTree
+ // 5. iofs.ErrNotExist
+
+ // 1
+ assert.Equal(t, errors.Is(errItem, errItem), true)
+ assert.Equal(t, errors.Is(errItem, errTree), false)
+ assert.Equal(t, errors.Is(errItem, btrfstree.ErrNoItem), true)
+ assert.Equal(t, errors.Is(errItem, btrfstree.ErrNoTree), false)
+ assert.Equal(t, errors.Is(errItem, iofs.ErrNotExist), true)
+
+ // 2
+ assert.Equal(t, errors.Is(errTree, errItem), false)
+ assert.Equal(t, errors.Is(errTree, errTree), true)
+ assert.Equal(t, errors.Is(errTree, btrfstree.ErrNoItem), false)
+ assert.Equal(t, errors.Is(errTree, btrfstree.ErrNoTree), true)
+ assert.Equal(t, errors.Is(errTree, iofs.ErrNotExist), true)
+
+ // 3
+ assert.Equal(t, errors.Is(btrfstree.ErrNoItem, errItem), false)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoItem, errTree), false)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoItem, btrfstree.ErrNoItem), true)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoItem, btrfstree.ErrNoTree), false)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoItem, iofs.ErrNotExist), true)
+
+ // 4
+ assert.Equal(t, errors.Is(btrfstree.ErrNoTree, errItem), false)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoTree, errTree), false)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoTree, btrfstree.ErrNoItem), false)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoTree, btrfstree.ErrNoTree), true)
+ assert.Equal(t, errors.Is(btrfstree.ErrNoTree, iofs.ErrNotExist), true)
+
+ // 5
+ assert.Equal(t, errors.Is(iofs.ErrNotExist, errItem), false)
+ assert.Equal(t, errors.Is(iofs.ErrNotExist, errTree), false)
+ assert.Equal(t, errors.Is(iofs.ErrNotExist, btrfstree.ErrNoItem), false)
+ assert.Equal(t, errors.Is(iofs.ErrNotExist, btrfstree.ErrNoTree), false)
+ assert.Equal(t, errors.Is(iofs.ErrNotExist, iofs.ErrNotExist), true)
+}
diff --git a/lib/btrfs/btrfstree/btree_forrest.go b/lib/btrfs/btrfstree/btree_forrest.go
index 0bab610..625fb30 100644
--- a/lib/btrfs/btrfstree/btree_forrest.go
+++ b/lib/btrfs/btrfstree/btree_forrest.go
@@ -5,6 +5,7 @@
package btrfstree
import (
+ "errors"
"fmt"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
@@ -69,6 +70,9 @@ func LookupTreeRoot(fs TreeOperator, sb Superblock, treeID btrfsprim.ObjID) (*Tr
default:
rootItem, err := fs.TreeSearch(btrfsprim.ROOT_TREE_OBJECTID, RootItemSearchFn(treeID))
if err != nil {
+ if errors.Is(err, ErrNoItem) {
+ err = ErrNoTree
+ }
return nil, err
}
switch rootItemBody := rootItem.Body.(type) {
diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go
index afaaf92..c51efa5 100644
--- a/lib/btrfs/btrfstree/btree_tree.go
+++ b/lib/btrfs/btrfstree/btree_tree.go
@@ -180,7 +180,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key,
}}
for {
if path.Node(-1).ToNodeAddr == 0 {
- return nil, nil, iofs.ErrNotExist
+ return nil, nil, ErrNoItem
}
node, err := fs.ReadNode(path)
if err != nil {
@@ -204,7 +204,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key,
})
if !ok {
FreeNodeRef(node)
- return nil, nil, iofs.ErrNotExist
+ return nil, nil, ErrNoItem
}
toMaxKey := path.Node(-1).ToMaxKey
if lastGood+1 < len(node.Data.BodyInterior) {
@@ -228,7 +228,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key,
//
// + + + + 0 - - - -
//
- // Such an item might not exist; in this case, return nil/ErrNotExist.
+ // Such an item might not exist; in this case, return (nil, ErrNoItem).
// Multiple such items might exist; in this case, it does not matter which
// is returned.
//
@@ -238,7 +238,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key,
})
if !ok {
FreeNodeRef(node)
- return nil, nil, iofs.ErrNotExist
+ return nil, nil, ErrNoItem
}
path = append(path, TreePathElem{
FromTree: node.Data.Head.Owner,
diff --git a/lib/btrfsutil/old_rebuilt_forrest.go b/lib/btrfsutil/old_rebuilt_forrest.go
index af2643a..4076072 100644
--- a/lib/btrfsutil/old_rebuilt_forrest.go
+++ b/lib/btrfsutil/old_rebuilt_forrest.go
@@ -7,7 +7,6 @@ package btrfsutil
import (
"context"
"fmt"
- iofs "io/fs"
"sync"
"github.com/datawire/dlib/derror"
@@ -226,7 +225,7 @@ func (bt *OldRebuiltForrest) TreeSearch(treeID btrfsprim.ObjID, fn func(btrfspri
return fn(indexItem.Key, indexItem.ItemSize)
})
if indexItem == nil {
- return btrfstree.Item{}, bt.addErrs(tree, fn, iofs.ErrNotExist)
+ return btrfstree.Item{}, bt.addErrs(tree, fn, btrfstree.ErrNoItem)
}
itemPath := bt.arena.Inflate(indexItem.Value.Path)
@@ -258,7 +257,7 @@ func (bt *OldRebuiltForrest) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfs
return true
})
if len(indexItems) == 0 {
- return nil, bt.addErrs(tree, fn, iofs.ErrNotExist)
+ return nil, bt.addErrs(tree, fn, btrfstree.ErrNoItem)
}
ret := make([]btrfstree.Item, len(indexItems))