Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

various fixes for /ipfs fuse code #4194

Merged
merged 4 commits into from
Sep 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/commands/mount_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion fuse/mount/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ type closer struct {
}

func (c *closer) Close() error {
log.Error(" (c *closer) Close(),", c.M.MountPoint())
log.Warning(" (c *closer) Close(),", c.M.MountPoint())
return c.M.Unmount()
}

Expand Down
26 changes: 14 additions & 12 deletions fuse/node/mount_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"strings"
"sync"

core "github.com/ipfs/go-ipfs/core"
ipns "github.com/ipfs/go-ipfs/fuse/ipns"
Expand Down Expand Up @@ -63,25 +64,26 @@ func doMount(node *core.IpfsNode, fsdir, nsdir string) error {
}

// this sync stuff is so that both can be mounted simultaneously.
var fsmount mount.Mount
var nsmount mount.Mount
var err1 error
var err2 error
var fsmount, nsmount mount.Mount
var err1, err2 error

done := make(chan struct{})
var wg sync.WaitGroup

wg.Add(1)
go func() {
defer wg.Done()
fsmount, err1 = rofs.Mount(node, fsdir)
done <- struct{}{}
}()

go func() {
nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
done <- struct{}{}
}()
if node.OnlineMode() {
wg.Add(1)
go func() {
defer wg.Done()
nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
}()
}

<-done
<-done
wg.Wait()

if err1 != nil {
log.Errorf("error mounting: %s", err1)
Expand Down
123 changes: 93 additions & 30 deletions fuse/readonly/readonly_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -60,19 +61,26 @@ 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, *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.
Expand All @@ -84,46 +92,48 @@ 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
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())
case ftpb.Data_File:
size := s.cached.GetFilesize()
a.Mode = 0444
a.Size = uint64(size)
a.Blocks = uint64(len(s.Nd.Links()))
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
case ftpb.Data_Raw:
a.Mode = 0444
a.Size = uint64(len(s.cached.GetData()))
a.Blocks = uint64(len(s.Nd.Links()))
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
case ftpb.Data_Symlink:
a.Mode = 0777 | os.ModeSymlink
a.Size = uint64(len(s.cached.GetData()))
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
default:
return fmt.Errorf("Invalid data type - %s", s.cached.GetType())
}
Expand All @@ -133,31 +143,78 @@ 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()
}
nd, err := s.Ipfs.DAG.Get(ctx, lnk.Cid)
if err != nil {
log.Warning("error fetching directory child node: ", err)
}

t := fuse.DT_Unknown
switch nd := nd.(type) {
case *mdag.RawNode:
t = fuse.DT_File
case *mdag.ProtoNode:
var data ftpb.Data
if err := proto.Unmarshal(nd.Data(), &data); err != nil {
log.Warning("failed to unmarshal protonode data field:", err)
} else {
switch data.GetType() {
case ftpb.Data_Directory, ftpb.Data_HAMTShard:
t = fuse.DT_Dir
case ftpb.Data_File, ftpb.Data_Raw:
t = fuse.DT_File
case ftpb.Data_Symlink:
t = fuse.DT_Link
case ftpb.Data_Metadata:
log.Error("metadata object in fuse should contain its wrapped type")
default:
log.Error("unrecognized protonode data type: ", data.GetType())
}
}
}
entries[i] = fuse.Dirent{Name: n, Type: fuse.DT_File}
entries = append(entries, fuse.Dirent{Name: n, Type: t})
return nil
})
if err != nil {
return nil, err
}

if len(entries) > 0 {
Expand All @@ -166,15 +223,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
Expand Down Expand Up @@ -220,6 +282,7 @@ type roNode interface {
fs.Node
fs.NodeStringLookuper
fs.NodeReadlinker
fs.NodeGetxattrer
}

var _ roNode = (*Node)(nil)
Expand Down
7 changes: 6 additions & 1 deletion merkledag/merkledag.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,13 @@ 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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing the case where err is nil (this is what's causing the segfaults in CI).

return nil, err
case nil:
// noop
}

return node.Decode(blk)
Expand Down