various fixes for /ipfs fuse code
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
Jeromy committed
Aug 31, 2017 at 16:33 UTC
c8c2921ed2850f0ec8de4a4d1836defe67567908
4 files changed
+86
-29
core/commands/mount_unix.go
+1
-1
@@ -88,7 +88,7 @@ baz
88
}
89
90
// error if we aren't running node in online mode
91
- if !node.OnlineMode() {
91
+ if node.LocalMode() {
92
res.SetError(errNotOnline, cmds.ErrClient)
93
return
94
}
fuse/node/mount_unix.go
+8
-5
@@ -75,12 +75,15 @@ func doMount(node *core.IpfsNode, fsdir, nsdir string) error {
75
done <- struct{}{}
76
}()
77
78
- go func() {
79
- nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
80
- done <- struct{}{}
81
- }()
78
+ if node.OnlineMode() {
79
+ go func() {
80
+ nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
81
+ done <- struct{}{}
82
+ }()
83
+
84
+ <-done
85
+ }
86
83
- <-done
87
<-done
88
89
if err1 != nil {
fuse/readonly/readonly_unix.go
+73
-22
@@ -18,6 +18,7 @@ import (
18
19
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
20
lgbl "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables"
21
+ format "gx/ipfs/QmYNyRZJBUYPNrLszFmrBrPJbsBh2vMsefz5gnDpB5M1P6/go-ipld-format"
22
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
23
fuse "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse"
24
fs "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse/fs"
@@ -60,19 +61,28 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
61
return nil, fuse.ENOENT
62
}
63
63
- nd, err := s.Ipfs.Resolver.ResolvePath(ctx, path.Path(name))
64
+ p, err := path.ParsePath(name)
65
+ if err != nil {
66
+ log.Debugf("fuse failed to parse path: %q: %s", name, err)
67
+ return nil, fuse.ENOENT
68
+ }
69
+
70
+ nd, err := s.Ipfs.Resolver.ResolvePath(ctx, p)
71
if err != nil {
72
// todo: make this error more versatile.
73
return nil, fuse.ENOENT
74
}
75
69
- pbnd, ok := nd.(*mdag.ProtoNode)
70
- if !ok {
76
+ switch nd := nd.(type) {
77
+ case *mdag.ProtoNode:
78
+ return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
79
+ case *mdag.RawNode:
80
+ return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
81
+ default:
82
log.Error("fuse node was not a protobuf node")
83
return nil, fuse.ENOTSUP
84
}
85
75
- return &Node{Ipfs: s.Ipfs, Nd: pbnd}, nil
86
}
87
88
// ReadDirAll reads a particular directory. Disallowed for root.
@@ -84,25 +94,37 @@ func (*Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
94
// Node is the core object representing a filesystem tree node.
95
type Node struct {
96
Ipfs *core.IpfsNode
87
- Nd *mdag.ProtoNode
97
+ Nd format.Node
98
cached *ftpb.Data
99
}
100
101
func (s *Node) loadData() error {
92
- s.cached = new(ftpb.Data)
93
- return proto.Unmarshal(s.Nd.Data(), s.cached)
102
+ if pbnd, ok := s.Nd.(*mdag.ProtoNode); ok {
103
+ s.cached = new(ftpb.Data)
104
+ return proto.Unmarshal(pbnd.Data(), s.cached)
105
+ }
106
+ return nil
107
}
108
109
// Attr returns the attributes of a given node.
110
func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
111
log.Debug("Node attr")
112
+ if rawnd, ok := s.Nd.(*mdag.RawNode); ok {
113
+ a.Mode = 0444
114
+ a.Size = uint64(len(rawnd.RawData()))
115
+ a.Blocks = 1
116
+ a.Uid = uint32(os.Getuid()) // TODO: should probably cache these calls. No sense making multiple syscalls for each attr call here
117
+ a.Gid = uint32(os.Getgid())
118
+ return nil
119
+ }
120
+
121
if s.cached == nil {
122
if err := s.loadData(); err != nil {
123
return fmt.Errorf("readonly: loadData() failed: %s", err)
124
}
125
}
126
switch s.cached.GetType() {
105
- case ftpb.Data_Directory:
127
+ case ftpb.Data_Directory, ftpb.Data_HAMTShard:
128
a.Mode = os.ModeDir | 0555
129
a.Uid = uint32(os.Getuid())
130
a.Gid = uint32(os.Getgid())
@@ -133,31 +155,54 @@ func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
155
// Lookup performs a lookup under this node.
156
func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) {
157
log.Debugf("Lookup '%s'", name)
136
- nodes, err := s.Ipfs.Resolver.ResolveLinks(ctx, s.Nd, []string{name})
137
- if err != nil {
158
+ link, _, err := uio.ResolveUnixfsOnce(ctx, s.Ipfs.DAG, s.Nd, []string{name})
159
+ switch err {
160
+ case os.ErrNotExist, mdag.ErrLinkNotFound:
161
// todo: make this error more versatile.
162
return nil, fuse.ENOENT
163
+ default:
164
+ log.Errorf("fuse lookup %q: %s", name, err)
165
+ return nil, fuse.EIO
166
+ case nil:
167
+ // noop
168
}
169
142
- pbnd, ok := nodes[len(nodes)-1].(*mdag.ProtoNode)
143
- if !ok {
144
- log.Error("fuse lookup got non-protobuf node")
145
- return nil, fuse.ENOTSUP
170
+ nd, err := s.Ipfs.DAG.Get(ctx, link.Cid)
171
+ switch err {
172
+ case mdag.ErrNotFound:
173
+ default:
174
+ log.Errorf("fuse lookup %q: %s", name, err)
175
+ return nil, err
176
+ case nil:
177
+ // noop
178
}
179
148
- return &Node{Ipfs: s.Ipfs, Nd: pbnd}, nil
180
+ return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
181
}
182
183
// ReadDirAll reads the link structure as directory entries
184
func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
185
log.Debug("Node ReadDir")
154
- entries := make([]fuse.Dirent, len(s.Nd.Links()))
155
- for i, link := range s.Nd.Links() {
156
- n := link.Name
186
+ dir, err := uio.NewDirectoryFromNode(s.Ipfs.DAG, s.Nd)
187
+ if err != nil {
188
+ return nil, err
189
+ }
190
+
191
+ var entries []fuse.Dirent
192
+ err = dir.ForEachLink(ctx, func(lnk *format.Link) error {
193
+ n := lnk.Name
194
if len(n) == 0 {
158
- n = link.Cid.String()
195
+ n = lnk.Cid.String()
196
}
160
- entries[i] = fuse.Dirent{Name: n, Type: fuse.DT_File}
197
+ // TODO: calling everything a DT_File here might cause issues. But it
198
+ // will be expensive to query each child. However most shells call an
199
+ // additional 'stat' on each item in a directory listing, its probably
200
+ // okay.
201
+ entries = append(entries, fuse.Dirent{Name: n, Type: fuse.DT_File})
202
+ return nil
203
+ })
204
+ if err != nil {
205
+ return nil, err
206
}
207
208
if len(entries) > 0 {
@@ -166,15 +211,20 @@ func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
211
return nil, fuse.ENOENT
212
}
213
214
+func (s *Node) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error {
215
+ // TODO: is nil the right response for 'bug off, we aint got none' ?
216
+ resp.Xattr = nil
217
+ return nil
218
+}
219
+
220
func (s *Node) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) {
170
- if s.cached.GetType() != ftpb.Data_Symlink {
221
+ if s.cached == nil || s.cached.GetType() != ftpb.Data_Symlink {
222
return "", fuse.Errno(syscall.EINVAL)
223
}
224
return string(s.cached.GetData()), nil
225
}
226
227
func (s *Node) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
177
-
228
c := s.Nd.Cid()
229
230
// setup our logging event
@@ -220,6 +270,7 @@ type roNode interface {
270
fs.Node
271
fs.NodeStringLookuper
272
fs.NodeReadlinker
273
+ fs.NodeGetxattrer
274
}
275
276
var _ roNode = (*Node)(nil)
merkledag/merkledag.go
+4
-1
@@ -153,7 +153,10 @@ type sesGetter struct {
153
154
func (sg *sesGetter) Get(ctx context.Context, c *cid.Cid) (node.Node, error) {
155
blk, err := sg.bs.GetBlock(ctx, c)
156
- if err != nil {
156
+ switch err {
157
+ case bserv.ErrNotFound:
158
+ return nil, ErrNotFound
159
+ default:
160
return nil, err
161
}
162