@cryptotaxi247 / kubo / commits / c8c2921ed

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