提交 a22cae1b 作者: Jeromy

fix coreapi unixfs resolving

License: MIT
Signed-off-by: 's avatarJeromy <jeromyj@gmail.com>
上级 0597a049
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
core "github.com/ipfs/go-ipfs/core" core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
ipfspath "github.com/ipfs/go-ipfs/path" ipfspath "github.com/ipfs/go-ipfs/path"
uio "github.com/ipfs/go-ipfs/unixfs/io"
cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid" cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid"
) )
...@@ -42,8 +43,13 @@ func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreifac ...@@ -42,8 +43,13 @@ func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreifac
return p, nil return p, nil
} }
r := &ipfspath.Resolver{
DAG: api.node.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
p2 := ipfspath.FromString(p.String()) p2 := ipfspath.FromString(p.String())
node, err := core.Resolve(ctx, api.node.Namesys, api.node.Resolver, p2) node, err := core.Resolve(ctx, api.node.Namesys, r, p2)
if err == core.ErrNoNamesys { if err == core.ErrNoNamesys {
return nil, coreiface.ErrOffline return nil, coreiface.ErrOffline
} else if err != nil { } else if err != nil {
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
uio "github.com/ipfs/go-ipfs/unixfs/io" uio "github.com/ipfs/go-ipfs/unixfs/io"
cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid" cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid"
node "gx/ipfs/Qmb3Hm9QDFmfYuET4pu7Kyg8JV78jFa1nvZx5vnCZsK4ck/go-ipld-format"
) )
type UnixfsAPI CoreAPI type UnixfsAPI CoreAPI
...@@ -46,9 +47,23 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path) ([]*coreiface.Li ...@@ -46,9 +47,23 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path) ([]*coreiface.Li
return nil, err return nil, err
} }
l := dagnode.Links() var ndlinks []*node.Link
links := make([]*coreiface.Link, len(l)) dir, err := uio.NewDirectoryFromNode(api.node.DAG, dagnode)
for i, l := range l { switch err {
case nil:
l, err := dir.Links(ctx)
if err != nil {
return nil, err
}
ndlinks = l
case uio.ErrNotADir:
ndlinks = dagnode.Links()
default:
return nil, err
}
links := make([]*coreiface.Link, len(ndlinks))
for i, l := range ndlinks {
links[i] = &coreiface.Link{l.Name, l.Size, l.Cid} links[i] = &coreiface.Link{l.Name, l.Size, l.Cid}
} }
return links, nil return links, nil
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
config "github.com/ipfs/go-ipfs/repo/config" config "github.com/ipfs/go-ipfs/repo/config"
testutil "github.com/ipfs/go-ipfs/thirdparty/testutil" testutil "github.com/ipfs/go-ipfs/thirdparty/testutil"
unixfs "github.com/ipfs/go-ipfs/unixfs" unixfs "github.com/ipfs/go-ipfs/unixfs"
cbor "gx/ipfs/QmNrbCt8j9DT5W9Pmjy2SdudT9k8GpaDr4sRuFix3BXhgR/go-ipld-cbor"
) )
// `echo -n 'hello, world!' | ipfs add` // `echo -n 'hello, world!' | ipfs add`
...@@ -276,7 +277,12 @@ func TestLsNonUnixfs(t *testing.T) { ...@@ -276,7 +277,12 @@ func TestLsNonUnixfs(t *testing.T) {
t.Error(err) t.Error(err)
} }
c, err := node.DAG.Add(new(mdag.ProtoNode)) nd, err := cbor.WrapObject(map[string]interface{}{"foo": "bar"})
if err != nil {
t.Fatal(err)
}
c, err := node.DAG.Add(nd)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
......
...@@ -37,7 +37,7 @@ func (e ErrNoLink) Error() string { ...@@ -37,7 +37,7 @@ func (e ErrNoLink) Error() string {
type Resolver struct { type Resolver struct {
DAG dag.DAGService DAG dag.DAGService
ResolveOnce func(ctx context.Context, ds dag.DAGService, nd node.Node, name string) (*node.Link, error) ResolveOnce func(ctx context.Context, ds dag.DAGService, nd node.Node, names []string) (*node.Link, []string, error)
} }
func NewBasicResolver(ds dag.DAGService) *Resolver { func NewBasicResolver(ds dag.DAGService) *Resolver {
...@@ -121,9 +121,10 @@ func (s *Resolver) ResolvePath(ctx context.Context, fpath Path) (node.Node, erro ...@@ -121,9 +121,10 @@ func (s *Resolver) ResolvePath(ctx context.Context, fpath Path) (node.Node, erro
return nodes[len(nodes)-1], err return nodes[len(nodes)-1], err
} }
func ResolveSingle(ctx context.Context, ds dag.DAGService, nd node.Node, name string) (*node.Link, error) { // ResolveSingle simply resolves one hop of a path through a graph with no
lnk, _, err := nd.ResolveLink([]string{name}) // extra context (does not opaquely resolve through sharded nodes)
return lnk, err func ResolveSingle(ctx context.Context, ds dag.DAGService, nd node.Node, names []string) (*node.Link, []string, error) {
return nd.ResolveLink(names)
} }
// ResolvePathComponents fetches the nodes for each segment of the given path. // ResolvePathComponents fetches the nodes for each segment of the given path.
...@@ -163,7 +164,7 @@ func (s *Resolver) ResolveLinks(ctx context.Context, ndd node.Node, names []stri ...@@ -163,7 +164,7 @@ func (s *Resolver) ResolveLinks(ctx context.Context, ndd node.Node, names []stri
ctx, cancel = context.WithTimeout(ctx, time.Minute) ctx, cancel = context.WithTimeout(ctx, time.Minute)
defer cancel() defer cancel()
lnk, err := s.ResolveOnce(ctx, s.DAG, nd, names[0]) lnk, rest, err := s.ResolveOnce(ctx, s.DAG, nd, names)
if err == dag.ErrLinkNotFound { if err == dag.ErrLinkNotFound {
return result, ErrNoLink{Name: names[0], Node: nd.Cid()} return result, ErrNoLink{Name: names[0], Node: nd.Cid()}
} else if err != nil { } else if err != nil {
...@@ -177,7 +178,7 @@ func (s *Resolver) ResolveLinks(ctx context.Context, ndd node.Node, names []stri ...@@ -177,7 +178,7 @@ func (s *Resolver) ResolveLinks(ctx context.Context, ndd node.Node, names []stri
nd = nextnode nd = nextnode
result = append(result, nextnode) result = append(result, nextnode)
names = names[1:] names = rest
} }
return result, nil return result, nil
} }
...@@ -191,6 +191,7 @@ type shardValue struct { ...@@ -191,6 +191,7 @@ type shardValue struct {
val *node.Link val *node.Link
} }
// Link returns a link to this node
func (sv *shardValue) Link() (*node.Link, error) { func (sv *shardValue) Link() (*node.Link, error) {
return sv.val, nil return sv.val, nil
} }
...@@ -234,7 +235,8 @@ func (ds *HamtShard) Remove(ctx context.Context, name string) error { ...@@ -234,7 +235,8 @@ func (ds *HamtShard) Remove(ctx context.Context, name string) error {
return ds.modifyValue(ctx, hv, name, nil) return ds.modifyValue(ctx, hv, name, nil)
} }
func (ds *HamtShard) Find(ctx context.Context, name string) (node.Node, error) { // Find searches for a child node by 'name' within this hamt
func (ds *HamtShard) Find(ctx context.Context, name string) (*node.Link, error) {
hv := &hashBits{b: hash([]byte(name))} hv := &hashBits{b: hash([]byte(name))}
var out *node.Link var out *node.Link
...@@ -246,7 +248,7 @@ func (ds *HamtShard) Find(ctx context.Context, name string) (node.Node, error) { ...@@ -246,7 +248,7 @@ func (ds *HamtShard) Find(ctx context.Context, name string) (node.Node, error) {
return nil, err return nil, err
} }
return ds.dserv.Get(ctx, out.Cid) return out, nil
} }
// getChild returns the i'th child of this shard. If it is cached in the // getChild returns the i'th child of this shard. If it is cached in the
...@@ -320,6 +322,7 @@ func (ds *HamtShard) setChild(i int, c child) { ...@@ -320,6 +322,7 @@ func (ds *HamtShard) setChild(i int, c child) {
ds.children[i] = c ds.children[i] = c
} }
// Link returns a merklelink to this shard node
func (ds *HamtShard) Link() (*node.Link, error) { func (ds *HamtShard) Link() (*node.Link, error) {
nd, err := ds.Node() nd, err := ds.Node()
if err != nil { if err != nil {
......
...@@ -48,6 +48,7 @@ func NewDirectory(dserv mdag.DAGService) *Directory { ...@@ -48,6 +48,7 @@ func NewDirectory(dserv mdag.DAGService) *Directory {
return db return db
} }
// ErrNotADir implies that the given node was not a unixfs directory
var ErrNotADir = fmt.Errorf("merkledag node was not a directory or shard") var ErrNotADir = fmt.Errorf("merkledag node was not a directory or shard")
func NewDirectoryFromNode(dserv mdag.DAGService, nd node.Node) (*Directory, error) { func NewDirectoryFromNode(dserv mdag.DAGService, nd node.Node) (*Directory, error) {
...@@ -167,7 +168,12 @@ func (d *Directory) Find(ctx context.Context, name string) (node.Node, error) { ...@@ -167,7 +168,12 @@ func (d *Directory) Find(ctx context.Context, name string) (node.Node, error) {
return d.dserv.Get(ctx, lnk.Cid) return d.dserv.Get(ctx, lnk.Cid)
} }
return d.shard.Find(ctx, name) lnk, err := d.shard.Find(ctx, name)
if err != nil {
return nil, err
}
return lnk.GetNode(ctx, d.dserv)
} }
func (d *Directory) RemoveChild(ctx context.Context, name string) error { func (d *Directory) RemoveChild(ctx context.Context, name string) error {
......
...@@ -10,37 +10,48 @@ import ( ...@@ -10,37 +10,48 @@ import (
node "gx/ipfs/Qmb3Hm9QDFmfYuET4pu7Kyg8JV78jFa1nvZx5vnCZsK4ck/go-ipld-format" node "gx/ipfs/Qmb3Hm9QDFmfYuET4pu7Kyg8JV78jFa1nvZx5vnCZsK4ck/go-ipld-format"
) )
func ResolveUnixfsOnce(ctx context.Context, ds dag.DAGService, nd node.Node, name string) (*node.Link, error) { // ResolveUnixfsOnce resolves a single hop of a path through a graph in a
// unixfs context. This includes handling traversing sharded directories.
func ResolveUnixfsOnce(ctx context.Context, ds dag.DAGService, nd node.Node, names []string) (*node.Link, []string, error) {
switch nd := nd.(type) { switch nd := nd.(type) {
case *dag.ProtoNode: case *dag.ProtoNode:
upb, err := ft.FromBytes(nd.Data()) upb, err := ft.FromBytes(nd.Data())
if err != nil { if err != nil {
// Not a unixfs node, use standard object traversal code // Not a unixfs node, use standard object traversal code
return nd.GetNodeLink(name) lnk, err := nd.GetNodeLink(names[0])
if err != nil {
return nil, nil, err
}
return lnk, names[1:], nil
} }
switch upb.GetType() { switch upb.GetType() {
case ft.THAMTShard: case ft.THAMTShard:
s, err := hamt.NewHamtFromDag(ds, nd) s, err := hamt.NewHamtFromDag(ds, nd)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// TODO: optimized routine on HAMT for returning a dag.Link to avoid extra disk hits out, err := s.Find(ctx, names[0])
out, err := s.Find(ctx, name)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
return node.MakeLink(out) return out, names[1:], nil
default: default:
return nd.GetNodeLink(name) lnk, err := nd.GetNodeLink(names[0])
if err != nil {
return nil, nil, err
}
return lnk, names[1:], nil
} }
default: default:
lnk, _, err := nd.ResolveLink([]string{name}) lnk, rest, err := nd.ResolveLink(names)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
return lnk, nil return lnk, rest, nil
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论