package coreunix import ( "fmt" "io" "io/ioutil" "os" gopath "path" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore" syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync" context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" bserv "github.com/ipfs/go-ipfs/blockservice" "github.com/ipfs/go-ipfs/exchange/offline" importer "github.com/ipfs/go-ipfs/importer" "github.com/ipfs/go-ipfs/importer/chunk" dagutils "github.com/ipfs/go-ipfs/merkledag/utils" "github.com/ipfs/go-ipfs/pin" "github.com/ipfs/go-ipfs/commands/files" core "github.com/ipfs/go-ipfs/core" merkledag "github.com/ipfs/go-ipfs/merkledag" unixfs "github.com/ipfs/go-ipfs/unixfs" logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" ) var log = logging.Logger("coreunix") // how many bytes of progress to wait before sending a progress update message const progressReaderIncrement = 1024 * 256 type Link struct { Name, Hash string Size uint64 } type Object struct { Hash string Links []Link } type hiddenFileError struct { fileName string } func (e *hiddenFileError) Error() string { return fmt.Sprintf("%s is a hidden file", e.fileName) } type ignoreFileError struct { fileName string } func (e *ignoreFileError) Error() string { return fmt.Sprintf("%s is an ignored file", e.fileName) } type AddedObject struct { Name string Hash string `json:",omitempty"` Bytes int64 `json:",omitempty"` } func NewAdder(ctx context.Context, n *core.IpfsNode, out chan interface{}) *Adder { e := dagutils.NewDagEditor(NewMemoryDagService(), newDirNode()) return &Adder{ ctx: ctx, node: n, editor: e, out: out, Progress: false, Hidden: true, Pin: true, Trickle: false, Wrap: false, Chunker: "", } } // Internal structure for holding the switches passed to the `add` call type Adder struct { ctx context.Context node *core.IpfsNode editor *dagutils.Editor out chan interface{} Progress bool Hidden bool Pin bool Trickle bool Wrap bool Chunker string root *merkledag.Node } // Perform the actual add & pin locally, outputting results to reader func (params Adder) add(reader io.Reader) (*merkledag.Node, error) { chnk, err := chunk.FromString(reader, params.Chunker) if err != nil { return nil, err } if params.Trickle { return importer.BuildTrickleDagFromReader( params.node.DAG, chnk, ) } return importer.BuildDagFromReader( params.node.DAG, chnk, ) } func (params *Adder) RootNode() (*merkledag.Node, error) { // for memoizing if params.root != nil { return params.root, nil } root := params.editor.GetNode() // if not wrapping, AND one root file, use that hash as root. if !params.Wrap && len(root.Links) == 1 { var err error root, err = root.Links[0].GetNode(params.ctx, params.editor.GetDagService()) params.root = root // no need to output, as we've already done so. return root, err } // otherwise need to output, as we have not. err := outputDagnode(params.out, "", root) params.root = root return root, err } func (params *Adder) PinRoot() error { root, err := params.RootNode() if err != nil { return err } if !params.Pin { return nil } rnk, err := root.Key() if err != nil { return err } params.node.Pinning.PinWithMode(rnk, pin.Recursive) return params.node.Pinning.Flush() } func (params *Adder) WriteOutputTo(DAG merkledag.DAGService) error { return params.editor.WriteOutputTo(DAG) } // Add builds a merkledag from the a reader, pinning all objects to the local // datastore. Returns a key representing the root node. func Add(n *core.IpfsNode, r io.Reader) (string, error) { unlock := n.Blockstore.PinLock() defer unlock() fileAdder := NewAdder(n.Context(), n, nil) node, err := fileAdder.add(r) if err != nil { return "", err } k, err := node.Key() if err != nil { return "", err } return k.String(), nil } // AddR recursively adds files in |path|. func AddR(n *core.IpfsNode, root string) (key string, err error) { unlock := n.Blockstore.PinLock() defer unlock() stat, err := os.Lstat(root) if err != nil { return "", err } f, err := files.NewSerialFile(root, root, stat) if err != nil { return "", err } defer f.Close() fileAdder := NewAdder(n.Context(), n, nil) dagnode, err := fileAdder.AddFile(f) if err != nil { return "", err } k, err := dagnode.Key() if err != nil { return "", err } return k.String(), nil } // AddWrapped adds data from a reader, and wraps it with a directory object // to preserve the filename. // Returns the path of the added file ("