func AddMetadataTo(n *core.IpfsNode, skey string, m *ft.Metadata) (string, error) { c, err := cid.Decode(skey) if err != nil { return "", err } nd, err := n.DAG.Get(n.Context(), c) if err != nil { return "", err } mdnode := new(dag.ProtoNode) mdata, err := ft.BytesForMetadata(m) if err != nil { return "", err } mdnode.SetData(mdata) if err := mdnode.AddNodeLinkClean("file", nd); err != nil { return "", err } nk, err := n.DAG.Add(mdnode) if err != nil { return "", err } return nk.String(), nil }
func addLink(ctx context.Context, ds dag.DAGService, root *dag.ProtoNode, childname string, childnd node.Node) (*dag.ProtoNode, error) { if childname == "" { return nil, errors.New("cannot create link with no name!") } // ensure that the node we are adding is in the dagservice _, err := ds.Add(childnd) if err != nil { return nil, err } _ = ds.Remove(root) // ensure no link with that name already exists _ = root.RemoveNodeLink(childname) // ignore error, only option is ErrNotFound if err := root.AddNodeLinkClean(childname, childnd); err != nil { return nil, err } if _, err := ds.Add(root); err != nil { return nil, err } return root, nil }
func ImportTar(r io.Reader, ds dag.DAGService) (*dag.ProtoNode, error) { tr := tar.NewReader(r) root := new(dag.ProtoNode) root.SetData([]byte("ipfs/tar")) e := dagutil.NewDagEditor(root, ds) for { h, err := tr.Next() if err != nil { if err == io.EOF { break } return nil, err } header := new(dag.ProtoNode) headerBytes, err := marshalHeader(h) if err != nil { return nil, err } header.SetData(headerBytes) if h.Size > 0 { spl := chunk.NewRabin(tr, uint64(chunk.DefaultBlockSize)) nd, err := importer.BuildDagFromReader(ds, spl) if err != nil { return nil, err } err = header.AddNodeLinkClean("data", nd) if err != nil { return nil, err } } _, err = ds.Add(header) if err != nil { return nil, err } path := escapePath(h.Name) err = e.InsertNodeAtPath(context.Background(), path, header, func() *dag.ProtoNode { return new(dag.ProtoNode) }) if err != nil { return nil, err } } return e.Finalize(ds) }
func (e *Editor) rmLink(ctx context.Context, root *dag.ProtoNode, path []string) (*dag.ProtoNode, error) { if len(path) == 1 { // base case, remove node in question err := root.RemoveNodeLink(path[0]) if err != nil { return nil, err } _, err = e.tmp.Add(root) if err != nil { return nil, err } return root, nil } // search for node in both tmp dagstore and source dagstore nd, err := root.GetLinkedProtoNode(ctx, e.tmp, path[0]) if err == dag.ErrNotFound { nd, err = root.GetLinkedProtoNode(ctx, e.src, path[0]) } if err != nil { return nil, err } nnode, err := e.rmLink(ctx, nd, path[1:]) if err != nil { return nil, err } _ = e.tmp.Remove(root) _ = root.RemoveNodeLink(path[0]) err = root.AddNodeLinkClean(path[0], nnode) if err != nil { return nil, err } _, err = e.tmp.Add(root) if err != nil { return nil, err } return root, nil }
func (e *Editor) insertNodeAtPath(ctx context.Context, root *dag.ProtoNode, path []string, toinsert node.Node, create func() *dag.ProtoNode) (*dag.ProtoNode, error) { if len(path) == 1 { return addLink(ctx, e.tmp, root, path[0], toinsert) } nd, err := root.GetLinkedProtoNode(ctx, e.tmp, path[0]) if err != nil { // if 'create' is true, we create directories on the way down as needed if err == dag.ErrLinkNotFound && create != nil { nd = create() err = nil // no longer an error case } else if err == dag.ErrNotFound { // try finding it in our source dagstore nd, err = root.GetLinkedProtoNode(ctx, e.src, path[0]) } // if we receive an ErrNotFound, then our second 'GetLinkedNode' call // also fails, we want to error out if err != nil { return nil, err } } ndprime, err := e.insertNodeAtPath(ctx, nd, path[1:], toinsert, create) if err != nil { return nil, err } _ = e.tmp.Remove(root) _ = root.RemoveNodeLink(path[0]) err = root.AddNodeLinkClean(path[0], ndprime) if err != nil { return nil, err } _, err = e.tmp.Add(root) if err != nil { return nil, err } return root, nil }
// dagTruncate truncates the given node to 'size' and returns the modified Node func dagTruncate(ctx context.Context, nd *mdag.ProtoNode, size uint64, ds mdag.DAGService) (*mdag.ProtoNode, error) { if len(nd.Links()) == 0 { // TODO: this can likely be done without marshaling and remarshaling pbn, err := ft.FromBytes(nd.Data()) if err != nil { return nil, err } nd.SetData(ft.WrapData(pbn.Data[:size])) return nd, nil } var cur uint64 end := 0 var modified *mdag.ProtoNode ndata := new(ft.FSNode) for i, lnk := range nd.Links() { child, err := lnk.GetNode(ctx, ds) if err != nil { return nil, err } childpb, ok := child.(*mdag.ProtoNode) if !ok { return nil, err } childsize, err := ft.DataSize(childpb.Data()) if err != nil { return nil, err } // found the child we want to cut if size < cur+childsize { nchild, err := dagTruncate(ctx, childpb, size-cur, ds) if err != nil { return nil, err } ndata.AddBlockSize(size - cur) modified = nchild end = i break } cur += childsize ndata.AddBlockSize(childsize) } _, err := ds.Add(modified) if err != nil { return nil, err } nd.SetLinks(nd.Links()[:end]) err = nd.AddNodeLinkClean("", modified) if err != nil { return nil, err } d, err := ndata.GetBytes() if err != nil { return nil, err } nd.SetData(d) // invalidate cache and recompute serialized data _, err = nd.EncodeProtobuf(true) if err != nil { return nil, err } return nd, nil }