Commit c8c2921e authored by Jeromy's avatar Jeromy

various fixes for /ipfs fuse code

License: MIT
Signed-off-by: default avatarJeromy <jeromyj@gmail.com>
parent c5d362e3
......@@ -88,7 +88,7 @@ baz
}
// error if we aren't running node in online mode
if !node.OnlineMode() {
if node.LocalMode() {
res.SetError(errNotOnline, cmds.ErrClient)
return
}
......
......@@ -75,12 +75,15 @@ func doMount(node *core.IpfsNode, fsdir, nsdir string) error {
done <- struct{}{}
}()
go func() {
nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
done <- struct{}{}
}()
if node.OnlineMode() {
go func() {
nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
done <- struct{}{}
}()
<-done
}
<-done
<-done
if err1 != nil {
......
......@@ -18,6 +18,7 @@ import (
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
lgbl "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables"
format "gx/ipfs/QmYNyRZJBUYPNrLszFmrBrPJbsBh2vMsefz5gnDpB5M1P6/go-ipld-format"
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
fuse "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse"
fs "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse/fs"
......@@ -60,19 +61,28 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
return nil, fuse.ENOENT
}
nd, err := s.Ipfs.Resolver.ResolvePath(ctx, path.Path(name))
p, err := path.ParsePath(name)
if err != nil {
log.Debugf("fuse failed to parse path: %q: %s", name, err)
return nil, fuse.ENOENT
}
nd, err := s.Ipfs.Resolver.ResolvePath(ctx, p)
if err != nil {
// todo: make this error more versatile.
return nil, fuse.ENOENT
}
pbnd, ok := nd.(*mdag.ProtoNode)
if !ok {
switch nd := nd.(type) {
case *mdag.ProtoNode:
return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
case *mdag.RawNode:
return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
default:
log.Error("fuse node was not a protobuf node")
return nil, fuse.ENOTSUP
}
return &Node{Ipfs: s.Ipfs, Nd: pbnd}, nil
}
// ReadDirAll reads a particular directory. Disallowed for root.
......@@ -84,25 +94,37 @@ func (*Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
// Node is the core object representing a filesystem tree node.
type Node struct {
Ipfs *core.IpfsNode
Nd *mdag.ProtoNode
Nd format.Node
cached *ftpb.Data
}
func (s *Node) loadData() error {
s.cached = new(ftpb.Data)
return proto.Unmarshal(s.Nd.Data(), s.cached)
if pbnd, ok := s.Nd.(*mdag.ProtoNode); ok {
s.cached = new(ftpb.Data)
return proto.Unmarshal(pbnd.Data(), s.cached)
}
return nil
}
// Attr returns the attributes of a given node.
func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
log.Debug("Node attr")
if rawnd, ok := s.Nd.(*mdag.RawNode); ok {
a.Mode = 0444
a.Size = uint64(len(rawnd.RawData()))
a.Blocks = 1
a.Uid = uint32(os.Getuid()) // TODO: should probably cache these calls. No sense making multiple syscalls for each attr call here
a.Gid = uint32(os.Getgid())
return nil
}
if s.cached == nil {
if err := s.loadData(); err != nil {
return fmt.Errorf("readonly: loadData() failed: %s", err)
}
}
switch s.cached.GetType() {
case ftpb.Data_Directory:
case ftpb.Data_Directory, ftpb.Data_HAMTShard:
a.Mode = os.ModeDir | 0555
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
......@@ -133,31 +155,54 @@ func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
// Lookup performs a lookup under this node.
func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) {
log.Debugf("Lookup '%s'", name)
nodes, err := s.Ipfs.Resolver.ResolveLinks(ctx, s.Nd, []string{name})
if err != nil {
link, _, err := uio.ResolveUnixfsOnce(ctx, s.Ipfs.DAG, s.Nd, []string{name})
switch err {
case os.ErrNotExist, mdag.ErrLinkNotFound:
// todo: make this error more versatile.
return nil, fuse.ENOENT
default:
log.Errorf("fuse lookup %q: %s", name, err)
return nil, fuse.EIO
case nil:
// noop
}
pbnd, ok := nodes[len(nodes)-1].(*mdag.ProtoNode)
if !ok {
log.Error("fuse lookup got non-protobuf node")
return nil, fuse.ENOTSUP
nd, err := s.Ipfs.DAG.Get(ctx, link.Cid)
switch err {
case mdag.ErrNotFound:
default:
log.Errorf("fuse lookup %q: %s", name, err)
return nil, err
case nil:
// noop
}
return &Node{Ipfs: s.Ipfs, Nd: pbnd}, nil
return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
}
// ReadDirAll reads the link structure as directory entries
func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
log.Debug("Node ReadDir")
entries := make([]fuse.Dirent, len(s.Nd.Links()))
for i, link := range s.Nd.Links() {
n := link.Name
dir, err := uio.NewDirectoryFromNode(s.Ipfs.DAG, s.Nd)
if err != nil {
return nil, err
}
var entries []fuse.Dirent
err = dir.ForEachLink(ctx, func(lnk *format.Link) error {
n := lnk.Name
if len(n) == 0 {
n = link.Cid.String()
n = lnk.Cid.String()
}
entries[i] = fuse.Dirent{Name: n, Type: fuse.DT_File}
// TODO: calling everything a DT_File here might cause issues. But it
// will be expensive to query each child. However most shells call an
// additional 'stat' on each item in a directory listing, its probably
// okay.
entries = append(entries, fuse.Dirent{Name: n, Type: fuse.DT_File})
return nil
})
if err != nil {
return nil, err
}
if len(entries) > 0 {
......@@ -166,15 +211,20 @@ func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
return nil, fuse.ENOENT
}
func (s *Node) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error {
// TODO: is nil the right response for 'bug off, we aint got none' ?
resp.Xattr = nil
return nil
}
func (s *Node) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) {
if s.cached.GetType() != ftpb.Data_Symlink {
if s.cached == nil || s.cached.GetType() != ftpb.Data_Symlink {
return "", fuse.Errno(syscall.EINVAL)
}
return string(s.cached.GetData()), nil
}
func (s *Node) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
c := s.Nd.Cid()
// setup our logging event
......@@ -220,6 +270,7 @@ type roNode interface {
fs.Node
fs.NodeStringLookuper
fs.NodeReadlinker
fs.NodeGetxattrer
}
var _ roNode = (*Node)(nil)
......
......@@ -153,7 +153,10 @@ type sesGetter struct {
func (sg *sesGetter) Get(ctx context.Context, c *cid.Cid) (node.Node, error) {
blk, err := sg.bs.GetBlock(ctx, c)
if err != nil {
switch err {
case bserv.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment