add.go 3.63 KB
Newer Older
Brian Tiger Chow's avatar
Brian Tiger Chow committed
1
package coreunix
2 3 4

import (
	"io"
5
	"io/ioutil"
6
	"os"
7
	gopath "path"
Jeromy's avatar
Jeromy committed
8 9 10
	"time"

	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11

12 13 14 15 16 17 18 19
	"github.com/ipfs/go-ipfs/commands/files"
	core "github.com/ipfs/go-ipfs/core"
	importer "github.com/ipfs/go-ipfs/importer"
	chunk "github.com/ipfs/go-ipfs/importer/chunk"
	merkledag "github.com/ipfs/go-ipfs/merkledag"
	"github.com/ipfs/go-ipfs/pin"
	"github.com/ipfs/go-ipfs/thirdparty/eventlog"
	unixfs "github.com/ipfs/go-ipfs/unixfs"
20 21
)

22 23
var log = eventlog.Logger("coreunix")

Brian Tiger Chow's avatar
Brian Tiger Chow committed
24 25
// Add builds a merkledag from the a reader, pinning all objects to the local
// datastore. Returns a key representing the root node.
26
func Add(n *core.IpfsNode, r io.Reader) (string, error) {
27
	// TODO more attractive function signature importer.BuildDagFromReader
28

29 30
	dagNode, err := importer.BuildDagFromReader(
		n.DAG,
31
		chunk.NewSizeSplitter(r, chunk.DefaultBlockSize),
32
		importer.BasicPinnerCB(n.Pinning.GetManual()),
33 34 35 36
	)
	if err != nil {
		return "", err
	}
37 38 39 40 41 42
	k, err := dagNode.Key()
	if err != nil {
		return "", err
	}

	return k.String(), nil
43
}
44 45 46 47 48 49 50 51

// AddR recursively adds files in |path|.
func AddR(n *core.IpfsNode, root string) (key string, err error) {
	f, err := os.Open(root)
	if err != nil {
		return "", err
	}
	defer f.Close()
52

53
	ff, err := files.NewSerialFile(root, root, f)
54 55 56
	if err != nil {
		return "", err
	}
57

58 59 60 61
	dagnode, err := addFile(n, ff)
	if err != nil {
		return "", err
	}
62

63 64 65 66
	k, err := dagnode.Key()
	if err != nil {
		return "", err
	}
67 68 69 70 71 72 73

	n.Pinning.GetManual().RemovePinWithMode(k, pin.Indirect)
	err = n.Pinning.Flush()
	if err != nil {
		return "", err
	}

74 75 76
	return k.String(), nil
}

77 78
// AddWrapped adds data from a reader, and wraps it with a directory object
// to preserve the filename.
79 80
// Returns the path of the added file ("<dir hash>/filename"), the DAG node of
// the directory, and and error if any.
81
func AddWrapped(n *core.IpfsNode, r io.Reader, filename string) (string, *merkledag.Node, error) {
82 83
	file := files.NewReaderFile(filename, filename, ioutil.NopCloser(r), nil)
	dir := files.NewSliceFile("", "", []files.File{file})
84 85 86 87 88 89 90 91 92 93 94
	dagnode, err := addDir(n, dir)
	if err != nil {
		return "", nil, err
	}
	k, err := dagnode.Key()
	if err != nil {
		return "", nil, err
	}
	return gopath.Join(k.String(), filename), dagnode, nil
}

95
func add(n *core.IpfsNode, reader io.Reader) (*merkledag.Node, error) {
96
	mp := n.Pinning.GetManual()
97

98 99
	node, err := importer.BuildDagFromReader(
		n.DAG,
100
		chunk.DefaultSplitter(reader),
101
		importer.PinIndirectCB(mp),
102
	)
103 104 105
	if err != nil {
		return nil, err
	}
106 107

	return node, nil
108 109 110 111 112 113 114
}

func addNode(n *core.IpfsNode, node *merkledag.Node) error {
	err := n.DAG.AddRecursive(node) // add the file to the graph + local storage
	if err != nil {
		return err
	}
Jeromy's avatar
Jeromy committed
115 116 117
	ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
	defer cancel()
	err = n.Pinning.Pin(ctx, node, true) // ensure we keep it
118 119 120 121 122 123 124 125 126 127 128
	if err != nil {
		return err
	}
	return nil
}

func addFile(n *core.IpfsNode, file files.File) (*merkledag.Node, error) {
	if file.IsDirectory() {
		return addDir(n, file)
	}

129
	dagnode, err := add(n, file)
130 131 132 133
	if err != nil {
		return nil, err
	}

134
	return dagnode, nil
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
}

func addDir(n *core.IpfsNode, dir files.File) (*merkledag.Node, error) {

	tree := &merkledag.Node{Data: unixfs.FolderPBData()}

Loop:
	for {
		file, err := dir.NextFile()
		switch {
		case err != nil && err != io.EOF:
			return nil, err
		case err == io.EOF:
			break Loop
		}

		node, err := addFile(n, file)
		if err != nil {
			return nil, err
		}

156
		_, name := gopath.Split(file.FileName())
157 158 159 160 161 162 163 164 165 166 167 168 169

		err = tree.AddNodeLink(name, node)
		if err != nil {
			return nil, err
		}
	}

	err := addNode(n, tree)
	if err != nil {
		return nil, err
	}
	return tree, nil
}