master
go 143 lines 3.41 KB
Raw
1 // Mounts all three FUSE filesystems (/ipfs, /ipns, /mfs). go-fuse only builds on linux, darwin, and freebsd.
2 //go:build (linux || darwin || freebsd) && !nofuse
3
4 package node
5
6 import (
7 "errors"
8 "fmt"
9 "strings"
10 "sync"
11
12 core "github.com/ipfs/kubo/core"
13 ipns "github.com/ipfs/kubo/fuse/ipns"
14 mfs "github.com/ipfs/kubo/fuse/mfs"
15 mount "github.com/ipfs/kubo/fuse/mount"
16 rofs "github.com/ipfs/kubo/fuse/readonly"
17
18 logging "github.com/ipfs/go-log/v2"
19 )
20
21 var log = logging.Logger("node")
22
23 // fuseNoDirectory used to check the returning fuse error.
24 const fuseNoDirectory = "fusermount: failed to access mountpoint"
25
26 // fuseExitStatus1 used to check the returning fuse error.
27 const fuseExitStatus1 = "fusermount: exit status 1"
28
29 // platformFuseChecks can get overridden by arch-specific files
30 // to run pre-mount checks (e.g. verifying macFUSE is installed).
31 var platformFuseChecks = func(*core.IpfsNode) error {
32 return nil
33 }
34
35 func Mount(node *core.IpfsNode, fsdir, nsdir, mfsdir string) error {
36 // check if we already have live mounts.
37 // if the user said "Mount", then there must be something wrong.
38 // so, close them and try again.
39 Unmount(node)
40
41 if err := platformFuseChecks(node); err != nil {
42 return err
43 }
44
45 return doMount(node, fsdir, nsdir, mfsdir)
46 }
47
48 func Unmount(node *core.IpfsNode) {
49 if node.Mounts.Ipfs != nil && node.Mounts.Ipfs.IsActive() {
50 // best effort
51 if err := node.Mounts.Ipfs.Unmount(); err != nil {
52 log.Errorf("error unmounting IPFS: %s", err)
53 }
54 }
55 if node.Mounts.Ipns != nil && node.Mounts.Ipns.IsActive() {
56 // best effort
57 if err := node.Mounts.Ipns.Unmount(); err != nil {
58 log.Errorf("error unmounting IPNS: %s", err)
59 }
60 }
61 if node.Mounts.Mfs != nil && node.Mounts.Mfs.IsActive() {
62 // best effort
63 if err := node.Mounts.Mfs.Unmount(); err != nil {
64 log.Errorf("error unmounting MFS: %s", err)
65 }
66 }
67 }
68
69 func doMount(node *core.IpfsNode, fsdir, nsdir, mfsdir string) error {
70 fmtFuseErr := func(err error, mountpoint string) error {
71 s := err.Error()
72 if strings.Contains(s, fuseNoDirectory) {
73 s = strings.ReplaceAll(s, `fusermount: "fusermount:`, "")
74 s = strings.ReplaceAll(s, `\n", exit status 1`, "")
75 return errors.New(s)
76 }
77 if s == fuseExitStatus1 {
78 s = fmt.Sprintf("fuse failed to access mountpoint %s", mountpoint)
79 return errors.New(s)
80 }
81 return err
82 }
83
84 // this sync stuff is so that both can be mounted simultaneously.
85 var fsmount, nsmount, mfmount mount.Mount
86 var err1, err2, err3 error
87
88 var wg sync.WaitGroup
89
90 wg.Go(func() {
91 fsmount, err1 = rofs.Mount(node, fsdir)
92 })
93
94 if node.IsOnline {
95 wg.Go(func() {
96 nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
97 })
98 }
99
100 wg.Go(func() {
101 mfmount, err3 = mfs.Mount(node, mfsdir)
102 })
103
104 wg.Wait()
105
106 if err1 != nil {
107 log.Errorf("error mounting IPFS %s: %s", fsdir, err1)
108 }
109
110 if err2 != nil {
111 log.Errorf("error mounting IPNS %s for IPFS %s: %s", nsdir, fsdir, err2)
112 }
113
114 if err3 != nil {
115 log.Errorf("error mounting MFS %s: %s", mfsdir, err3)
116 }
117
118 if err1 != nil || err2 != nil || err3 != nil {
119 if fsmount != nil {
120 _ = fsmount.Unmount()
121 }
122 if nsmount != nil {
123 _ = nsmount.Unmount()
124 }
125 if mfmount != nil {
126 _ = mfmount.Unmount()
127 }
128
129 if err1 != nil {
130 return fmtFuseErr(err1, fsdir)
131 }
132 if err2 != nil {
133 return fmtFuseErr(err2, nsdir)
134 }
135 return fmtFuseErr(err3, mfsdir)
136 }
137
138 // setup node state, so that it can be canceled
139 node.Mounts.Ipfs = fsmount
140 node.Mounts.Ipns = nsmount
141 node.Mounts.Mfs = mfmount
142 return nil
143 }