提交 038430d9 作者: Jeromy Johnson 提交者: GitHub

Merge pull request #4194 from ipfs/feat/fuse-fixes

various fixes for /ipfs fuse code
...@@ -88,7 +88,7 @@ baz ...@@ -88,7 +88,7 @@ baz
} }
// error if we aren't running node in online mode // error if we aren't running node in online mode
if !node.OnlineMode() { if node.LocalMode() {
res.SetError(errNotOnline, cmds.ErrClient) res.SetError(errNotOnline, cmds.ErrClient)
return return
} }
......
...@@ -90,7 +90,7 @@ type closer struct { ...@@ -90,7 +90,7 @@ type closer struct {
} }
func (c *closer) Close() error { 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() return c.M.Unmount()
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"sync"
core "github.com/ipfs/go-ipfs/core" core "github.com/ipfs/go-ipfs/core"
ipns "github.com/ipfs/go-ipfs/fuse/ipns" ipns "github.com/ipfs/go-ipfs/fuse/ipns"
...@@ -63,25 +64,26 @@ func doMount(node *core.IpfsNode, fsdir, nsdir string) error { ...@@ -63,25 +64,26 @@ func doMount(node *core.IpfsNode, fsdir, nsdir string) error {
} }
// this sync stuff is so that both can be mounted simultaneously. // this sync stuff is so that both can be mounted simultaneously.
var fsmount mount.Mount var fsmount, nsmount mount.Mount
var nsmount mount.Mount var err1, err2 error
var err1 error
var err2 error
done := make(chan struct{}) var wg sync.WaitGroup
wg.Add(1)
go func() { go func() {
defer wg.Done()
fsmount, err1 = rofs.Mount(node, fsdir) fsmount, err1 = rofs.Mount(node, fsdir)
done <- struct{}{}
}() }()
if node.OnlineMode() {
wg.Add(1)
go func() { go func() {
defer wg.Done()
nsmount, err2 = ipns.Mount(node, nsdir, fsdir) nsmount, err2 = ipns.Mount(node, nsdir, fsdir)
done <- struct{}{}
}() }()
}
<-done wg.Wait()
<-done
if err1 != nil { if err1 != nil {
log.Errorf("error mounting: %s", err1) log.Errorf("error mounting: %s", err1)
......
...@@ -18,6 +18,7 @@ import ( ...@@ -18,6 +18,7 @@ import (
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
lgbl "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables" lgbl "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables"
format "gx/ipfs/QmYNyRZJBUYPNrLszFmrBrPJbsBh2vMsefz5gnDpB5M1P6/go-ipld-format"
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto" proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
fuse "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse" fuse "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse"
fs "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse/fs" fs "gx/ipfs/QmaFNtBAXX4nVMQWbUqNysXyhevUj1k4B1y5uS45LC7Vw9/fuse/fs"
...@@ -60,19 +61,26 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) { ...@@ -60,19 +61,26 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
return nil, fuse.ENOENT 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 { if err != nil {
// todo: make this error more versatile. // todo: make this error more versatile.
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
pbnd, ok := nd.(*mdag.ProtoNode) switch nd := nd.(type) {
if !ok { case *mdag.ProtoNode, *mdag.RawNode:
return &Node{Ipfs: s.Ipfs, Nd: nd}, nil
default:
log.Error("fuse node was not a protobuf node") log.Error("fuse node was not a protobuf node")
return nil, fuse.ENOTSUP return nil, fuse.ENOTSUP
} }
return &Node{Ipfs: s.Ipfs, Nd: pbnd}, nil
} }
// ReadDirAll reads a particular directory. Disallowed for root. // ReadDirAll reads a particular directory. Disallowed for root.
...@@ -84,46 +92,48 @@ func (*Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { ...@@ -84,46 +92,48 @@ func (*Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
// Node is the core object representing a filesystem tree node. // Node is the core object representing a filesystem tree node.
type Node struct { type Node struct {
Ipfs *core.IpfsNode Ipfs *core.IpfsNode
Nd *mdag.ProtoNode Nd format.Node
cached *ftpb.Data cached *ftpb.Data
} }
func (s *Node) loadData() error { func (s *Node) loadData() error {
if pbnd, ok := s.Nd.(*mdag.ProtoNode); ok {
s.cached = new(ftpb.Data) s.cached = new(ftpb.Data)
return proto.Unmarshal(s.Nd.Data(), s.cached) return proto.Unmarshal(pbnd.Data(), s.cached)
}
return nil
} }
// Attr returns the attributes of a given node. // Attr returns the attributes of a given node.
func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error { func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
log.Debug("Node attr") 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 s.cached == nil {
if err := s.loadData(); err != nil { if err := s.loadData(); err != nil {
return fmt.Errorf("readonly: loadData() failed: %s", err) return fmt.Errorf("readonly: loadData() failed: %s", err)
} }
} }
switch s.cached.GetType() { switch s.cached.GetType() {
case ftpb.Data_Directory: case ftpb.Data_Directory, ftpb.Data_HAMTShard:
a.Mode = os.ModeDir | 0555 a.Mode = os.ModeDir | 0555
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
case ftpb.Data_File: case ftpb.Data_File:
size := s.cached.GetFilesize() size := s.cached.GetFilesize()
a.Mode = 0444 a.Mode = 0444
a.Size = uint64(size) a.Size = uint64(size)
a.Blocks = uint64(len(s.Nd.Links())) a.Blocks = uint64(len(s.Nd.Links()))
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
case ftpb.Data_Raw: case ftpb.Data_Raw:
a.Mode = 0444 a.Mode = 0444
a.Size = uint64(len(s.cached.GetData())) a.Size = uint64(len(s.cached.GetData()))
a.Blocks = uint64(len(s.Nd.Links())) a.Blocks = uint64(len(s.Nd.Links()))
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
case ftpb.Data_Symlink: case ftpb.Data_Symlink:
a.Mode = 0777 | os.ModeSymlink a.Mode = 0777 | os.ModeSymlink
a.Size = uint64(len(s.cached.GetData())) a.Size = uint64(len(s.cached.GetData()))
a.Uid = uint32(os.Getuid())
a.Gid = uint32(os.Getgid())
default: default:
return fmt.Errorf("Invalid data type - %s", s.cached.GetType()) return fmt.Errorf("Invalid data type - %s", s.cached.GetType())
} }
...@@ -133,31 +143,78 @@ func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error { ...@@ -133,31 +143,78 @@ func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
// Lookup performs a lookup under this node. // Lookup performs a lookup under this node.
func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) { func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) {
log.Debugf("Lookup '%s'", name) log.Debugf("Lookup '%s'", name)
nodes, err := s.Ipfs.Resolver.ResolveLinks(ctx, s.Nd, []string{name}) link, _, err := uio.ResolveUnixfsOnce(ctx, s.Ipfs.DAG, s.Nd, []string{name})
if err != nil { switch err {
case os.ErrNotExist, mdag.ErrLinkNotFound:
// todo: make this error more versatile. // todo: make this error more versatile.
return nil, fuse.ENOENT 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) nd, err := s.Ipfs.DAG.Get(ctx, link.Cid)
if !ok { switch err {
log.Error("fuse lookup got non-protobuf node") case mdag.ErrNotFound:
return nil, fuse.ENOTSUP 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 // ReadDirAll reads the link structure as directory entries
func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
log.Debug("Node ReadDir") log.Debug("Node ReadDir")
entries := make([]fuse.Dirent, len(s.Nd.Links())) dir, err := uio.NewDirectoryFromNode(s.Ipfs.DAG, s.Nd)
for i, link := range s.Nd.Links() { if err != nil {
n := link.Name return nil, err
}
var entries []fuse.Dirent
err = dir.ForEachLink(ctx, func(lnk *format.Link) error {
n := lnk.Name
if len(n) == 0 { 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 { if len(entries) > 0 {
...@@ -166,15 +223,20 @@ func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { ...@@ -166,15 +223,20 @@ func (s *Node) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
return nil, fuse.ENOENT 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) { 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 "", fuse.Errno(syscall.EINVAL)
} }
return string(s.cached.GetData()), nil return string(s.cached.GetData()), nil
} }
func (s *Node) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { func (s *Node) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
c := s.Nd.Cid() c := s.Nd.Cid()
// setup our logging event // setup our logging event
...@@ -220,6 +282,7 @@ type roNode interface { ...@@ -220,6 +282,7 @@ type roNode interface {
fs.Node fs.Node
fs.NodeStringLookuper fs.NodeStringLookuper
fs.NodeReadlinker fs.NodeReadlinker
fs.NodeGetxattrer
} }
var _ roNode = (*Node)(nil) var _ roNode = (*Node)(nil)
......
...@@ -153,8 +153,13 @@ type sesGetter struct { ...@@ -153,8 +153,13 @@ type sesGetter struct {
func (sg *sesGetter) Get(ctx context.Context, c *cid.Cid) (node.Node, error) { func (sg *sesGetter) Get(ctx context.Context, c *cid.Cid) (node.Node, error) {
blk, err := sg.bs.GetBlock(ctx, c) blk, err := sg.bs.GetBlock(ctx, c)
if err != nil { switch err {
case bserv.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err return nil, err
case nil:
// noop
} }
return node.Decode(blk) return node.Decode(blk)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论