Skip to content

Commit

Permalink
filestore util: Add basic implementation of 'filestore get' command.
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Kevin Atkinson <k@kevina.org>
  • Loading branch information
kevina committed Sep 21, 2017
1 parent 2b12a33 commit 55d4ae4
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 2 deletions.
48 changes: 48 additions & 0 deletions core/commands/filestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"path/filepath"

cmds "github.com/ipfs/go-ipfs/commands"
"github.com/ipfs/go-ipfs/core"
Expand All @@ -20,6 +21,7 @@ var FileStoreCmd = &cmds.Command{
"ls": lsFileStore,
"verify": verifyFileStore,
"dups": dupsFileStore,
"get": getFileStoreCmd,
},
}

Expand Down Expand Up @@ -201,6 +203,52 @@ var dupsFileStore = &cmds.Command{
Type: RefWrapper{},
}

var getFileStoreCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Download IPFS objects into filestore.",
},
Arguments: []cmds.Argument{
cmds.StringArg("cid", true, false, "The cid of the IPFS object to be outputted."),
cmds.StringArg("file-path", true, false, "Path of file to store object in."),
},
Run: func(req cmds.Request, res cmds.Response) {
node, fs, err := getFilestore(req)
ctx := req.Context()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
args := req.Arguments()
c, err := cid.Decode(args[0])
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
filePath, err := filepath.Abs(args[1])
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
println("here we go")
g := &filestore.Getter{
Ctx: ctx,
FullPath: filePath,
Nodes: node.DAG,
Filestore: fs,
}
err = g.Init()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
_, err = g.Get(c, 0)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
},
}

func getFilestore(req cmds.Request) (*core.IpfsNode, *filestore.Filestore, error) {
n, err := req.InvocContext().GetNode()
if err != nil {
Expand Down
12 changes: 10 additions & 2 deletions filestore/fsrefstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,19 @@ func (f *FileManager) Put(b *posinfo.FilestoreNode) error {
return f.putTo(b, f.ds)
}

func (f *FileManager) CheckPath(fullpath string) error {
if !filepath.HasPrefix(fullpath, f.root) {
return fmt.Errorf("cannot add filestore references outside ipfs root (%s)", f.root)
}
return nil
}

func (f *FileManager) putTo(b *posinfo.FilestoreNode, to putter) error {
var dobj pb.DataObj

if !filepath.HasPrefix(b.PosInfo.FullPath, f.root) {
return fmt.Errorf("cannot add filestore references outside ipfs root (%s)", f.root)
err := f.CheckPath(b.PosInfo.FullPath)
if err != nil {
return err
}

p, err := filepath.Rel(f.root, b.PosInfo.FullPath)
Expand Down
85 changes: 85 additions & 0 deletions filestore/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package filestore

import (
"context"
"fmt"
"os"

dag "github.com/ipfs/go-ipfs/merkledag"
pi "github.com/ipfs/go-ipfs/thirdparty/posinfo"
unixfs "github.com/ipfs/go-ipfs/unixfs"
cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
)

type Getter struct {
Ctx context.Context
FullPath string
Nodes node.NodeGetter
Filestore *Filestore
fh *os.File
}

// Init inits the filestore getter
func (g *Getter) Init() error {
err := g.Filestore.FileManager().CheckPath(g.FullPath)
if err != nil {
return err
}

g.fh, err = os.Create(g.FullPath)
if err != nil {
return err
}

return nil
}

// Get gets a node directly into the filestore
func (g *Getter) Get(c *cid.Cid, offset uint64) (uint64, error) {
node, err := g.Nodes.Get(g.Ctx, c)
if err != nil {
return 0, err
}
switch n := node.(type) {
case *dag.ProtoNode:
pbn, err := unixfs.FromBytes(n.Data())
if err != nil {
return 0, err
}
if len(pbn.Data) != 0 {
return 0, fmt.Errorf("%s: unsupported node type", c.String())
}
// still need to store the node, incase the node getter
// bypasses the normal blockstore
err = g.Filestore.Put(n)
if err != nil {
return 0, err
}
for _, lnk := range n.Links() {
offset, err = g.Get(lnk.Cid, offset)
if err != nil {
return 0, err
}
}
return offset, nil
case *dag.RawNode:
data := n.RawData()
_, err := g.fh.WriteAt(data, int64(offset))
if err != nil {
return 0, err
}
fsn := &pi.FilestoreNode{node, &pi.PosInfo{
Offset: offset,
FullPath: g.FullPath,
}}
err = g.Filestore.Put(fsn)
if err != nil {
return 0, err
}
return offset + uint64(len(data)), nil
default:
return 0, fmt.Errorf("%s: unsupported node type", c.String())
}

}
23 changes: 23 additions & 0 deletions test/sharness/t0271-filestore-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,25 @@ test_filestore_dups() {
'
}

test_filestore_get() {
test_expect_success "create and add some files" '
random 1000 11 > smallfile0 &&
random 1000000 12 > largefile0 &&
SMALLHASH=$(ipfs add -q --raw-leaves smallfile0) &&
LARGEHASH=$(ipfs add -q --raw-leaves largefile0)
'

test_expect_success "get small file into filestore" '
ipfs filestore get $SMALLHASH smallfile &&
test_cmp smallfile0 smallfile
'

test_expect_success "get large file into filestore" '
ipfs filestore get $LARGEHASH largefile &&
test_cmp largefile0 largefile
'
}

#
# No daemon
#
Expand All @@ -177,6 +196,8 @@ test_filestore_verify

test_filestore_dups

test_filestore_get

#
# With daemon
#
Expand All @@ -193,6 +214,8 @@ test_filestore_verify

test_filestore_dups

test_filestore_get

test_kill_ipfs_daemon

test_done

0 comments on commit 55d4ae4

Please sign in to comment.