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

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

various fixes for /ipfs fuse code
......@@ -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
}
......
......@@ -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()
}
......
......@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"strings"
"sync"
core "github.com/ipfs/go-ipfs/core"
ipns "github.com/ipfs/go-ipfs/fuse/ipns"
......@@ -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)
......
......@@ -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,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.
......@@ -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())
}
......@@ -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 {
......@@ -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
......@@ -220,6 +282,7 @@ type roNode interface {
fs.Node
fs.NodeStringLookuper
fs.NodeReadlinker
fs.NodeGetxattrer
}
var _ roNode = (*Node)(nil)
......
......@@ -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:
return nil, err
case nil:
// noop
}
return node.Decode(blk)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论