summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/btrfs-clear-bad-nodes/main.go84
-rw-r--r--cmd/btrfs-dump-tree/main.go76
-rw-r--r--cmd/btrfs-fsck/pass1.go6
-rw-r--r--cmd/btrfs-fsck/pass2.go4
-rw-r--r--cmd/btrfs-ls-files/main.go4
-rw-r--r--cmd/btrfs-ls-trees/main.go6
-rw-r--r--cmd/btrfs-mount/fuseutil.go56
-rw-r--r--cmd/btrfs-mount/main.go25
-rw-r--r--cmd/btrfs-mount/subvol_fuse.go342
9 files changed, 22 insertions, 581 deletions
diff --git a/cmd/btrfs-clear-bad-nodes/main.go b/cmd/btrfs-clear-bad-nodes/main.go
index 88c148c..f4b25f1 100644
--- a/cmd/btrfs-clear-bad-nodes/main.go
+++ b/cmd/btrfs-clear-bad-nodes/main.go
@@ -5,14 +5,11 @@
package main
import (
- "errors"
"fmt"
"os"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
- "git.lukeshu.com/btrfs-progs-ng/lib/util"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsrepair"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
)
func main() {
@@ -29,7 +26,7 @@ func Main(imgfilenames ...string) (err error) {
}
}
- fs, err := btrfsmisc.Open(os.O_RDWR, imgfilenames...)
+ fs, err := btrfsutil.Open(os.O_RDWR, imgfilenames...)
if err != nil {
return err
}
@@ -37,78 +34,5 @@ func Main(imgfilenames ...string) (err error) {
maybeSetErr(fs.Close())
}()
- var uuidsInited bool
- var metadataUUID, chunkTreeUUID btrfs.UUID
-
- var treeName string
- var treeID btrfs.ObjID
- btrfsmisc.WalkAllTrees(fs, btrfsmisc.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 = btrfsmisc.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 btrfsmisc.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
+ return btrfsrepair.ClearBadNodes(fs)
}
diff --git a/cmd/btrfs-dump-tree/main.go b/cmd/btrfs-dump-tree/main.go
index 14bb201..cf29ea4 100644
--- a/cmd/btrfs-dump-tree/main.go
+++ b/cmd/btrfs-dump-tree/main.go
@@ -8,9 +8,8 @@ import (
"fmt"
"os"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
)
func main() {
@@ -29,7 +28,7 @@ func Main(imgfilename string) (err error) {
}
}
- fs, err := btrfsmisc.Open(os.O_RDONLY, imgfilename)
+ fs, err := btrfsutil.Open(os.O_RDONLY, imgfilename)
if err != nil {
return err
}
@@ -37,73 +36,6 @@ func Main(imgfilename string) (err error) {
maybeSetErr(fs.Close())
}()
- superblock, err := fs.Superblock()
- if err != nil {
- return err
- }
-
fmt.Printf("btrfs-progs v%v\n", version)
- if superblock.Data.RootTree != 0 {
- fmt.Printf("root tree\n")
- if err := btrfsmisc.PrintTree(fs, btrfs.ROOT_TREE_OBJECTID); err != nil {
- return err
- }
- }
- if superblock.Data.ChunkTree != 0 {
- fmt.Printf("chunk tree\n")
- if err := btrfsmisc.PrintTree(fs, btrfs.CHUNK_TREE_OBJECTID); err != nil {
- return err
- }
- }
- if superblock.Data.LogTree != 0 {
- fmt.Printf("log root tree\n")
- if err := btrfsmisc.PrintTree(fs, btrfs.TREE_LOG_OBJECTID); err != nil {
- return err
- }
- }
- if superblock.Data.BlockGroupRoot != 0 {
- fmt.Printf("block group tree\n")
- if err := btrfsmisc.PrintTree(fs, btrfs.BLOCK_GROUP_TREE_OBJECTID); err != nil {
- return err
- }
- }
- if err := fs.TreeWalk(btrfs.ROOT_TREE_OBJECTID, btrfs.TreeWalkHandler{
- Item: func(_ btrfs.TreePath, item btrfs.Item) error {
- if item.Head.Key.ItemType != btrfsitem.ROOT_ITEM_KEY {
- return nil
- }
- treeName, ok := map[btrfs.ObjID]string{
- btrfs.ROOT_TREE_OBJECTID: "root",
- btrfs.EXTENT_TREE_OBJECTID: "extent",
- btrfs.CHUNK_TREE_OBJECTID: "chunk",
- btrfs.DEV_TREE_OBJECTID: "device",
- btrfs.FS_TREE_OBJECTID: "fs",
- btrfs.ROOT_TREE_DIR_OBJECTID: "directory",
- btrfs.CSUM_TREE_OBJECTID: "checksum",
- btrfs.ORPHAN_OBJECTID: "orphan",
- btrfs.TREE_LOG_OBJECTID: "log",
- btrfs.TREE_LOG_FIXUP_OBJECTID: "log fixup",
- btrfs.TREE_RELOC_OBJECTID: "reloc",
- btrfs.DATA_RELOC_TREE_OBJECTID: "data reloc",
- btrfs.EXTENT_CSUM_OBJECTID: "extent checksum",
- btrfs.QUOTA_TREE_OBJECTID: "quota",
- btrfs.UUID_TREE_OBJECTID: "uuid",
- btrfs.FREE_SPACE_TREE_OBJECTID: "free space",
- btrfs.MULTIPLE_OBJECTIDS: "multiple",
- btrfs.BLOCK_GROUP_TREE_OBJECTID: "block group",
- }[item.Head.Key.ObjectID]
- if !ok {
- treeName = "file"
- }
- fmt.Printf("%v tree %v \n", treeName, btrfsmisc.FmtKey(item.Head.Key))
- return btrfsmisc.PrintTree(fs, item.Head.Key.ObjectID)
- },
- }); err != nil {
- return err
- }
- fmt.Printf("total bytes %v\n", superblock.Data.TotalBytes)
- fmt.Printf("bytes used %v\n", superblock.Data.BytesUsed)
- fmt.Printf("uuid %v\n", superblock.Data.FSUUID)
-
- return nil
+ return btrfsinspect.DumpTrees(fs)
}
diff --git a/cmd/btrfs-fsck/pass1.go b/cmd/btrfs-fsck/pass1.go
index 9296f0a..0f1ebbf 100644
--- a/cmd/btrfs-fsck/pass1.go
+++ b/cmd/btrfs-fsck/pass1.go
@@ -17,7 +17,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/util"
)
@@ -26,7 +26,7 @@ func pass1(fs *btrfs.FS, superblock *util.Ref[btrfsvol.PhysicalAddr, btrfs.Super
fmt.Printf("Pass 1: ... walking fs\n")
visitedNodes := make(map[btrfsvol.LogicalAddr]struct{})
- btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{
+ btrfsutil.WalkAllTrees(fs, btrfsutil.WalkAllTreesHandler{
TreeWalkHandler: btrfs.TreeWalkHandler{
Node: func(path btrfs.TreePath, node *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error {
if err != nil {
@@ -246,7 +246,7 @@ func pass1ScanOneDev_real(dev *btrfs.Device, superblock btrfs.Superblock) (pass1
devSize, _ := dev.Size()
lastProgress := -1
- err := btrfsmisc.ScanForNodes(dev, superblock, func(nodeRef *util.Ref[btrfsvol.PhysicalAddr, btrfs.Node], err error) {
+ err := btrfsutil.ScanForNodes(dev, superblock, func(nodeRef *util.Ref[btrfsvol.PhysicalAddr, btrfs.Node], err error) {
if err != nil {
fmt.Printf("Pass 1: ... dev[%q] error: %v\n", dev.Name(), err)
return
diff --git a/cmd/btrfs-fsck/pass2.go b/cmd/btrfs-fsck/pass2.go
index 86eb5f0..9256220 100644
--- a/cmd/btrfs-fsck/pass2.go
+++ b/cmd/btrfs-fsck/pass2.go
@@ -9,7 +9,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/util"
)
@@ -17,7 +17,7 @@ func pass2(fs *btrfs.FS, foundNodes map[btrfsvol.LogicalAddr]struct{}) {
fmt.Printf("\nPass 2: orphaned nodes\n")
visitedNodes := make(map[btrfsvol.LogicalAddr]struct{})
- btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{
+ btrfsutil.WalkAllTrees(fs, btrfsutil.WalkAllTreesHandler{
TreeWalkHandler: btrfs.TreeWalkHandler{
Node: func(path btrfs.TreePath, node *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error {
visitedNodes[node.Addr] = struct{}{}
diff --git a/cmd/btrfs-ls-files/main.go b/cmd/btrfs-ls-files/main.go
index 3fb540c..36d14ed 100644
--- a/cmd/btrfs-ls-files/main.go
+++ b/cmd/btrfs-ls-files/main.go
@@ -14,7 +14,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/util"
)
@@ -32,7 +32,7 @@ func Main(imgfilenames ...string) (err error) {
}
}
- fs, err := btrfsmisc.Open(os.O_RDONLY, imgfilenames...)
+ fs, err := btrfsutil.Open(os.O_RDONLY, imgfilenames...)
if err != nil {
return err
}
diff --git a/cmd/btrfs-ls-trees/main.go b/cmd/btrfs-ls-trees/main.go
index 7063323..a0ae460 100644
--- a/cmd/btrfs-ls-trees/main.go
+++ b/cmd/btrfs-ls-trees/main.go
@@ -12,7 +12,7 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/util"
)
@@ -30,7 +30,7 @@ func Main(imgfilenames ...string) (err error) {
}
}
- fs, err := btrfsmisc.Open(os.O_RDONLY, imgfilenames...)
+ fs, err := btrfsutil.Open(os.O_RDONLY, imgfilenames...)
if err != nil {
return err
}
@@ -40,7 +40,7 @@ func Main(imgfilenames ...string) (err error) {
var treeErrCnt int
var treeItemCnt map[btrfsitem.Type]int
- btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{
+ btrfsutil.WalkAllTrees(fs, btrfsutil.WalkAllTreesHandler{
PreTree: func(name string, treeID btrfs.ObjID) {
treeErrCnt = 0
treeItemCnt = make(map[btrfsitem.Type]int)
diff --git a/cmd/btrfs-mount/fuseutil.go b/cmd/btrfs-mount/fuseutil.go
deleted file mode 100644
index 940e571..0000000
--- a/cmd/btrfs-mount/fuseutil.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package main
-
-import (
- "context"
- "sync/atomic"
-
- "github.com/datawire/dlib/dcontext"
- "github.com/datawire/dlib/dgroup"
- "github.com/datawire/dlib/dlog"
- "github.com/jacobsa/fuse"
-)
-
-func Mount(ctx context.Context, mountpoint string, server fuse.Server, cfg *fuse.MountConfig) error {
- grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{
- // Allow mountHandle.Join() returning to cause the
- // "unmount" goroutine to quit.
- ShutdownOnNonError: true,
- })
- mounted := uint32(1)
- grp.Go("unmount", func(ctx context.Context) error {
- <-ctx.Done()
- var err error
- var gotNil bool
- // Keep retrying, because the FS might be busy.
- for atomic.LoadUint32(&mounted) != 0 {
- if _err := fuse.Unmount(mountpoint); _err == nil {
- gotNil = true
- } else if !gotNil {
- err = _err
- }
- }
- if gotNil {
- return nil
- }
- return err
- })
- grp.Go("mount", func(ctx context.Context) error {
- defer atomic.StoreUint32(&mounted, 0)
-
- cfg.OpContext = ctx
- cfg.ErrorLogger = dlog.StdLogger(ctx, dlog.LogLevelError)
- cfg.DebugLogger = dlog.StdLogger(ctx, dlog.LogLevelDebug)
-
- mountHandle, err := fuse.Mount(mountpoint, server, cfg)
- if err != nil {
- return err
- }
- dlog.Infof(ctx, "mounted %q", mountpoint)
- return mountHandle.Join(dcontext.HardContext(ctx))
- })
- return grp.Wait()
-}
diff --git a/cmd/btrfs-mount/main.go b/cmd/btrfs-mount/main.go
index 0183c02..7debb3a 100644
--- a/cmd/btrfs-mount/main.go
+++ b/cmd/btrfs-mount/main.go
@@ -8,14 +8,13 @@ import (
"context"
"fmt"
"os"
- "path/filepath"
"github.com/datawire/dlib/dgroup"
"github.com/datawire/dlib/dlog"
"github.com/sirupsen/logrus"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsmisc"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
)
func main() {
@@ -36,14 +35,6 @@ func main() {
}
}
-func tryAbs(rel string) string {
- abs, err := filepath.Abs(rel)
- if err != nil {
- return rel
- }
- return abs
-}
-
func Main(ctx context.Context, mountpoint string, imgfilenames ...string) (err error) {
maybeSetErr := func(_err error) {
if _err != nil && err == nil {
@@ -51,7 +42,7 @@ func Main(ctx context.Context, mountpoint string, imgfilenames ...string) (err e
}
}
- fs, err := btrfsmisc.Open(os.O_RDONLY, imgfilenames...)
+ fs, err := btrfsutil.Open(os.O_RDONLY, imgfilenames...)
if err != nil {
return err
}
@@ -59,13 +50,5 @@ func Main(ctx context.Context, mountpoint string, imgfilenames ...string) (err e
maybeSetErr(fs.Close())
}()
- rootSubvol := &Subvolume{
- Subvolume: btrfs.Subvolume{
- FS: fs,
- TreeID: btrfs.FS_TREE_OBJECTID,
- },
- DeviceName: tryAbs(imgfilenames[0]),
- Mountpoint: mountpoint,
- }
- return rootSubvol.Run(ctx)
+ return btrfsinspect.MountRO(ctx, fs, mountpoint)
}
diff --git a/cmd/btrfs-mount/subvol_fuse.go b/cmd/btrfs-mount/subvol_fuse.go
deleted file mode 100644
index 8a910bf..0000000
--- a/cmd/btrfs-mount/subvol_fuse.go
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package main
-
-import (
- "context"
- "errors"
- "fmt"
- "io"
- "path/filepath"
- "sync"
- "sync/atomic"
- "syscall"
-
- "github.com/datawire/dlib/dgroup"
- "github.com/jacobsa/fuse"
- "github.com/jacobsa/fuse/fuseops"
- "github.com/jacobsa/fuse/fuseutil"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
- "git.lukeshu.com/btrfs-progs-ng/lib/linux"
- "git.lukeshu.com/btrfs-progs-ng/lib/util"
-)
-
-type dirState struct {
- Dir *btrfs.Dir
-}
-
-type fileState struct {
- File *btrfs.File
-}
-
-type Subvolume struct {
- btrfs.Subvolume
- DeviceName string
- Mountpoint string
-
- fuseutil.NotImplementedFileSystem
- lastHandle uint64
- dirHandles util.SyncMap[fuseops.HandleID, *dirState]
- fileHandles util.SyncMap[fuseops.HandleID, *fileState]
-
- subvolMu sync.Mutex
- subvols map[string]struct{}
- grp *dgroup.Group
-}
-
-func (sv *Subvolume) Run(ctx context.Context) error {
- sv.grp = dgroup.NewGroup(ctx, dgroup.GroupConfig{})
- sv.grp.Go("self", func(ctx context.Context) error {
- cfg := &fuse.MountConfig{
- FSName: sv.DeviceName,
- Subtype: "btrfs",
-
- ReadOnly: true,
-
- Options: map[string]string{
- "allow_other": "",
- },
- }
- return Mount(ctx, sv.Mountpoint, fuseutil.NewFileSystemServer(sv), cfg)
- })
- return sv.grp.Wait()
-}
-
-func (sv *Subvolume) newHandle() fuseops.HandleID {
- return fuseops.HandleID(atomic.AddUint64(&sv.lastHandle, 1))
-}
-
-func inodeItemToFUSE(itemBody btrfsitem.Inode) fuseops.InodeAttributes {
- return fuseops.InodeAttributes{
- Size: uint64(itemBody.Size),
- Nlink: uint32(itemBody.NLink),
- Mode: uint32(itemBody.Mode),
- //RDev: itemBody.Rdev, // jacobsa/fuse doesn't expose rdev
- Atime: itemBody.ATime.ToStd(),
- Mtime: itemBody.MTime.ToStd(),
- Ctime: itemBody.CTime.ToStd(),
- //Crtime: itemBody.OTime,
- Uid: uint32(itemBody.UID),
- Gid: uint32(itemBody.GID),
- }
-}
-
-func (sv *Subvolume) LoadDir(inode btrfs.ObjID) (val *btrfs.Dir, err error) {
- val, err = sv.Subvolume.LoadDir(inode)
- if val != nil {
- haveSubvolumes := false
- for _, index := range util.SortedMapKeys(val.ChildrenByIndex) {
- entry := val.ChildrenByIndex[index]
- if entry.Location.ItemType == btrfsitem.ROOT_ITEM_KEY {
- haveSubvolumes = true
- break
- }
- }
- if haveSubvolumes {
- abspath, _err := val.AbsPath()
- if _err != nil {
- return
- }
- sv.subvolMu.Lock()
- for _, index := range util.SortedMapKeys(val.ChildrenByIndex) {
- entry := val.ChildrenByIndex[index]
- if entry.Location.ItemType != btrfsitem.ROOT_ITEM_KEY {
- continue
- }
- if sv.subvols == nil {
- sv.subvols = make(map[string]struct{})
- }
- subMountpoint := filepath.Join(abspath, string(entry.Name))
- if _, alreadyMounted := sv.subvols[subMountpoint]; !alreadyMounted {
- sv.subvols[subMountpoint] = struct{}{}
- workerName := fmt.Sprintf("%d-%s", val.Inode, filepath.Base(subMountpoint))
- sv.grp.Go(workerName, func(ctx context.Context) error {
- subSv := &Subvolume{
- Subvolume: btrfs.Subvolume{
- FS: sv.FS,
- TreeID: entry.Location.ObjectID,
- },
- DeviceName: sv.DeviceName,
- Mountpoint: filepath.Join(sv.Mountpoint, subMountpoint[1:]),
- }
- return subSv.Run(ctx)
- })
- }
- }
- sv.subvolMu.Unlock()
- }
- }
- return
-}
-
-func (sv *Subvolume) StatFS(_ context.Context, op *fuseops.StatFSOp) error {
- // See linux.git/fs/btrfs/super.c:btrfs_statfs()
- sb, err := sv.FS.Superblock()
- if err != nil {
- return err
- }
-
- op.IoSize = sb.Data.SectorSize
- op.BlockSize = sb.Data.SectorSize
- op.Blocks = sb.Data.TotalBytes / uint64(sb.Data.SectorSize) // TODO: adjust for RAID type
- //op.BlocksFree = TODO
-
- // btrfs doesn't have a fixed number of inodes
- op.Inodes = 0
- op.InodesFree = 0
-
- // jacobsa/fuse doesn't expose namelen, instead hard-coding it
- // to 255. Which is fine by us, because that's what it is for
- // btrfs.
-
- return nil
-}
-
-func (sv *Subvolume) LookUpInode(_ context.Context, op *fuseops.LookUpInodeOp) error {
- if op.Parent == fuseops.RootInodeID {
- parent, err := sv.GetRootInode()
- if err != nil {
- return err
- }
- op.Parent = fuseops.InodeID(parent)
- }
-
- dir, err := sv.LoadDir(btrfs.ObjID(op.Parent))
- if err != nil {
- return err
- }
- entry, ok := dir.ChildrenByName[op.Name]
- if !ok {
- return syscall.ENOENT
- }
- if entry.Location.ItemType != btrfsitem.INODE_ITEM_KEY {
- // Subvolume
- //
- // Because each subvolume has its own pool of inodes
- // (as in 2 different subvolumes can have files with
- // te same inode number), so to represent that to FUSE
- // we need to have this be a full separate mountpoint.
- //
- // I'd want to return EIO or EINTR or something here,
- // but both the FUSE userspace tools and the kernel
- // itself stat the mountpoint before mounting it, so
- // we've got to return something bogus here to let
- // that mount happen.
- op.Entry = fuseops.ChildInodeEntry{
- Child: 2, // an inode number that a real file will never have
- Attributes: fuseops.InodeAttributes{
- Nlink: 1,
- Mode: uint32(linux.ModeFmtDir | 0700),
- },
- }
- return nil
- }
- bareInode, err := sv.LoadBareInode(entry.Location.ObjectID)
- if err != nil {
- return err
- }
- op.Entry = fuseops.ChildInodeEntry{
- Child: fuseops.InodeID(entry.Location.ObjectID),
- Generation: fuseops.GenerationNumber(bareInode.InodeItem.Sequence),
- Attributes: inodeItemToFUSE(*bareInode.InodeItem),
- }
- return nil
-}
-
-func (sv *Subvolume) GetInodeAttributes(_ context.Context, op *fuseops.GetInodeAttributesOp) error {
- if op.Inode == fuseops.RootInodeID {
- inode, err := sv.GetRootInode()
- if err != nil {
- return err
- }
- op.Inode = fuseops.InodeID(inode)
- }
-
- bareInode, err := sv.LoadBareInode(btrfs.ObjID(op.Inode))
- if err != nil {
- return err
- }
-
- op.Attributes = inodeItemToFUSE(*bareInode.InodeItem)
- return nil
-}
-
-func (sv *Subvolume) OpenDir(_ context.Context, op *fuseops.OpenDirOp) error {
- if op.Inode == fuseops.RootInodeID {
- inode, err := sv.GetRootInode()
- if err != nil {
- return err
- }
- op.Inode = fuseops.InodeID(inode)
- }
-
- dir, err := sv.LoadDir(btrfs.ObjID(op.Inode))
- if err != nil {
- return err
- }
- handle := sv.newHandle()
- sv.dirHandles.Store(handle, &dirState{
- Dir: dir,
- })
- op.Handle = handle
- return nil
-}
-func (sv *Subvolume) ReadDir(_ context.Context, op *fuseops.ReadDirOp) error {
- state, ok := sv.dirHandles.Load(op.Handle)
- if !ok {
- return syscall.EBADF
- }
- origOffset := op.Offset
- for _, index := range util.SortedMapKeys(state.Dir.ChildrenByIndex) {
- if index < uint64(origOffset) {
- continue
- }
- entry := state.Dir.ChildrenByIndex[index]
- n := fuseutil.WriteDirent(op.Dst[op.BytesRead:], fuseutil.Dirent{
- Offset: fuseops.DirOffset(index + 1),
- Inode: fuseops.InodeID(entry.Location.ObjectID),
- Name: string(entry.Name),
- Type: map[btrfsitem.FileType]fuseutil.DirentType{
- btrfsitem.FT_UNKNOWN: fuseutil.DT_Unknown,
- btrfsitem.FT_REG_FILE: fuseutil.DT_File,
- btrfsitem.FT_DIR: fuseutil.DT_Directory,
- btrfsitem.FT_CHRDEV: fuseutil.DT_Char,
- btrfsitem.FT_BLKDEV: fuseutil.DT_Block,
- btrfsitem.FT_FIFO: fuseutil.DT_FIFO,
- btrfsitem.FT_SOCK: fuseutil.DT_Socket,
- btrfsitem.FT_SYMLINK: fuseutil.DT_Link,
- }[entry.Type],
- })
- if n == 0 {
- break
- }
- op.BytesRead += n
- }
- return nil
-}
-func (sv *Subvolume) ReleaseDirHandle(_ context.Context, op *fuseops.ReleaseDirHandleOp) error {
- _, ok := sv.dirHandles.LoadAndDelete(op.Handle)
- if !ok {
- return syscall.EBADF
- }
- return nil
-}
-
-func (sv *Subvolume) OpenFile(_ context.Context, op *fuseops.OpenFileOp) error {
- file, err := sv.LoadFile(btrfs.ObjID(op.Inode))
- if err != nil {
- return err
- }
- handle := sv.newHandle()
- sv.fileHandles.Store(handle, &fileState{
- File: file,
- })
- op.Handle = handle
- op.KeepPageCache = true
- return nil
-}
-func (sv *Subvolume) ReadFile(_ context.Context, op *fuseops.ReadFileOp) error {
- state, ok := sv.fileHandles.Load(op.Handle)
- if !ok {
- return syscall.EBADF
- }
-
- var dat []byte
- if op.Dst != nil {
- size := util.Min(int64(len(op.Dst)), op.Size)
- dat = op.Dst[:size]
- } else {
- dat = make([]byte, op.Size)
- op.Data = [][]byte{dat}
- }
-
- var err error
- op.BytesRead, err = state.File.ReadAt(dat, op.Offset)
- if errors.Is(err, io.EOF) {
- err = nil
- }
-
- return err
-}
-func (sv *Subvolume) ReleaseFileHandle(_ context.Context, op *fuseops.ReleaseFileHandleOp) error {
- _, ok := sv.fileHandles.LoadAndDelete(op.Handle)
- if !ok {
- return syscall.EBADF
- }
- return nil
-}
-
-func (sv *Subvolume) ReadSymlink(_ context.Context, op *fuseops.ReadSymlinkOp) error {
- return syscall.ENOSYS
-}
-
-func (sv *Subvolume) GetXattr(_ context.Context, op *fuseops.GetXattrOp) error { return syscall.ENOSYS }
-func (sv *Subvolume) ListXattr(_ context.Context, op *fuseops.ListXattrOp) error {
- return syscall.ENOSYS
-}
-
-func (sv *Subvolume) Destroy() {}