fuse works now
Juan Batiz-Benet committed
Jul 6, 2014 at 03:49 UTC
3588f5ad25e419db572a3e572d64352bd0a620c3
1 file changed
+118
-73
fuse/readonly/readonly.go
+118
-73
@@ -3,116 +3,161 @@
3
package readonly
4
5
import (
6
- "os"
6
"bazil.org/fuse"
8
- "bazil.org/fuse/fs"
9
- core "github.com/jbenet/go-ipfs/core"
10
- mdag "github.com/jbenet/go-ipfs/merkledag"
7
+ "bazil.org/fuse/fs"
8
+ "fmt"
9
+ core "github.com/jbenet/go-ipfs/core"
10
+ mdag "github.com/jbenet/go-ipfs/merkledag"
11
+ "os"
12
+ "os/exec"
13
+ "os/signal"
14
+ "runtime"
15
+ "syscall"
16
+ "time"
17
)
18
13
-
19
type FileSystem struct {
15
- Ipfs *core.IpfsNode
20
+ Ipfs *core.IpfsNode
21
}
22
23
func NewFileSystem(ipfs *core.IpfsNode) *FileSystem {
19
- return &FileSystem{ Ipfs: ipfs }
24
+ return &FileSystem{Ipfs: ipfs}
25
}
26
27
func (f FileSystem) Root() (fs.Node, fuse.Error) {
23
- return Root{Ipfs: f.Ipfs }, nil
28
+ return &Root{Ipfs: f.Ipfs}, nil
29
}
30
26
-
31
type Root struct {
28
- Ipfs *core.IpfsNode
32
+ Ipfs *core.IpfsNode
33
}
34
31
-func (Root) Attr() fuse.Attr {
32
- return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0111} // -rw+x
35
+func (*Root) Attr() fuse.Attr {
36
+ return fuse.Attr{Mode: os.ModeDir | 0111} // -rw+x
37
}
38
39
func (s *Root) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
36
-
37
- nd, err := s.Ipfs.Resolver.ResolvePath(name)
38
- if err != nil {
39
- // todo: make this error more versatile.
40
- return nil, fuse.ENOENT
41
- }
42
-
43
- return Node{Ipfs: s.Ipfs, Nd: nd}, nil
40
+ switch name {
41
+ case "mach_kernel", ".hidden", "._.":
42
+ // Just quiet some log noise on OS X.
43
+ return nil, fuse.ENOENT
44
+ }
45
+
46
+ nd, err := s.Ipfs.Resolver.ResolvePath(name)
47
+ if err != nil {
48
+ // todo: make this error more versatile.
49
+ return nil, fuse.ENOENT
50
+ }
51
+
52
+ return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
53
}
54
46
-func (Root) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
47
- return nil, fuse.EPERM
55
+func (*Root) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
56
+ return nil, fuse.EPERM
57
}
58
59
type Node struct {
51
- Ipfs *core.IpfsNode
52
- Nd *mdag.Node
60
+ Ipfs *core.IpfsNode
61
+ Nd *mdag.Node
62
}
63
55
-func (s Node) Attr() fuse.Attr {
56
-
57
- if len(s.Nd.Links) > 0 {
58
- return fuse.Attr{Mode: os.ModeDir | 0555}
59
- }
64
+func (s *Node) Attr() fuse.Attr {
65
+ if len(s.Nd.Links) > 0 {
66
+ return fuse.Attr{Mode: os.ModeDir | 0555}
67
+ }
68
61
- size, _ := s.Nd.Size()
62
- return fuse.Attr{Mode: 0444, Size: uint64(size)}
69
+ size, _ := s.Nd.Size()
70
+ return fuse.Attr{Mode: 0444, Size: uint64(size)}
71
}
72
73
func (s *Node) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
74
+ nd, err := s.Ipfs.Resolver.ResolveLinks(s.Nd, []string{name})
75
+ if err != nil {
76
+ // todo: make this error more versatile.
77
+ return nil, fuse.ENOENT
78
+ }
79
67
- nd, err := s.Ipfs.Resolver.ResolveLinks(s.Nd, []string{name})
68
- if err != nil {
69
- // todo: make this error more versatile.
70
- return nil, fuse.ENOENT
71
- }
72
-
73
- return Node{Ipfs: s.Ipfs, Nd: nd}, nil
80
+ return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
81
}
82
83
func (s *Node) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
77
-
78
- entries := make([]fuse.Dirent, len(s.Nd.Links))
79
- for i, link := range s.Nd.Links {
80
- n := link.Name
81
- if len(n) == 0 {
82
- n = link.Hash.B58String()
83
- }
84
- entries[i] = fuse.Dirent{Name: n, Type: fuse.DT_File}
85
- }
86
-
87
- if len(entries) > 0 {
88
- return entries, nil
89
- }
90
- return nil, fuse.ENOENT
84
+ entries := make([]fuse.Dirent, len(s.Nd.Links))
85
+ for i, link := range s.Nd.Links {
86
+ n := link.Name
87
+ if len(n) == 0 {
88
+ n = link.Hash.B58String()
89
+ }
90
+ entries[i] = fuse.Dirent{Name: n, Type: fuse.DT_File}
91
+ }
92
+
93
+ if len(entries) > 0 {
94
+ return entries, nil
95
+ }
96
+ return nil, fuse.ENOENT
97
}
98
99
func (s *Node) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
94
- return []byte(s.Nd.Data), nil
100
+ return []byte(s.Nd.Data), nil
101
}
102
103
+func Mount(ipfs *core.IpfsNode, fpath string) error {
104
+
105
+ sigc := make(chan os.Signal, 1)
106
+ signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT,
107
+ syscall.SIGTERM, syscall.SIGQUIT)
108
+
109
+ go func() {
110
+ <-sigc
111
+ Unmount(fpath)
112
+ }()
113
+
114
+ c, err := fuse.Mount(fpath)
115
+ if err != nil {
116
+ return err
117
+ }
118
+ defer c.Close()
119
+
120
+ err = fs.Serve(c, FileSystem{Ipfs: ipfs})
121
+ if err != nil {
122
+ return err
123
+ }
124
+
125
+ // check if the mount process has an error to report
126
+ <-c.Ready
127
+ if err := c.MountError; err != nil {
128
+ return err
129
+ }
130
+ return nil
131
+}
132
98
-
99
-func Mount(ipfs *core.IpfsNode, fpath string) (error) {
100
-
101
- c, err := fuse.Mount(fpath)
102
- if err != nil {
103
- return err
104
- }
105
- defer c.Close()
106
-
107
- err = fs.Serve(c, FileSystem{Ipfs: ipfs})
108
- if err != nil {
109
- return err
110
- }
111
-
112
- // check if the mount process has an error to report
113
- <-c.Ready
114
- if err := c.MountError; err != nil {
115
- return err
116
- }
117
- return nil
133
+// Unmount attempts to unmount the provided FUSE mount point, forcibly
134
+// if necessary.
135
+func Unmount(point string) error {
136
+ fmt.Printf("Unmounting %s...\n", point)
137
+
138
+ var cmd *exec.Cmd
139
+ switch runtime.GOOS {
140
+ case "darwin":
141
+ cmd = exec.Command("diskutil", "umount", "force", point)
142
+ case "linux":
143
+ cmd = exec.Command("fusermount", "-u", point)
144
+ default:
145
+ return fmt.Errorf("unmount: unimplemented")
146
+ }
147
+
148
+ errc := make(chan error, 1)
149
+ go func() {
150
+ if err := exec.Command("umount", point).Run(); err == nil {
151
+ errc <- err
152
+ }
153
+ // retry to unmount with the fallback cmd
154
+ errc <- cmd.Run()
155
+ }()
156
+
157
+ select {
158
+ case <-time.After(1 * time.Second):
159
+ return fmt.Errorf("umount timeout")
160
+ case err := <-errc:
161
+ return err
162
+ }
163
}