summaryrefslogtreecommitdiff
path: root/lib/btrfsprogs/btrfsutil
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-02-28 14:05:27 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-03-14 19:45:07 -0600
commit8c8c6c27552f8554ba014c34d684cb90538ef65b (patch)
treef3a53ed194e29b516b52770e4949a1e508fad6a7 /lib/btrfsprogs/btrfsutil
parent34bf167ef33c57b4d6767273f1d265971a4693b9 (diff)
Move files around [ci-skip]
Diffstat (limited to 'lib/btrfsprogs/btrfsutil')
-rw-r--r--lib/btrfsprogs/btrfsutil/broken_btree.go363
-rw-r--r--lib/btrfsprogs/btrfsutil/open.go46
-rw-r--r--lib/btrfsprogs/btrfsutil/skinny_paths.go146
-rw-r--r--lib/btrfsprogs/btrfsutil/walk.go97
4 files changed, 0 insertions, 652 deletions
diff --git a/lib/btrfsprogs/btrfsutil/broken_btree.go b/lib/btrfsprogs/btrfsutil/broken_btree.go
deleted file mode 100644
index b7663fa..0000000
--- a/lib/btrfsprogs/btrfsutil/broken_btree.go
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package btrfsutil
-
-import (
- "context"
- "fmt"
- iofs "io/fs"
- "sync"
-
- "github.com/datawire/dlib/derror"
- "github.com/datawire/dlib/dlog"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/containers"
- "git.lukeshu.com/btrfs-progs-ng/lib/diskio"
-)
-
-type treeIndex struct {
- TreeRootErr error
- Items *containers.RBTree[treeIndexValue]
- Errors *containers.IntervalTree[btrfsprim.Key, treeIndexError]
-}
-
-type treeIndexError struct {
- Path SkinnyPath
- Err error
-}
-
-type treeIndexValue struct {
- Path SkinnyPath
- Key btrfsprim.Key
- ItemSize uint32
-}
-
-// Compare implements containers.Ordered.
-func (a treeIndexValue) Compare(b treeIndexValue) int {
- return a.Key.Compare(b.Key)
-}
-
-func newTreeIndex(arena *SkinnyPathArena) treeIndex {
- return treeIndex{
- Items: new(containers.RBTree[treeIndexValue]),
- Errors: &containers.IntervalTree[btrfsprim.Key, treeIndexError]{
- MinFn: func(err treeIndexError) btrfsprim.Key {
- return arena.Inflate(err.Path).Node(-1).ToKey
- },
- MaxFn: func(err treeIndexError) btrfsprim.Key {
- return arena.Inflate(err.Path).Node(-1).ToMaxKey
- },
- },
- }
-}
-
-type brokenTrees struct {
- ctx context.Context //nolint:containedctx // don't have an option while keeping the same API
- inner *btrfs.FS
-
- arena *SkinnyPathArena
-
- // btrfsprim.ROOT_TREE_OBJECTID
- rootTreeMu sync.Mutex
- rootTreeIndex *treeIndex
- // for all other trees
- treeMu sync.Mutex
- treeIndexes map[btrfsprim.ObjID]treeIndex
-}
-
-var _ btrfstree.TreeOperator = (*brokenTrees)(nil)
-
-// NewBrokenTrees wraps a *btrfs.FS to support looking up information
-// from broken trees.
-//
-// Of the btrfstree.TreeOperator methods:
-//
-// - TreeWalk works on broken trees
-// - TreeLookup relies on the tree being properly ordered (which a
-// broken tree might not be).
-// - TreeSearch relies on the tree being properly ordered (which a
-// broken tree might not be).
-// - TreeSearchAll relies on the tree being properly ordered (which a
-// broken tree might not be), and a bad node may cause it to not
-// return a truncated list of results.
-//
-// NewBrokenTrees attempts to remedy these deficiencies by using
-// .TreeWalk to build an out-of-FS index of all of the items in the
-// tree, and re-implements TreeLookup, TreeSearch, and TreeSearchAll
-// using that index.
-func NewBrokenTrees(ctx context.Context, inner *btrfs.FS) interface {
- btrfstree.TreeOperator
- Superblock() (*btrfstree.Superblock, error)
- ReadAt(p []byte, off btrfsvol.LogicalAddr) (int, error)
- Augment(treeID btrfsprim.ObjID, nodeAddr btrfsvol.LogicalAddr) ([]btrfsprim.Key, error)
-} {
- return &brokenTrees{
- ctx: ctx,
- inner: inner,
- }
-}
-
-func (bt *brokenTrees) treeIndex(treeID btrfsprim.ObjID) treeIndex {
- var treeRoot *btrfstree.TreeRoot
- var sb *btrfstree.Superblock
- var err error
- if treeID == btrfsprim.ROOT_TREE_OBJECTID {
- bt.rootTreeMu.Lock()
- defer bt.rootTreeMu.Unlock()
- if bt.rootTreeIndex != nil {
- return *bt.rootTreeIndex
- }
- sb, err = bt.inner.Superblock()
- if err == nil {
- treeRoot, err = btrfstree.LookupTreeRoot(bt.inner, *sb, treeID)
- }
- } else {
- bt.treeMu.Lock()
- defer bt.treeMu.Unlock()
- if bt.treeIndexes == nil {
- bt.treeIndexes = make(map[btrfsprim.ObjID]treeIndex)
- }
- if cacheEntry, exists := bt.treeIndexes[treeID]; exists {
- return cacheEntry
- }
- sb, err = bt.inner.Superblock()
- if err == nil {
- treeRoot, err = btrfstree.LookupTreeRoot(bt, *sb, treeID)
- }
- }
- if bt.arena == nil {
- var _sb btrfstree.Superblock
- if sb != nil {
- _sb = *sb
- }
- bt.arena = &SkinnyPathArena{
- FS: bt.inner,
- SB: _sb,
- }
- }
- cacheEntry := newTreeIndex(bt.arena)
- if err != nil {
- cacheEntry.TreeRootErr = err
- } else {
- dlog.Infof(bt.ctx, "indexing tree %v...", treeID)
- bt.rawTreeWalk(*treeRoot, cacheEntry, nil)
- dlog.Infof(bt.ctx, "... done indexing tree %v", treeID)
- }
- if treeID == btrfsprim.ROOT_TREE_OBJECTID {
- bt.rootTreeIndex = &cacheEntry
- } else {
- bt.treeIndexes[treeID] = cacheEntry
- }
- return cacheEntry
-}
-
-func (bt *brokenTrees) rawTreeWalk(root btrfstree.TreeRoot, cacheEntry treeIndex, walked *[]btrfsprim.Key) {
- btrfstree.TreeOperatorImpl{NodeSource: bt.inner}.RawTreeWalk(
- bt.ctx,
- root,
- func(err *btrfstree.TreeError) {
- if len(err.Path) > 0 && err.Path.Node(-1).ToNodeAddr == 0 {
- // This is a panic because on the filesystems I'm working with it more likely
- // indicates a bug in my item parser than a problem with the filesystem.
- panic(fmt.Errorf("TODO: error parsing item: %w", err))
- }
- cacheEntry.Errors.Insert(treeIndexError{
- Path: bt.arena.Deflate(err.Path),
- Err: err.Err,
- })
- },
- btrfstree.TreeWalkHandler{
- Item: func(path btrfstree.TreePath, item btrfstree.Item) error {
- if cacheEntry.Items.Search(func(v treeIndexValue) int { return item.Key.Compare(v.Key) }) != nil {
- // This is a panic because I'm not really sure what the best way to
- // handle this is, and so if this happens I want the program to crash
- // and force me to figure out how to handle it.
- panic(fmt.Errorf("dup key=%v in tree=%v", item.Key, root.TreeID))
- }
- cacheEntry.Items.Insert(treeIndexValue{
- Path: bt.arena.Deflate(path),
- Key: item.Key,
- ItemSize: item.BodySize,
- })
- if walked != nil {
- *walked = append(*walked, item.Key)
- }
- return nil
- },
- },
- )
-}
-
-func (bt *brokenTrees) TreeLookup(treeID btrfsprim.ObjID, key btrfsprim.Key) (btrfstree.Item, error) {
- item, err := bt.TreeSearch(treeID, btrfstree.KeySearch(key.Compare))
- if err != nil {
- err = fmt.Errorf("item with key=%v: %w", key, err)
- }
- return item, err
-}
-
-func (bt *brokenTrees) addErrs(index treeIndex, fn func(btrfsprim.Key, uint32) int, err error) error {
- var errs derror.MultiError
- index.Errors.Subrange(
- func(k btrfsprim.Key) int { return fn(k, 0) },
- func(v treeIndexError) bool {
- errs = append(errs, &btrfstree.TreeError{
- Path: bt.arena.Inflate(v.Path),
- Err: v.Err,
- })
- return true
- })
- if len(errs) == 0 {
- return err
- }
- if err != nil {
- errs = append(errs, err)
- }
- return errs
-}
-
-func (bt *brokenTrees) TreeSearch(treeID btrfsprim.ObjID, fn func(btrfsprim.Key, uint32) int) (btrfstree.Item, error) {
- index := bt.treeIndex(treeID)
- if index.TreeRootErr != nil {
- return btrfstree.Item{}, index.TreeRootErr
- }
-
- indexItem := index.Items.Search(func(indexItem treeIndexValue) int {
- return fn(indexItem.Key, indexItem.ItemSize)
- })
- if indexItem == nil {
- return btrfstree.Item{}, bt.addErrs(index, fn, iofs.ErrNotExist)
- }
-
- itemPath := bt.arena.Inflate(indexItem.Value.Path)
- node, err := bt.inner.ReadNode(itemPath.Parent())
- defer btrfstree.FreeNodeRef(node)
- if err != nil {
- return btrfstree.Item{}, bt.addErrs(index, fn, err)
- }
-
- item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx]
- item.Body = item.Body.CloneItem()
-
- // Since we were only asked to return 1 item, it isn't
- // necessary to augment this `nil` with bt.addErrs().
- return item, nil
-}
-
-func (bt *brokenTrees) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfsprim.Key, uint32) int) ([]btrfstree.Item, error) {
- index := bt.treeIndex(treeID)
- if index.TreeRootErr != nil {
- return nil, index.TreeRootErr
- }
-
- var indexItems []treeIndexValue
- index.Items.Subrange(
- func(indexItem treeIndexValue) int { return fn(indexItem.Key, indexItem.ItemSize) },
- func(node *containers.RBNode[treeIndexValue]) bool {
- indexItems = append(indexItems, node.Value)
- return true
- })
- if len(indexItems) == 0 {
- return nil, bt.addErrs(index, fn, iofs.ErrNotExist)
- }
-
- ret := make([]btrfstree.Item, len(indexItems))
- var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]
- for i := range indexItems {
- itemPath := bt.arena.Inflate(indexItems[i].Path)
- if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr {
- var err error
- btrfstree.FreeNodeRef(node)
- node, err = bt.inner.ReadNode(itemPath.Parent())
- if err != nil {
- btrfstree.FreeNodeRef(node)
- return nil, bt.addErrs(index, fn, err)
- }
- }
- ret[i] = node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx]
- ret[i].Body = ret[i].Body.CloneItem()
- }
- btrfstree.FreeNodeRef(node)
-
- return ret, bt.addErrs(index, fn, nil)
-}
-
-func (bt *brokenTrees) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, errHandle func(*btrfstree.TreeError), cbs btrfstree.TreeWalkHandler) {
- index := bt.treeIndex(treeID)
- if index.TreeRootErr != nil {
- errHandle(&btrfstree.TreeError{
- Path: btrfstree.TreePath{{
- FromTree: treeID,
- ToMaxKey: btrfsprim.MaxKey,
- }},
- Err: index.TreeRootErr,
- })
- return
- }
- var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]
- index.Items.Range(func(indexItem *containers.RBNode[treeIndexValue]) bool {
- if ctx.Err() != nil {
- return false
- }
- if bt.ctx.Err() != nil {
- return false
- }
- if cbs.Item != nil {
- itemPath := bt.arena.Inflate(indexItem.Value.Path)
- if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr {
- var err error
- btrfstree.FreeNodeRef(node)
- node, err = bt.inner.ReadNode(itemPath.Parent())
- if err != nil {
- btrfstree.FreeNodeRef(node)
- errHandle(&btrfstree.TreeError{Path: itemPath, Err: err})
- return true
- }
- }
- item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx]
- if err := cbs.Item(itemPath, item); err != nil {
- errHandle(&btrfstree.TreeError{Path: itemPath, Err: err})
- }
- }
- return true
- })
- btrfstree.FreeNodeRef(node)
-}
-
-func (bt *brokenTrees) Superblock() (*btrfstree.Superblock, error) {
- return bt.inner.Superblock()
-}
-
-func (bt *brokenTrees) ReadAt(p []byte, off btrfsvol.LogicalAddr) (int, error) {
- return bt.inner.ReadAt(p, off)
-}
-
-func (bt *brokenTrees) Augment(treeID btrfsprim.ObjID, nodeAddr btrfsvol.LogicalAddr) ([]btrfsprim.Key, error) {
- sb, err := bt.Superblock()
- if err != nil {
- return nil, err
- }
- index := bt.treeIndex(treeID)
- if index.TreeRootErr != nil {
- return nil, index.TreeRootErr
- }
- nodeRef, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](bt.inner, *sb, nodeAddr, btrfstree.NodeExpectations{})
- defer btrfstree.FreeNodeRef(nodeRef)
- if err != nil {
- return nil, err
- }
- var ret []btrfsprim.Key
- bt.rawTreeWalk(btrfstree.TreeRoot{
- TreeID: treeID,
- RootNode: nodeAddr,
- Level: nodeRef.Data.Head.Level,
- Generation: nodeRef.Data.Head.Generation,
- }, index, &ret)
- return ret, nil
-}
diff --git a/lib/btrfsprogs/btrfsutil/open.go b/lib/btrfsprogs/btrfsutil/open.go
deleted file mode 100644
index c5ee314..0000000
--- a/lib/btrfsprogs/btrfsutil/open.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package btrfsutil
-
-import (
- "context"
- "fmt"
- "os"
-
- "github.com/datawire/dlib/dlog"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/diskio"
- "git.lukeshu.com/btrfs-progs-ng/lib/textui"
-)
-
-func Open(ctx context.Context, flag int, filenames ...string) (*btrfs.FS, error) {
- fs := new(btrfs.FS)
- for i, filename := range filenames {
- dlog.Debugf(ctx, "Adding device file %d/%d %q...", i, len(filenames), filename)
- osFile, err := os.OpenFile(filename, flag, 0)
- if err != nil {
- _ = fs.Close()
- return nil, fmt.Errorf("device file %q: %w", filename, err)
- }
- typedFile := &diskio.OSFile[btrfsvol.PhysicalAddr]{
- File: osFile,
- }
- bufFile := diskio.NewBufferedFile[btrfsvol.PhysicalAddr](
- typedFile,
- //nolint:gomnd // False positive: gomnd.ignored-functions=[textui.Tunable] doesn't support type params.
- textui.Tunable[btrfsvol.PhysicalAddr](16*1024), // block size: 16KiB
- textui.Tunable(1024), // number of blocks to buffer; total of 16MiB
- )
- devFile := &btrfs.Device{
- File: bufFile,
- }
- if err := fs.AddDevice(ctx, devFile); err != nil {
- return nil, fmt.Errorf("device file %q: %w", filename, err)
- }
- }
- return fs, nil
-}
diff --git a/lib/btrfsprogs/btrfsutil/skinny_paths.go b/lib/btrfsprogs/btrfsutil/skinny_paths.go
deleted file mode 100644
index 1695990..0000000
--- a/lib/btrfsprogs/btrfsutil/skinny_paths.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package btrfsutil
-
-import (
- "fmt"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/containers"
- "git.lukeshu.com/btrfs-progs-ng/lib/diskio"
- "git.lukeshu.com/btrfs-progs-ng/lib/textui"
-)
-
-type skinnyItem struct {
- Node btrfsvol.LogicalAddr
- Item int
-}
-
-type SkinnyPath struct {
- Root btrfsvol.LogicalAddr
- Items []int
-}
-
-type SkinnyPathArena struct {
- FS diskio.File[btrfsvol.LogicalAddr]
- SB btrfstree.Superblock
-
- fatRoots map[btrfsvol.LogicalAddr]btrfstree.TreePathElem
- fatItems containers.ARCache[skinnyItem, btrfstree.TreePathElem]
-}
-
-func (a *SkinnyPathArena) init() {
- if a.fatRoots == nil {
- a.fatRoots = make(map[btrfsvol.LogicalAddr]btrfstree.TreePathElem)
- a.fatItems.MaxLen = textui.Tunable(128 * 1024)
- }
-}
-
-func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemIdx int) (btrfstree.TreePathElem, error) {
- if itemIdx < 0 {
- panic("should not happen")
- }
-
- a.init()
-
- ret, ok := a.fatItems.Load(skinnyItem{
- Node: parent.Node(-1).ToNodeAddr,
- Item: itemIdx,
- })
- if ok {
- return ret, nil
- }
-
- node, err := btrfstree.ReadNode(a.FS, a.SB, parent.Node(-1).ToNodeAddr, btrfstree.NodeExpectations{})
- defer btrfstree.FreeNodeRef(node)
- if err != nil {
- return btrfstree.TreePathElem{}, err
- }
- if node.Data.Head.Level > 0 {
- if itemIdx >= len(node.Data.BodyInternal) {
- panic("should not happen")
- }
- for i, item := range node.Data.BodyInternal {
- toMaxKey := parent.Node(-1).ToMaxKey
- if i+1 < len(node.Data.BodyInternal) {
- toMaxKey = node.Data.BodyInternal[i+1].Key.Mm()
- }
- elem := btrfstree.TreePathElem{
- FromTree: node.Data.Head.Owner,
- FromItemIdx: i,
- ToNodeAddr: item.BlockPtr,
- ToNodeGeneration: item.Generation,
- ToNodeLevel: node.Data.Head.Level - 1,
- ToKey: item.Key,
- ToMaxKey: toMaxKey,
- }
- a.fatItems.Store(skinnyItem{Node: parent.Node(-1).ToNodeAddr, Item: i}, elem)
- if i == itemIdx {
- ret = elem
- }
- }
- } else {
- if itemIdx >= len(node.Data.BodyLeaf) {
- panic("should not happen")
- }
- for i, item := range node.Data.BodyLeaf {
- elem := btrfstree.TreePathElem{
- FromTree: node.Data.Head.Owner,
- FromItemIdx: i,
- ToKey: item.Key,
- ToMaxKey: item.Key,
- }
- a.fatItems.Store(skinnyItem{Node: parent.Node(-1).ToNodeAddr, Item: i}, elem)
- if i == itemIdx {
- ret = elem
- }
- }
- }
-
- return ret, nil
-}
-
-func (a *SkinnyPathArena) Deflate(fat btrfstree.TreePath) SkinnyPath {
- a.init()
-
- var ret SkinnyPath
-
- var prevNode btrfsvol.LogicalAddr
- for i, elem := range fat {
- if i == 0 {
- a.fatRoots[elem.ToNodeAddr] = elem
- ret.Root = elem.ToNodeAddr
- } else {
- a.fatItems.Store(skinnyItem{Node: prevNode, Item: elem.FromItemIdx}, elem)
- ret.Items = append(ret.Items, elem.FromItemIdx)
- }
- prevNode = elem.ToNodeAddr
- }
- return ret
-}
-
-func (a *SkinnyPathArena) Inflate(skinny SkinnyPath) btrfstree.TreePath {
- a.init()
-
- ret := make(btrfstree.TreePath, 0, 1+len(skinny.Items))
-
- root, ok := a.fatRoots[skinny.Root]
- if !ok {
- panic(fmt.Errorf("SkinnyPathArena.Inflate: no stored TreePathElem for root->%v",
- skinny.Root))
- }
- ret = append(ret, root)
-
- for _, itemIdx := range skinny.Items {
- elem, err := a.getItem(ret, itemIdx)
- if err != nil {
- panic(err)
- }
- ret = append(ret, elem)
- }
-
- return ret
-}
diff --git a/lib/btrfsprogs/btrfsutil/walk.go b/lib/btrfsprogs/btrfsutil/walk.go
deleted file mode 100644
index 355976a..0000000
--- a/lib/btrfsprogs/btrfsutil/walk.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package btrfsutil
-
-import (
- "context"
- "fmt"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree"
-)
-
-type WalkError struct {
- TreeName string
- Err *btrfstree.TreeError
-}
-
-func (e *WalkError) Unwrap() error { return e.Err }
-
-func (e *WalkError) Error() string {
- return fmt.Sprintf("%v: %v", e.TreeName, e.Err)
-}
-
-type WalkAllTreesHandler struct {
- Err func(*WalkError)
- // Callbacks for entire trees
- PreTree func(name string, id btrfsprim.ObjID)
- PostTree func(name string, id btrfsprim.ObjID)
- // Callbacks for nodes or smaller
- btrfstree.TreeWalkHandler
-}
-
-// WalkAllTrees walks all trees in a *btrfs.FS. Rather than returning
-// an error, it calls errCb each time an error is encountered. The
-// error will always be of type WalkError.
-func WalkAllTrees(ctx context.Context, fs btrfstree.TreeOperator, cbs WalkAllTreesHandler) {
- var treeName string
-
- trees := []struct {
- Name string
- ID btrfsprim.ObjID
- }{
- {
- Name: "root tree",
- ID: btrfsprim.ROOT_TREE_OBJECTID,
- },
- {
- Name: "chunk tree",
- ID: btrfsprim.CHUNK_TREE_OBJECTID,
- },
- {
- Name: "log tree",
- ID: btrfsprim.TREE_LOG_OBJECTID,
- },
- {
- Name: "block group tree",
- ID: btrfsprim.BLOCK_GROUP_TREE_OBJECTID,
- },
- }
- origItem := cbs.Item
- cbs.Item = func(path btrfstree.TreePath, item btrfstree.Item) error {
- if item.Key.ItemType == btrfsitem.ROOT_ITEM_KEY {
- trees = append(trees, struct {
- Name string
- ID btrfsprim.ObjID
- }{
- Name: fmt.Sprintf("tree %v (via %v %v)",
- item.Key.ObjectID.Format(0), treeName, path),
- ID: item.Key.ObjectID,
- })
- }
- if origItem != nil {
- return origItem(path, item)
- }
- return nil
- }
-
- for i := 0; i < len(trees); i++ {
- tree := trees[i]
- treeName = tree.Name
- if cbs.PreTree != nil {
- cbs.PreTree(treeName, tree.ID)
- }
- fs.TreeWalk(
- ctx,
- tree.ID,
- func(err *btrfstree.TreeError) { cbs.Err(&WalkError{TreeName: treeName, Err: err}) },
- cbs.TreeWalkHandler,
- )
- if cbs.PostTree != nil {
- cbs.PostTree(treeName, tree.ID)
- }
- }
-}