From f84fb2849bb64df667dd65c1912a0e691001ea06 Mon Sep 17 00:00:00 2001 From: Marcin Rataj <lidel@lidel.org> Date: Thu, 15 May 2025 23:43:43 +0200 Subject: [PATCH] fix(fuse): ipns error handling and friendly errors (#10807) * fix(fusei/ux): check if paths exist, print err * fix(fuse): ipns 'could not resolve' error type changed when code got extracted to boxo, but it was not caught because of FUSE tests do not cover IPNS in online mode Closes #8095 Closes #2167 Closes #3013 * docs: clarify opt-in --- cmd/ipfs/kubo/daemon.go | 29 +++++++++++++++++++++++++++++ docs/config.md | 5 ++++- fuse/ipns/ipns_unix.go | 3 ++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/cmd/ipfs/kubo/daemon.go b/cmd/ipfs/kubo/daemon.go index 5cdf3fa1d..94b633f79 100644 --- a/cmd/ipfs/kubo/daemon.go +++ b/cmd/ipfs/kubo/daemon.go @@ -1065,16 +1065,25 @@ func mountFuse(req *cmds.Request, cctx *oldcmds.Context) error { if !found { fsdir = cfg.Mounts.IPFS } + if err := checkFusePath("Mounts.IPFS", fsdir); err != nil { + return err + } nsdir, found := req.Options[ipnsMountKwd].(string) if !found { nsdir = cfg.Mounts.IPNS } + if err := checkFusePath("Mounts.IPNS", nsdir); err != nil { + return err + } mfsdir, found := req.Options[mfsMountKwd].(string) if !found { mfsdir = cfg.Mounts.MFS } + if err := checkFusePath("Mounts.MFS", mfsdir); err != nil { + return err + } node, err := cctx.ConstructNode() if err != nil { @@ -1091,6 +1100,26 @@ func mountFuse(req *cmds.Request, cctx *oldcmds.Context) error { return nil } +func checkFusePath(name, path string) error { + if path == "" { + return fmt.Errorf("%s path cannot be empty", name) + } + + fileInfo, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("%s path (%q) does not exist: %w", name, path, err) + } + return fmt.Errorf("error while inspecting %s path (%q): %w", name, path, err) + } + + if !fileInfo.IsDir() { + return fmt.Errorf("%s path (%q) is not a directory", name, path) + } + + return nil +} + func maybeRunGC(req *cmds.Request, node *core.IpfsNode) (<-chan error, error) { enableGC, _ := req.Options[enableGCKwd].(bool) if !enableGC { diff --git a/docs/config.md b/docs/config.md index 4b8d66ac0..e40ac5887 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1373,7 +1373,10 @@ Default: `cache` ## `Mounts` > [!CAUTION] -> **EXPERIMENTAL:** read about current limitations at [fuse.md](./fuse.md). +> **EXPERIMENTAL:** +> This feature is disabled by default, requires an explicit opt-in with `ipfs mount` or `ipfs daemon --mount`. +> +> Read about current limitations at [fuse.md](./fuse.md). FUSE mount point configuration options. diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index 23704cabd..ea2e75301 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -16,6 +16,7 @@ import ( dag "github.com/ipfs/boxo/ipld/merkledag" ft "github.com/ipfs/boxo/ipld/unixfs" + "github.com/ipfs/boxo/namesys" "github.com/ipfs/boxo/path" fuse "bazil.org/fuse" @@ -95,7 +96,7 @@ func loadRoot(ctx context.Context, ipfs iface.CoreAPI, key iface.Key) (*mfs.Root node, err := ipfs.ResolveNode(ctx, key.Path()) switch err { case nil: - case iface.ErrResolveFailed: + case namesys.ErrResolveFailed: node = ft.EmptyDirNode() default: log.Errorf("looking up %s: %s", key.Path(), err) -- GitLab