master
go 88 lines 2.38 KB
Raw
1 // Mount/unmount helpers for the /ipns FUSE mount. go-fuse only builds on linux, darwin, and freebsd.
2 //go:build (linux || darwin || freebsd) && !nofuse
3
4 package ipns
5
6 import (
7 "os"
8 "time"
9
10 "github.com/hanwen/go-fuse/v2/fs"
11 "github.com/hanwen/go-fuse/v2/fuse"
12 "github.com/ipfs/kubo/config"
13 core "github.com/ipfs/kubo/core"
14 coreapi "github.com/ipfs/kubo/core/coreapi"
15 iface "github.com/ipfs/kubo/core/coreiface"
16 fusemnt "github.com/ipfs/kubo/fuse/mount"
17 )
18
19 // How long the kernel caches Lookup and Getattr results. 1 second
20 // matches the go-fuse default and what gocryptfs/rclone use.
21 // TODO: for resolved IPNS names, use the record's cache TTL (capped
22 // at Ipns.MaxCacheTTL) instead of a fixed 1 second.
23 // var (not const) because fs.Options needs a *time.Duration.
24 var mutableCacheTime = time.Second
25
26 // Mount mounts ipns at a given location, and returns a mount.Mount instance.
27 func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (fusemnt.Mount, error) {
28 coreAPI, err := coreapi.NewCoreAPI(ipfs)
29 if err != nil {
30 return nil, err
31 }
32
33 cfg, err := ipfs.Repo.Config()
34 if err != nil {
35 return nil, err
36 }
37
38 mfsOpts, err := cfg.Import.MFSRootOptions()
39 if err != nil {
40 return nil, err
41 }
42
43 key, err := coreAPI.Key().Self(ipfs.Context())
44 if err != nil {
45 return nil, err
46 }
47
48 root, err := CreateRoot(ipfs.Context(), coreAPI, map[string]iface.Key{"local": key}, ipfsmp, ipnsmp, ipfs.Repo.Path(), cfg.Mounts, cfg.Import, mfsOpts...)
49 if err != nil {
50 return nil, err
51 }
52
53 opts := &fs.Options{
54 NullPermissions: true,
55 UID: uint32(os.Getuid()),
56 GID: uint32(os.Getgid()),
57 EntryTimeout: &mutableCacheTime,
58 AttrTimeout: &mutableCacheTime,
59 MountOptions: fuse.MountOptions{
60 AllowOther: cfg.Mounts.FuseAllowOther.WithDefault(config.DefaultFuseAllowOther),
61 FsName: "ipns",
62 MaxReadAhead: fusemnt.MaxReadAhead,
63 Debug: os.Getenv("IPFS_FUSE_DEBUG") != "",
64 ExtraCapabilities: fusemnt.WritableMountCapabilities,
65 },
66 }
67
68 m, err := fusemnt.NewMount(root, ipnsmp, opts)
69 if err != nil {
70 _ = root.Close()
71 return nil, err
72 }
73
74 return &ipnsMount{Mount: m, root: root}, nil
75 }
76
77 // ipnsMount wraps mount.Mount to call Root.Close() on unmount,
78 // which flushes and publishes all MFS roots.
79 type ipnsMount struct {
80 fusemnt.Mount
81 root *Root
82 }
83
84 func (m *ipnsMount) Unmount() error {
85 err := m.Mount.Unmount()
86 _ = m.root.Close()
87 return err
88 }