diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-10 17:24:51 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-11 00:44:30 -0600 |
commit | bde202f286461ab575dc7e3d83f996d9a5f4a6ec (patch) | |
tree | 64782c354c15f64a164996125a06c1bca30c9aa7 /cmd | |
parent | d2da99882ea49cc67780c0255bf624698898e7fe (diff) |
Have a go at rearranging things in to a lib/btrfsprogs
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/btrfs-clear-bad-nodes/main.go | 84 | ||||
-rw-r--r-- | cmd/btrfs-dump-tree/main.go | 76 | ||||
-rw-r--r-- | cmd/btrfs-fsck/pass1.go | 6 | ||||
-rw-r--r-- | cmd/btrfs-fsck/pass2.go | 4 | ||||
-rw-r--r-- | cmd/btrfs-ls-files/main.go | 4 | ||||
-rw-r--r-- | cmd/btrfs-ls-trees/main.go | 6 | ||||
-rw-r--r-- | cmd/btrfs-mount/fuseutil.go | 56 | ||||
-rw-r--r-- | cmd/btrfs-mount/main.go | 25 | ||||
-rw-r--r-- | cmd/btrfs-mount/subvol_fuse.go | 342 |
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() {} |