add.go 3.5 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

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

11 12 13 14 15 16
	"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"
17
	logging "github.com/ipfs/go-ipfs/vendor/QmTBXYb6y2ZcJmoXVKk3pf9rzSEjbCg7tQaJW7RSuH14nv/go-log"
18
	unixfs "github.com/ipfs/go-ipfs/unixfs"
19 20
)

Jeromy's avatar
Jeromy committed
21
var log = logging.Logger("coreunix")
22

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

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

	return k.String(), nil
42
}
43 44 45

// AddR recursively adds files in |path|.
func AddR(n *core.IpfsNode, root string) (key string, err error) {
46
	stat, err := os.Lstat(root)
47 48 49
	if err != nil {
		return "", err
	}
50

51
	f, err := files.NewSerialFile(root, root, stat)
52 53 54
	if err != nil {
		return "", err
	}
55
	defer f.Close()
56

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

62 63 64 65
	k, err := dagnode.Key()
	if err != nil {
		return "", err
	}
66 67

	n.Pinning.GetManual().RemovePinWithMode(k, pin.Indirect)
68
	if err := n.Pinning.Flush(); err != nil {
69 70 71
		return "", err
	}

72 73 74
	return k.String(), nil
}

75 76
// AddWrapped adds data from a reader, and wraps it with a directory object
// to preserve the filename.
77 78
// Returns the path of the added file ("<dir hash>/filename"), the DAG node of
// the directory, and and error if any.
79
func AddWrapped(n *core.IpfsNode, r io.Reader, filename string) (string, *merkledag.Node, error) {
80 81
	file := files.NewReaderFile(filename, filename, ioutil.NopCloser(r), nil)
	dir := files.NewSliceFile("", "", []files.File{file})
82 83 84 85 86 87 88 89 90 91 92
	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
}

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

96
	return importer.BuildDagFromReader(
97
		n.DAG,
98
		chunk.DefaultSplitter(reader),
99
		importer.PinIndirectCB(mp),
100
	)
101 102 103
}

func addNode(n *core.IpfsNode, node *merkledag.Node) error {
104
	if err := n.DAG.AddRecursive(node); err != nil { // add the file to the graph + local storage
105 106
		return err
	}
107
	ctx, cancel := context.WithCancel(n.Context())
Jeromy's avatar
Jeromy committed
108
	defer cancel()
109 110
	err := n.Pinning.Pin(ctx, node, true) // ensure we keep it
	return err
111 112 113 114 115 116
}

func addFile(n *core.IpfsNode, file files.File) (*merkledag.Node, error) {
	if file.IsDirectory() {
		return addDir(n, file)
	}
117
	return add(n, file)
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
}

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
		}

139
		_, name := gopath.Split(file.FileName())
140

141
		if err := tree.AddNodeLink(name, node); err != nil {
142 143 144 145
			return nil, err
		}
	}

146
	if err := addNode(n, tree); err != nil {
147 148 149 150
		return nil, err
	}
	return tree, nil
}