/
car.go
81 lines (65 loc) · 1.6 KB
/
car.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package dag
import (
"context"
"errors"
"io"
cid "github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
ipld "github.com/ipfs/go-ipld-format"
merkledag "github.com/ipfs/go-merkledag"
car "github.com/ipld/go-car"
"github.com/ipld/go-car/util"
)
type carWriter struct {
ds ipld.NodeGetter
w io.Writer
}
func (cw *carWriter) getLinks(ctx context.Context, id cid.Cid) ([]*ipld.Link, error) {
node, err := cw.ds.Get(ctx, id)
if err != nil {
return nil, err
}
if err := util.LdWrite(cw.w, id.Bytes(), node.RawData()); err != nil {
return nil, err
}
return node.Links(), nil
}
// WriteCar writes the dag into the given writer starting at head and stopping at refs.
func WriteCar(ctx context.Context, ds ipld.NodeGetter, head cid.Cid, refs *cid.Set, w io.Writer) error {
h := &car.CarHeader{
Roots: []cid.Cid{head},
Version: 1,
}
if err := car.WriteHeader(h, w); err != nil {
return err
}
cw := carWriter{
ds: ds,
w: w,
}
return merkledag.Walk(ctx, cw.getLinks, head, refs.Visit)
}
// ReadCar reads the car into the given dag and returns the root cid.
func ReadCar(bs blockstore.Blockstore, r io.Reader) (cid.Cid, error) {
cr, err := car.NewCarReader(r)
if err != nil {
return cid.Cid{}, err
}
if len(cr.Header.Roots) != 1 {
return cid.Cid{}, errors.New("unexpected header roots")
}
// load blocks slowly or badger will return an error
for {
block, err := cr.Next()
if err == io.EOF {
break
}
if err != nil {
return cid.Cid{}, err
}
if err := bs.Put(block); err != nil {
return cid.Cid{}, err
}
}
return cr.Header.Roots[0], nil
}